Index: firmware/App/Modes/ModeHeatDisinfect.c =================================================================== diff -u -r1440a4a2be8d12edebd405a20807882e5d32d619 -r72bca5d2e489fa253f3bdfdb254261a32c7a0c19 --- firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 1440a4a2be8d12edebd405a20807882e5d32d619) +++ firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 72bca5d2e489fa253f3bdfdb254261a32c7a0c19) @@ -92,8 +92,8 @@ #define HEAT_DISINFECT_TARGET_RO_FLOW_TRANSFER_LPM 0.8F ///< Heat disinfect target RO flow rate in L/min when transferring between reservoirs. #define HEAT_DISINFECT_MAX_RO_PRESSURE_PSI 30 ///< Heat disinfect maximum RO pressure in psi. #define HEAT_DISINFECT_START_TEMP_TIMOUT_MS ( 4 * MIN_PER_HOUR * SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect reaching to minimum temperature timeout in milliseconds. -#define RSRVRS_TARGET_VOL_OUT_TIMEOUT_MS ( 0.5F * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 maximum volume out of range timeout during heat disinfect. TODO change this to 5 seconds -#define RSRVRS_MAX_TARGET_VOL_CHANGE_ML 250.0F // TODO temporary change. Change back to 100 ///< Reservoirs 1 & 2 maximum allowed volume change when full during heat disinfect. +#define RSRVRS_TARGET_VOL_OUT_TIMEOUT_MS ( 5 * MS_PER_SECOND ) ///< Reservoirs 1 & 2 maximum volume out of range timeout during heat disinfect. +#define RSRVRS_MAX_TARGET_VOL_CHANGE_ML 100.0F ///< Reservoirs 1 & 2 maximum allowed volume change when full during heat disinfect. #define POST_HEAT_DISINFECT_WAIT_TIME_MS ( 3 * SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect final wait time before flushing the system in milliseconds. #define HEAT_DISINFECT_MAX_TEMP_GRADIENT_C 15.0F ///< Heat disinfect maximum allowed temperature gradient in between hottest and coldest sensors. #define HEAT_DISINFECT_TEMP_GRAD_OUT_RANGE_TIME_MS ( 0.16 * SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect temperature gradient out of range timeout in milliseconds. @@ -193,6 +193,10 @@ static DISINFECT_NV_OPS_T disinfectNVOps; ///< Disinfect non-volatile memory operations. static HEAT_DISINFECT_TIME_STATUS_T timeStatus[ NUM_OF_HEAT_DISINFECT_TIMES ]; ///< Heat disinfect time status. +#ifndef _RELEASE_ +static NELSON_SUPPORT_T nelsonSupport; ///< Nelson support. +#endif + // ********** private function prototypes ********** static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectStartState( void ); @@ -224,6 +228,11 @@ static void monitorModeHeatDisinfect( void ); static void writeDisinfectDataToNV( DG_USAGE_INFO_ITEMS_T info ); +#ifndef _RELEASE_ +static void setNelsonSupportConditions( void ); +static DG_HEAT_DISINFECT_STATE_T handleNelsonHeatDisinfectFillR1WithWaterState( void ); +#endif + /*********************************************************************//** * @brief * The initHeatDisinfectMode function initializes the heat disinfect mode @@ -267,6 +276,10 @@ areRsrvrsLeaking = FALSE; dataPublishCounter = 0; +#ifndef _RELEASE_ + nelsonSupport = NELSON_NONE; +#endif + // Initialize the disinfect times timeStatus[ RO_AT_77_C ].startTempC = HEAT_DISINFECT_START_TEMP_AT_77_C; timeStatus[ RO_AT_77_C ].startTimeMS = 0; @@ -291,6 +304,10 @@ timeStatus[ RSRVR_AT_82_C ].stopTempC = HEAT_DISINFECT_STOP_TEMP_AT_81_C; timeStatus[ RSRVR_AT_82_C ].targetTimeMS = HEAT_DISINFECT_AT_82_C_TIME_MS; timeStatus[ RSRVR_AT_82_C ].tempSensor = TEMPSENSORS_INLET_DIALYSATE; + +#ifndef _RELEASE_ + setNelsonSupportConditions(); +#endif } /*********************************************************************//** @@ -414,6 +431,12 @@ heatDisinfectState = handleHeatDisinfectCompleteState(); break; +#ifndef _RELEASE_ + case DG_NELSON_HEAT_DISINFECT_STATE_FILL_R1_WITH_WATER: + heatDisinfectState = handleNelsonHeatDisinfectFillR1WithWaterState(); + break; +#endif + default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_HEAT_DISINFECT_INVALID_EXEC_STATE, heatDisinfectState ) heatDisinfectState = DG_HEAT_DISINFECT_STATE_START; @@ -452,6 +475,9 @@ // Check if the current operation mode is heat disinfect if ( DG_MODE_HEAT == getCurrentOperationMode() ) { +#ifndef _RELEASE_ + nelsonSupport = NELSON_NONE; +#endif // Reset all the actuators deenergizeActuators( NO_PARK_CONC_PUMPS ); @@ -464,6 +490,22 @@ return status; } +#ifndef _RELEASE_ +/*********************************************************************//** + * @brief + * The setNelsonSupportMode function sets the requested Nelson support + * mode (i.e. inoculate, ...) + * @details Inputs: none + * @details Outputs: nelsonSupport + * @param support the type Nelson support (i.e. inoculate, heat disinfect) + * @return none + *************************************************************************/ +void setNelsonSupportMode( NELSON_SUPPORT_T support ) +{ + nelsonSupport = support; +} +#endif + // ********** private functions ********** /*********************************************************************//** @@ -520,20 +562,17 @@ tareLoadCell( LOAD_CELL_RESERVOIR_1_PRIMARY ); tareLoadCell( LOAD_CELL_RESERVOIR_1_BACKUP ); - // Assume reservoir 2 is full and drain it - rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; - // Done with draining R1, close it setValveState( VRD1, VALVE_STATE_CLOSED ); // Set the actuators to drain R2. // NOTE: Drain pump is already on and VDr is already on drain state setValveState( VRD2, VALVE_STATE_OPEN ); - state = DG_HEAT_DISINFECT_STATE_DRAIN_R2; - setValveState( VPO, VALVE_STATE_FILL_C_TO_NC); - // Start the timer - stateTimer = getMSTimerCount(); + // Assume reservoir 2 is full and drain it + rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; + state = DG_HEAT_DISINFECT_STATE_DRAIN_R2; + stateTimer = getMSTimerCount(); } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { @@ -570,14 +609,23 @@ signalDrainPumpHardStop(); - // Done with draining R2, close it - turnOnUVReactor( INLET_UV_REACTOR ); - setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); - setValveState( VRD2, VALVE_STATE_CLOSED ); - setValveState( VPI, VALVE_STATE_OPEN ); - stateTrialCounter = 0; - stateTimer = getMSTimerCount(); - state = DG_HEAT_DISINFECT_STATE_FLUSH_DRAIN; +#ifndef _RELEASE_ + if ( NELSON_DRAIN_SAMPLES == nelsonSupport ) + { + state = DG_HEAT_DISINFECT_STATE_COMPLETE; + } + else +#endif + { + // Done with draining R2, close it + turnOnUVReactor( INLET_UV_REACTOR ); + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + setValveState( VPI, VALVE_STATE_OPEN ); + stateTrialCounter = 0; + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_FLUSH_DRAIN; + } } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) { @@ -1226,6 +1274,27 @@ stateTimer = getMSTimerCount(); state = DG_HEAT_DISINFECT_STATE_COOL_DOWN_HEATERS; } +#ifndef _RELEASE_ + if ( NELSON_INOCULATE == nelsonSupport ) + { + // Set the valves to transfer hot water from R1 to R2 and fill up R2. + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_OPEN ); + setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); + setDrainPumpTargetOutletFlowLPM( HEAT_DISINFECT_TARGET_RO_FLOW_TRANSFER_LPM ); + + // Although there is fluid in both reservoirs, but they are set to empty + // to begin the transition of hot water from R1 to R2. + rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; + rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; + stateTimer = getMSTimerCount(); + rsrvr1RefVolML = 0.0F; + rsrvr2RefVolML = 0.0F; + state = DG_NELSON_HEAT_DISINFECT_STATE_FILL_R1_WITH_WATER; + } +#endif break; case HEAT_DISINFECT_HEAT_UP_IN_PROGRESS: @@ -1512,7 +1581,18 @@ heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_COMPLETE; - requestNewOperationMode( DG_MODE_HCOL ); +#ifndef _RELEASE_ + if ( nelsonSupport != NELSON_NONE ) + { + // Clear the variable to be out of Nelson support + nelsonSupport = NELSON_NONE; + requestNewOperationMode( DG_MODE_STAN ); + } + else +#endif + { + requestNewOperationMode( DG_MODE_HCOL ); + } return state; } @@ -1533,7 +1613,19 @@ { SET_ALARM_WITH_1_U32_DATA( alarmDetectedPendingTrigger, prevHeatDisinfectState ) } - requestNewOperationMode( DG_MODE_FAUL ); + +#ifndef _RELEASE_ + if ( nelsonSupport != NELSON_NONE ) + { + // Clear the variable to be out of Nelson support + nelsonSupport = NELSON_NONE; + requestNewOperationMode( DG_MODE_STAN ); + } + else +#endif + { + requestNewOperationMode( DG_MODE_FAUL ); + } } /*********************************************************************//** @@ -1853,6 +1945,7 @@ uiData.r82CountdownTimeS = ( 0 == timeStatus[ RSRVR_AT_82_C ].startTimeMS ? 0 : ( timeStatus[ RSRVR_AT_82_C ].targetTimeMS - calcTimeSince( timeStatus[ RSRVR_AT_82_C ].startTimeMS ) ) / 1000 ); data.R1FillLevel = rsrvr1RefVolML; data.R2FillLevel = rsrvr2RefVolML; + data.nelsonSupportMode = (U32)nelsonSupport; broadcastData( MSG_ID_DG_HEAT_DISINFECT_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&data, sizeof( MODE_HEAT_DISINFECT_DATA_T ) ); broadcastData( MSG_ID_DG_HEAT_DISINFECT_TIME_DATA, COMM_BUFFER_OUT_CAN_DG_2_UI, (U08*)&uiData, sizeof( MODE_HEAT_DISINFECT_UI_DATA_T ) ); @@ -1913,4 +2006,127 @@ } } +// ********** Nelson Support Functions ********** + +#ifndef _RELEASE_ +/*********************************************************************//** + * @brief + * The setNelsonSupportConditions function sets the disinfect variables for + * Nelson support. + * @details Inputs: nelsonSupport + * @details Outputs: timeStatus, heatDisinfectState + * @return: none + *************************************************************************/ +static void setNelsonSupportConditions( void ) +{ + F32 temperature = 0.0F; + F32 stopTemperature = 0.0F; + U32 disinfectTime = 0; + + switch ( nelsonSupport ) + { + case NELSON_INOCULATE: + // The target temperature is set to low so the heater will turn on but it will not heat because + // we are very close to the target. Set the stop temperature to a temperature lower by a couple degrees + // make sure the timer will continuously count against the disinfection time to inoculate. + // NOTE: this is not part of the commercial code so no #defines + temperature = 20.0F; + stopTemperature = temperature - 3.0F; + disinfectTime = 2 * MIN_PER_HOUR * SEC_PER_MIN * MS_PER_SECOND; + heatDisinfectState = DG_HEAT_DISINFECT_STATE_START; + + timeStatus[ RO_AT_77_C ].startTempC = temperature; + timeStatus[ RO_AT_77_C ].startTimeMS = 0; + timeStatus[ RO_AT_77_C ].stopTempC = stopTemperature; + timeStatus[ RO_AT_77_C ].targetTimeMS = HEAT_DISINFECT_AT_77_C_TIME_MS; + + timeStatus[ RO_AT_82_C ].startTempC = temperature; + timeStatus[ RO_AT_82_C ].startTimeMS = 0; + timeStatus[ RO_AT_82_C ].stopTempC = stopTemperature; + timeStatus[ RO_AT_82_C ].targetTimeMS = HEAT_DISINFECT_AT_82_C_TIME_MS; + + timeStatus[ RSRVR_AT_77_C ].startTempC = temperature; + timeStatus[ RSRVR_AT_77_C ].startTimeMS = 0; + timeStatus[ RSRVR_AT_77_C ].stopTempC = stopTemperature; + timeStatus[ RSRVR_AT_77_C ].targetTimeMS = disinfectTime; + + timeStatus[ RSRVR_AT_82_C ].startTempC = temperature; + timeStatus[ RSRVR_AT_82_C ].startTimeMS = 0; + timeStatus[ RSRVR_AT_82_C ].stopTempC = stopTemperature; + timeStatus[ RSRVR_AT_82_C ].targetTimeMS = disinfectTime; + break; + + case NELSON_HEAT_DISINFECT: + // Set the valves to drain R2 and no fill + setValveState( VPI, VALVE_STATE_CLOSED ); + setValveState( VBF, VALVE_STATE_OPEN ); + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VDR, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState( VRC, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_OPEN ); + signalROPumpHardStop(); + setDrainPumpTargetOutletFlowLPM( HEAT_DISINFECT_TARGET_RO_FLOW_LPM ); + setHeaterTargetTemperature( DG_PRIMARY_HEATER, HEAT_DISINFECT_PRIM_HEATER_TARGET_TEMP_C ); + startHeater( DG_PRIMARY_HEATER ); + heatDisinfectState = DG_HEAT_DISINFECT_STATE_DISINFECT_R1_TO_R2; + break; + + case NELSON_DRAIN_SAMPLES: + heatDisinfectState = DG_HEAT_DISINFECT_STATE_START; + break; + + case NELSON_NONE: + default: + break; + } +} + +/*********************************************************************//** + * @brief + * The handleNelsonHeatDisinfectFillR1WithWaterState function handles the Nelson + * fill reservoir 1 with water. + * @details Inputs: rsrvr1Status, rsrvr2Status + * @details Outputs: rsrvr1Status, rsrvr2Status, prevHeatDisinfectState + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleNelsonHeatDisinfectFillR1WithWaterState( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_NELSON_HEAT_DISINFECT_STATE_FILL_R1_WITH_WATER; + + // First reservoir 2 must be partially full + if ( DG_RESERVOIR_BELOW_TARGET == rsrvr2Status ) + { + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); + } + else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) + { + rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + + if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) + { + deenergizeActuators( PARK_CONC_PUMPS ); + state = DG_HEAT_DISINFECT_STATE_COMPLETE; + } + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) + { + prevHeatDisinfectState = state; + state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; + } + } + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) + { + prevHeatDisinfectState = state; + state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; + } + + return state; +} + +#endif + /**@}*/