Index: firmware/App/Modes/ModeFill.c =================================================================== diff -u -r54f45c387430e440ab4607451fc84dea61f273f1 -r3461c140ba07e74863dee1d4c51d0119076fecf8 --- firmware/App/Modes/ModeFill.c (.../ModeFill.c) (revision 54f45c387430e440ab4607451fc84dea61f273f1) +++ firmware/App/Modes/ModeFill.c (.../ModeFill.c) (revision 3461c140ba07e74863dee1d4c51d0119076fecf8) @@ -15,13 +15,16 @@ * ***************************************************************************/ +#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" @@ -33,53 +36,67 @@ // ********** private definitions ********** +#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 * The initFillMode function initializes the fill mode module. - * @details - * Inputs : none - * Outputs : Fill mode module initialized + * @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 * The transitionToFillMode function prepares for transition to fill mode. - * @details - * Inputs : none - * Outputs : Re-initialized 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 * The execFillMode function executes the fill mode state machine. - * @details - * Inputs : fillState - * Outputs : Check water quality, fill mode state machine executed + * @details Inputs: fillState + * @details Outputs: Check water quality, fill mode state machine executed * @return current state. *************************************************************************/ U32 execFillMode( void ) @@ -90,13 +107,23 @@ 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; @@ -116,19 +143,64 @@ /*********************************************************************//** * @brief - * The handleDialysateProductionState function executes the Dialysate production + * 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 - * Outputs : none + * @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; @@ -139,34 +211,38 @@ /*********************************************************************//** * @brief - * The handleDeliverDialysateState function executes the deliver Dialysate + * The handleDeliverDialysateState function executes the deliver dialysate * state of the fill mode state machine. - * @details - * Inputs : none - * Outputs : Deliver Dialysate + * @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 ); } @@ -175,15 +251,24 @@ /*********************************************************************//** * @brief - * The getCurrentFillState function returns the current state of the fill mode. - * @details - * Inputs : fillState - * Outputs : none - * @return 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 ); + checkPersistentAlarm( PERSISTENT_ALARM_RO_PUMP_FLOW_RATE_OUT_OF_RANGE, isROPumpFlowRateOutOfRange, measuredROFlowRate ); } /**@}*/