Index: firmware/App/Modes/ModeFill.c =================================================================== diff -u -rf308cc4c35eab630ebbbde405cfe47d049afeafb -rfeb93744f73bc0a3d58841bb02bd05c38357f35d --- firmware/App/Modes/ModeFill.c (.../ModeFill.c) (revision f308cc4c35eab630ebbbde405cfe47d049afeafb) +++ firmware/App/Modes/ModeFill.c (.../ModeFill.c) (revision feb93744f73bc0a3d58841bb02bd05c38357f35d) @@ -8,23 +8,26 @@ * @file ModeFill.c * * @author (last) Quang Nguyen -* @date (last) 13-Aug-2020 +* @date (last) 25-Aug-2020 * * @author (original) Leonardo Baloa * @date (original) 19-Nov-2019 * ***************************************************************************/ +#include "ConcentratePumps.h" #include "ConductivitySensors.h" #include "FPGA.h" #include "LoadCell.h" #include "ModeFill.h" #include "OperationModes.h" +#include "PersistentAlarm.h" #include "Pressures.h" #include "Reservoirs.h" +#include "ROPump.h" +#include "TemperatureSensors.h" #include "Timers.h" #include "Valves.h" -#include "TemperatureSensors.h" /** * @addtogroup DGFillMode @@ -33,73 +36,94 @@ // ********** private definitions ********** -#define QUARTER_SECOND 250 -#define HALF_SECOND 500 +#define FILL_MIN_RO_FLOW_RATE 0.6 ///< Minimum RO flow rate in fill mode. +#define FILL_MAX_RO_FLOW_RATE 1.0 ///< Maximum RO flow rate in fill mode. +#define FILL_TARGET_RO_FLOW_RATE 0.8 ///< Target RO flow rate in fill mode. +#define FILL_TARGET_RO_PRESSURE_PSI 120 ///< Target RO pressure in fill mode. +#define RO_FLOW_RATE_OUT_OF_RANGE_PERSISTENCE_PERIOD ( 5 * MS_PER_SECOND ) ///< Persistence period for RO flow rate out of range. +#define DIALYSATE_ACID_CONCENTRATE_RATIO ( 2.35618 / FRACTION_TO_PERCENT_FACTOR ) ///< Ratio between RO water and acid concentrate. +#define DIALYSATE_BICARB_CONCENTRATE_RATIO ( 4.06812 / FRACTION_TO_PERCENT_FACTOR ) ///< Ratio between RO water and bicarbonate concentrate. + +#define DIALYSATE_FILL_TIME_OUT ( 5 * SEC_PER_MIN * MS_PER_SECOND ) ///< Time out period when reservoir is not filled with correct dialysate. + // ********** private data ********** -static DG_FILL_MODE_STATE_T fillState; ///< Currently active fill state. +static DG_FILL_MODE_STATE_T fillState; ///< Currently active fill state. +static U32 dialysateFillStartTime; ///< Current time when starting to fill dialysate. // ********** private function prototypes ********** +static DG_FILL_MODE_STATE_T handleCheckInletWaterState( void ); static DG_FILL_MODE_STATE_T handleDialysateProductionState( void ); static DG_FILL_MODE_STATE_T handleDeliverDialysateState( void ); +static void handleDialysateMixing( void ); + /*********************************************************************//** - * @brief initFillMode - * The initFillMode function initializes the Fill Mode module. - * @details - * Inputs : none - * Outputs : Fill Mode module initialized. + * @brief + * The initFillMode function initializes the fill mode module. + * @details Inputs: none + * @details Outputs: Fill mode module initialized * @return none *************************************************************************/ void initFillMode( void ) { fillState = DG_FILL_MODE_STATE_START; + + initPersistentAlarm( PERSISTENT_ALARM_RO_PUMP_FLOW_RATE_OUT_OF_RANGE, ALARM_ID_RO_PUMP_FLOW_RATE_OUT_OF_RANGE, + FALSE, RO_FLOW_RATE_OUT_OF_RANGE_PERSISTENCE_PERIOD, RO_FLOW_RATE_OUT_OF_RANGE_PERSISTENCE_PERIOD ); } /*********************************************************************//** - * @brief transitionToFillMode - * The transitionToFillMode function prepares for transition to \n - * fill mode. - * @details - * Inputs : none - * Outputs : fillState + * @brief + * The transitionToFillMode function prepares for transition to fill mode. + * @details Inputs: none + * @details Outputs: Re-initialized fill mode * @return none *************************************************************************/ void transitionToFillMode( void ) { - // re-initialize fill mode each time we transition to fill mode - initFillMode(); + fillState = DG_FILL_MODE_STATE_START; + dialysateFillStartTime = getMSTimerCount(); // set initial actuator states setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); - // Conc. pumps on } /*********************************************************************//** - * @brief execFillMode - * The execFillMode function executes the Fill Mode state machine. - * @details - * Inputs : fillState - * Outputs : fillState + * @brief + * The execFillMode function executes the fill mode state machine. + * @details Inputs: fillState + * @details Outputs: Check water quality, fill mode state machine executed * @return current state. *************************************************************************/ U32 execFillMode( void ) { - // check inlet water conductivity, temperature, and pressure - checkInletWaterConductivity( fillState ); + // check inlet water conductivity, temperature, pressure, and RO rejection ratio + checkInletWaterConductivity(); checkInletWaterTemperature(); checkInletPressure(); + checkRORejectionRatio(); + // check if run out of time to fill the reservoir + if ( didTimeout( dialysateFillStartTime, DIALYSATE_FILL_TIME_OUT ) ) + { + activateAlarmNoData( ALARM_ID_DG_DIALYSATE_FILL_OUT_OF_TIME ); + } + // execute current Fill state switch ( fillState ) { case DG_FILL_MODE_STATE_START: - fillState = DG_FILL_MODE_STATE_DIALYSATE_PRODUCTION; + fillState = DG_FILL_MODE_STATE_CHECK_INLET_WATER; break; + case DG_FILL_MODE_STATE_CHECK_INLET_WATER: + fillState = handleCheckInletWaterState(); + break; + case DG_FILL_MODE_STATE_DIALYSATE_PRODUCTION: fillState = handleDialysateProductionState(); break; @@ -119,19 +143,64 @@ /*********************************************************************//** * @brief - * The handleDialysateProductionState function executes the Dialysate Production \n - * state of the Fill Mode state machine. - * @details - * Inputs : none - * Outputs : + * The handleCheckInletWaterState function checks for inlet water quality + * before jumping to dialysate production state. + * @details Inputs: Temperature and conductivity alarms + * @details Outputs: request concentrate pump on and set RO pump flow rate * @return the next state *************************************************************************/ +static DG_FILL_MODE_STATE_T handleCheckInletWaterState( void ) +{ + DG_FILL_MODE_STATE_T result = DG_FILL_MODE_STATE_CHECK_INLET_WATER; + + BOOL const isWaterTemperatureGood = !isAlarmActive( ALARM_ID_INLET_WATER_HIGH_TEMPERATURE ) && !isAlarmActive( ALARM_ID_INLET_WATER_LOW_TEMPERATURE ); + BOOL const isWaterConductivityGood = !isAlarmActive( ALARM_ID_INLET_WATER_HIGH_CONDUCTIVITY ) && !isAlarmActive( ALARM_ID_INLET_WATER_LOW_CONDUCTIVITY ) && + !isAlarmActive( ALARM_ID_RO_REJECTION_RATIO_OUT_OF_RANGE ); + + BOOL isInletWaterReady = isWaterTemperatureGood && isWaterConductivityGood; + +#ifdef DISABLE_DIALYSATE_CHECK + isInletWaterReady = TRUE; +#endif + + if ( isInletWaterReady ) + { + // Concentrate pumps on request and set RO pump to flow rate 800 mL/min + requestConcentratePumpsOn( CONCENTRATEPUMPS_CP1 ); + requestConcentratePumpsOn( CONCENTRATEPUMPS_CP2 ); + // TODO: Change to set flow rate once RO pump driver is updated + // setROPumpFlowRate( FILL_TARGET_RO_FLOW_RATE ); + setROPumpTargetPressure( FILL_TARGET_RO_PRESSURE_PSI, PUMP_CONTROL_MODE_CLOSED_LOOP ); + + result = DG_FILL_MODE_STATE_DIALYSATE_PRODUCTION; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleDialysateProductionState function executes the dialysate production + * state of the fill mode state machine. + * @details Inputs: none + * @details Outputs: none + * @return the next state + *************************************************************************/ static DG_FILL_MODE_STATE_T handleDialysateProductionState( void ) { DG_FILL_MODE_STATE_T result = DG_FILL_MODE_STATE_DIALYSATE_PRODUCTION; + handleDialysateMixing(); + checkConcentrateConductivity(); + + BOOL isDialysateProductionGood = ( !isAlarmActive( ALARM_ID_POST_ACID_CONDUCTIVITY_OUT_OF_RANGE ) && !isAlarmActive( ALARM_ID_POST_BICARB_CONDUCTIVITY_OUT_OF_RANGE ) ); + +#ifdef DISABLE_DIALYSATE_CHECK + isDialysateProductionGood = TRUE; +#endif + // TODO - transition when temperature and mix is in range - if ( 1 ) + if ( isDialysateProductionGood ) { setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); result = DG_FILL_MODE_STATE_DELIVER_DIALYSATE; @@ -142,34 +211,38 @@ /*********************************************************************//** * @brief - * The handleDeliverDialysateState function executes the Deliver Dialysate \n - * state of the Fill Mode state machine. - * @details - * Inputs : none - * Outputs : + * The handleDeliverDialysateState function executes the deliver dialysate + * state of the fill mode state machine. + * @details Inputs: none + * @details Outputs: Deliver dialysate * @return the next state *************************************************************************/ static DG_FILL_MODE_STATE_T handleDeliverDialysateState( void ) { DG_FILL_MODE_STATE_T result = DG_FILL_MODE_STATE_DELIVER_DIALYSATE; - LOAD_CELL_ID_T fillWeightLoadCell = LOAD_CELL_A1; + RESERVOIR_ID_T inactiveReservoir = getInactiveReservoir(); + handleDialysateMixing(); + checkConcentrateConductivity(); + + BOOL isDialysateConductivityBad = ( isAlarmActive( ALARM_ID_POST_ACID_CONDUCTIVITY_OUT_OF_RANGE ) || isAlarmActive( ALARM_ID_POST_BICARB_CONDUCTIVITY_OUT_OF_RANGE ) ); + +#ifdef DISABLE_DIALYSATE_CHECK + isDialysateConductivityBad = FALSE; +#endif + // TODO - transition back when temperature or mix out of range - if ( 0 ) + if ( isDialysateConductivityBad ) { setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); result = DG_FILL_MODE_STATE_DIALYSATE_PRODUCTION; } - // determine which load cell to use for fill volume - we want weight of inactive reservoir - if ( RESERVOIR_1 == getActiveReservoir() ) - { - fillWeightLoadCell = LOAD_CELL_B1; - } - // if we've reached our target fill to volume (by weight), we're done filling - go back to re-circ mode - if ( getReservoirFillVolumeTargetMl() <= getLoadCellFilteredWeight( fillWeightLoadCell ) ) + if ( hasTargetFillVolumeBeenReached( inactiveReservoir ) ) { + requestConcentratePumpsOff( CONCENTRATEPUMPS_CP1 ); + requestConcentratePumpsOff( CONCENTRATEPUMPS_CP2 ); requestNewOperationMode( DG_MODE_CIRC ); } @@ -178,16 +251,26 @@ /*********************************************************************//** * @brief - * The getCurrentFillState function returns the current state of the \n - * fill mode. - * @details - * Inputs : fillState - * Outputs : none - * @return the current state of fill mode. + * The handleDialysateMixing function handles the dialysate mixing by setting + * the concentrate pump speed relative to the RO pump flow rate. + * @details Inputs: none + * @details Outputs: Set concentrate pump speed relative to RO pump flow rate + * @return none *************************************************************************/ -DG_FILL_MODE_STATE_T getCurrentFillState( void ) +static void handleDialysateMixing( void ) { - return fillState; + // Set concentrate pumps speed based off RO pump flow rate + F32 const measuredROFlowRate = getMeasuredROFlowRate(); + F32 const acidCP1PumpFlowRate = DIALYSATE_ACID_CONCENTRATE_RATIO * measuredROFlowRate * ML_PER_LITER; + F32 const bicarbCP2PumpFlowRate = DIALYSATE_BICARB_CONCENTRATE_RATIO * measuredROFlowRate * ML_PER_LITER; + + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1, acidCP1PumpFlowRate ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2, bicarbCP2PumpFlowRate ); + + BOOL const isROPumpFlowRateOutOfRange = ( measuredROFlowRate <= FILL_MIN_RO_FLOW_RATE ) || ( measuredROFlowRate >= FILL_MAX_RO_FLOW_RATE ); + + // TODO add the right limit values + checkPersistentAlarm( PERSISTENT_ALARM_RO_PUMP_FLOW_RATE_OUT_OF_RANGE, isROPumpFlowRateOutOfRange, measuredROFlowRate, 0 ); } /**@}*/