Index: firmware/App/Modes/ModeDrain.c =================================================================== diff -u -rdcbd821e41803adc6e582d909207bc97f85ff939 -r8a553b10a224c745cb4bd6d963c867391905ba8c --- firmware/App/Modes/ModeDrain.c (.../ModeDrain.c) (revision dcbd821e41803adc6e582d909207bc97f85ff939) +++ firmware/App/Modes/ModeDrain.c (.../ModeDrain.c) (revision 8a553b10a224c745cb4bd6d963c867391905ba8c) @@ -1,65 +1,326 @@ /************************************************************************** - * - * Copyright (c) 2019-2019 Diality Inc. - All Rights Reserved. - * - * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN - * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. - * - * @file ModeDrain.c - * - * @date 20-Dec-2019 - * @author L. Baloa - * - * @brief Top-level state machine for the drain mode. - * - **************************************************************************/ +* +* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file ModeDrain.c +* +* @author (last) Sean Nash +* @date (last) 12-Nov-2021 +* +* @author (original) Leonardo Baloa +* @date (original) 20-Dec-2019 +* +***************************************************************************/ -#include -#include "Common.h" +#include "ConcentratePumps.h" +#include "ConductivitySensors.h" +#include "DrainPump.h" +#include "Heaters.h" +#include "ModeDrain.h" #include "OperationModes.h" +#include "Pressures.h" +#include "Reservoirs.h" +#include "ROPump.h" +#include "SystemComm.h" +#include "TaskGeneral.h" +#include "TemperatureSensors.h" +#include "Timers.h" +#include "Valves.h" +/** + * @addtogroup DGDrainMode + * @{ + */ + +// ********** private definitions ********** + +#define TARGET_DRAIN_PUMP_RPM 2300 ///< Target drain pump speed (in RPM). +#define DRAIN_WEIGHT_UNCHANGE_TIMEOUT ( 2 * MS_PER_SECOND ) ///< Time period of unchanged weight during draining before timeout. + +#define DRAIN_EMPTY_TARE_WAIT ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) /// Time period to wait after drain complete and before taring load cells. + +#define TARGET_RO_PRESSURE_PSI 130 ///< Target pressure for RO pump. +#define TARGET_RO_FLOW_RATE_L 0.3 ///< Target flow rate for RO pump. + +#define DELAY_RES_DRAIN_VALVE_MS 1000 ///< Delay reservoir drain valve open by 1 second. +#define DELAY_DRAIN_PUMP_MS 2000 ///< Delay drain pump on by 2 seconds. + +#define DIALYSATE_DRAIN_TIME_OUT ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Dialysate drain time out. + +/// Time period to wait for concentrate lines to rinse. +#define RINSE_CONCENTRATE_LINES_WAIT ( 25 * MS_PER_SECOND / TASK_GENERAL_INTERVAL ) +/// Reserver the concentrate speed to rinse out concentrate lines. +#define RINSE_SPEED ( ( CONCENTRATE_PUMP_MAX_SPEED - 3.0 ) * -1.0 ) + // ********** private data ********** +static DG_DRAIN_STATE_T drainState; ///< Currently active drain state. +static U32 drainEmptyTareTimerCtr; ///< Timer counter for delay between drain complete and load cell tare. +static BOOL rinseConcentrateLines; ///< Flag indicates to rinse concentrate lines. +static U32 rinseConcentrateLinesTimerCtr; ///< Timer counter for rinsing concentrate lines. +static U32 dialysateDrainStartTime; ///< Dialysate drain start time. + // ********** private function prototypes ********** +static DG_DRAIN_STATE_T handleDrainStateStart( void ); +static DG_DRAIN_STATE_T handleDrainStateDrain( void ); +static DG_DRAIN_STATE_T handleDrainStateTare( void ); +static DG_DRAIN_STATE_T handleRinseState( void ); -/************************************************************************* - * @brief initDrainMode - * The initOpParamsMode function initializes the Drain Mode module. - * @details - * Inputs : none - * Outputs : Operating Parameters Mode module initialized. - * @param none +/*********************************************************************//** + * @brief + * The initDrainMode function initializes the drain mode module. + * @details Inputs: none + * @details Outputs: drainState, drainEmptyTareTimerCtr, dialysateDrainStartTime * @return none *************************************************************************/ void initDrainMode( void ) { + drainState = DG_DRAIN_STATE_START; + drainEmptyTareTimerCtr = 0; + rinseConcentrateLines = FALSE; + rinseConcentrateLinesTimerCtr = 0; + dialysateDrainStartTime = 0; } -/************************************************************************* - * @brief transitionToDrainMode - * The transitionToDrainMode function prepares for transition to drain \n - * mode. - * @details - * Inputs : none - * Outputs : - * @param none - * @return none +/*********************************************************************//** + * @brief + * The transitionToDrainMode function prepares for transition to drain mode. + * @details Inputs: none + * @details Outputs: Drain mode initialized + * @return initial state *************************************************************************/ -void transitionToDrainMode( void ) +U32 transitionToDrainMode( void ) { + // re-initialize each time we transition to drain mode + initDrainMode(); + + DG_RESERVOIR_ID_T inactiveReservoir = getInactiveReservoir(); + + if ( DG_RESERVOIR_1 == inactiveReservoir ) + { + setValveStateDelayed( VRD1, VALVE_STATE_OPEN, DELAY_RES_DRAIN_VALVE_MS ); + } + else if ( DG_RESERVOIR_2 == inactiveReservoir ) + { + setValveStateDelayed( VRD2, VALVE_STATE_OPEN, DELAY_RES_DRAIN_VALVE_MS ); + } + // set initial actuator states + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setDrainPumpTargetRPMDelayed( TARGET_DRAIN_PUMP_RPM, DELAY_DRAIN_PUMP_MS ); + + // NOTE: The target flow rate should be set prior to setting the start primary heater + // because the initial guess in the heaters driver needs the target flow to calculate + // the new PWMs for the main and small primary heaters +#ifndef DISABLE_FLOW_CONTROL_TREATMENT + setROPumpTargetFlowRateLPM( TARGET_RO_FLOW_RATE_L, TARGET_RO_PRESSURE_PSI ); +#endif + setHeaterTargetTemperature( DG_PRIMARY_HEATER, getPrimaryHeaterTargetTemperature() ); + startHeater( DG_PRIMARY_HEATER ); + + return drainState; } -/************************************************************************* - * @brief execDrainMode - * The execDrainMode function executes the Drain Mode state machine. - * @details - * Inputs : none - * Outputs : - * @param none +/*********************************************************************//** + * @brief + * The execDrainMode function executes the drain mode state machine. + * @details Inputs: drainState + * @details Outputs: Check water quality, drain mode state machine executed + * @return current state. + *************************************************************************/ +U32 execDrainMode( void ) +{ + // check inlet water conductivity, temperature, pressure, and RO rejection ratio + checkInletWaterConductivity(); + checkInletWaterTemperature(); + checkInletPressure(); + checkRORejectionRatio(); + + // execute current drain state + switch ( drainState ) + { + case DG_DRAIN_STATE_START: + drainState = handleDrainStateStart(); + break; + + case DG_DRAIN_STATE_DRAIN: + drainState = handleDrainStateDrain(); + break; + + case DG_DRAIN_STATE_TARE: + drainState = handleDrainStateTare(); + break; + + case DG_DRAIN_STATE_RINSE: + drainState = handleRinseState(); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_DRAIN_MODE_INVALID_EXEC_STATE, drainState ) + drainState = DG_DRAIN_STATE_START; + break; + } + + return drainState; +} + +/*********************************************************************//** + * @brief + * The getCurrentDrainState function returns the current state of the drain mode. + * @details Inputs: drainState + * @details Outputs: none + * @return the current state of drain mode. + *************************************************************************/ +DG_DRAIN_STATE_T getCurrentDrainState( void ) +{ + return drainState; +} + +/*********************************************************************//** + * @brief + * The signalDrainModeRinseConcentrateLines function sets the flag for drain + * mode to rinse concentrate lines. + * @details Inputs: none + * @details Outputs: rinseConcentrateLines * @return none *************************************************************************/ -void execDrainMode( void ) +void signalDrainModeRinseConcentrateLines( BOOL rinse ) { + rinseConcentrateLines = rinse; +} +/*********************************************************************//** + * @brief + * The handleDrainStateStart function handles the drain start state of + * the drain mode state machine. + * @details Inputs: none + * @details Outputs: dialysateDrainStartTime + * @return the next state + *************************************************************************/ +static DG_DRAIN_STATE_T handleDrainStateStart( void ) +{ + DG_DRAIN_STATE_T state = DG_DRAIN_STATE_START; + + if ( TRUE == isDrainPumpOn() ) + { + dialysateDrainStartTime = getMSTimerCount(); + state = DG_DRAIN_STATE_DRAIN; + } + + return state; } +/*********************************************************************//** + * @brief + * The handleDrainStateDrain function handles the drain state of the drain + * mode state machine. + * @details Inputs: none + * @details Outputs: none + * @return the next state + *************************************************************************/ +static DG_DRAIN_STATE_T handleDrainStateDrain( void ) +{ + DG_DRAIN_STATE_T result = DG_DRAIN_STATE_DRAIN; + DG_RESERVOIR_ID_T inactiveReservoir = getInactiveReservoir(); + + // if we have reached our target drain to volume (by weight) or cannot drain anymore, we are done draining - go back to generation idle mode + if ( TRUE == hasTargetDrainVolumeBeenReached( inactiveReservoir, DRAIN_WEIGHT_UNCHANGE_TIMEOUT ) ) + { + signalDrainPumpHardStop(); + + if ( DG_RESERVOIR_1 == inactiveReservoir ) + { + setValveState( VRD1, VALVE_STATE_CLOSED ); + } + else if ( DG_RESERVOIR_2 == inactiveReservoir ) + { + setValveState( VRD2, VALVE_STATE_CLOSED ); + } + + if ( TRUE == isReservoirTarePending() ) + { // Tare reservoir load cells at empty if requested + result = DG_DRAIN_STATE_TARE; + } + else + { + requestNewOperationMode( DG_MODE_GENE ); + } + } + + // Drain timed out raise the alarm + if ( TRUE == didTimeout( dialysateDrainStartTime, DIALYSATE_DRAIN_TIME_OUT ) ) + { + activateAlarmNoData( ALARM_ID_DG_DIALYSATE_DRAIN_TIME_OUT ); + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleDrainStateTare function handles the tare state of the drain mode + * state machine. + * @details Inputs: drainEmptyTareTimerCtr + * @details Outputs: drainEmptyTareTimerCtr + * @return the next state + *************************************************************************/ +static DG_DRAIN_STATE_T handleDrainStateTare( void ) +{ + DG_DRAIN_STATE_T result = DG_DRAIN_STATE_TARE; + DG_RESERVOIR_ID_T inactiveReservoir = getInactiveReservoir(); + + if ( ++drainEmptyTareTimerCtr > DRAIN_EMPTY_TARE_WAIT ) + { + drainEmptyTareTimerCtr = 0; + tareLoadCellsAtEmpty( inactiveReservoir ); + + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + + if ( TRUE == rinseConcentrateLines ) + { + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, RINSE_SPEED ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, RINSE_SPEED ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); + } + rinseConcentrateLinesTimerCtr = 0; + result = DG_DRAIN_STATE_RINSE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleRinseState function handles the tare state of the drain mode + * state machine. + * @details Inputs: drainEmptyTareTimerCtr + * @details Outputs: drainEmptyTareTimerCtr + * @return the next state + *************************************************************************/ +static DG_DRAIN_STATE_T handleRinseState( void ) +{ + DG_DRAIN_STATE_T result = DG_DRAIN_STATE_RINSE; + + if ( TRUE == rinseConcentrateLines ) + { + if ( ++rinseConcentrateLinesTimerCtr > RINSE_CONCENTRATE_LINES_WAIT ) + { + rinseConcentrateLinesTimerCtr = 0; + requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB ); + requestNewOperationMode( DG_MODE_GENE ); + } + } + else + { + requestNewOperationMode( DG_MODE_GENE ); + } + + return result; +} + +/**@}*/