Index: firmware/App/Modes/ModeStandby.c =================================================================== diff -u -r72ba5f3c63325b00306b544b2513c03500919d06 -r7d4711edd7b40cd3e29f43e766f79a8a09586fe9 --- firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 72ba5f3c63325b00306b544b2513c03500919d06) +++ firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 7d4711edd7b40cd3e29f43e766f79a8a09586fe9) @@ -1,27 +1,31 @@ /************************************************************************** * -* Copyright (c) 2019-2022 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2024 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 ModeStandby.c * * @author (last) Dara Navaei -* @date (last) 31-May-2022 +* @date (last) 10-Nov-2023 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 * ***************************************************************************/ #include "ConcentratePumps.h" +#include "ConductivitySensors.h" #include "CPLD.h" #include "DrainPump.h" #include "Heaters.h" #include "MessageSupport.h" +#include "ModeChemicalDisinfect.h" #include "ModeFault.h" +#include "ModeHeatDisinfect.h" #include "ModeStandby.h" +#include "NVDataMgmt.h" #include "OperationModes.h" #include "Pressures.h" #include "Reservoirs.h" @@ -44,8 +48,6 @@ #define MAX_WATER_SAMPLE_TIME_MS ( 10 * MS_PER_SECOND ) ///< Maximum duration of water sample state (in ms). #define FLUSH_EXPIRATION_TIME_MS ( 10 * SEC_PER_MIN * MS_PER_SECOND ) ///< Duration in which a filter flush is valid (in ms). #define FILTER_FLUSH_DATA_PUBLISH_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Filter flush data broadcast interval. -// Milliseconds was too big, greater than U32 -#define DG_SRVC_TIME_INTERVAL_S ( 6 * 30 * SECONDS_IN_A_DAY ) ///< DG service interval in seconds. ( 6 months with 30 days each). // ********** private data ********** @@ -62,50 +64,53 @@ static BOOL pendingStartDGFlushRequest; ///< Flag indicating HD has requested DG start flush. static BOOL pendingStartDGHeatDisinfectRequest; ///< Flag indicating HD has requested DG start heat disinfect. static BOOL pendingStartDGChemicalDisinfectRequest; ///< Flag indicating HD has requested DG start chemical disinfect. +static BOOL pendingStartDGHeatDisinfectActiveCoolRequest; ///< Flag indicating HD has requested DG start heat disinfect active cool. +static BOOL pendingStartDGChemicalDisinfectFlushRequest; ///< Flag indicating HD has requested DG start chemical disinfect flush. +static BOOL pendingStartDGROPermeateSampleRequest; ///< Flag indicating HD has requested DG start RO permeate sample. static OVERRIDE_U32_T filterFlushTimePeriod = { FILTER_FLUSH_TIME_MS, FILTER_FLUSH_TIME_MS, 0, 0 }; ///< Filter flush time period in ms. // ********** private function prototypes ********** +static BOOL areInletWaterConditionsAlarmsActive( void ); + static DG_STANDBY_MODE_STATE_T handleStandbyIdleState( void ); static DG_STANDBY_MODE_STATE_T handleStandbyFlushFilterState( void ); static DG_STANDBY_MODE_STATE_T handleStandbyFlushFilterIdleState( void ); static DG_STANDBY_MODE_STATE_T handleStandbySampleWaterState( void ); +static DG_STANDBY_MODE_STATE_T handleStandbyPauseState( void ); -static BOOL isDisinfectValid( void ); -static BOOL isServiceTimeValid( void ); - /*********************************************************************//** * @brief * The initStandbyMode function initializes the standby mode module. * @details Inputs: none * @details Outputs: standbyState, stopSampleWaterRequest, startSampleWaterRequest, * flushFilterRequest, endSampleWaterRequest, waterSampleStartTime, - * filterFlushStartTime, filterFlushPublishTimerCounter, pendingStartDGRequest + * filterFlushStartTime, filterFlushPublishTimerCounter, pendingStartDGRequest, + * pendingStartDGHeatDisinfectActiveCoolRequest, + * pendingStartDGROPermeateSampleRequest * @return none *************************************************************************/ void initStandbyMode( void ) { - standbyState = DG_STANDBY_MODE_STATE_IDLE; - stopSampleWaterRequest = FALSE; - startSampleWaterRequest = FALSE; - flushFilterRequest = FALSE; - endSampleWaterRequest = FALSE; - waterSampleStartTime = 0; - filterFlushStartTime = 0; - filterFlushPublishTimerCounter = 0; - pendingStartDGRequest = FALSE; - pendingStartDGFlushRequest = FALSE; - pendingStartDGHeatDisinfectRequest = FALSE; - pendingStartDGChemicalDisinfectRequest = FALSE; + standbyState = DG_STANDBY_MODE_STATE_IDLE; + stopSampleWaterRequest = FALSE; + startSampleWaterRequest = FALSE; + flushFilterRequest = FALSE; + endSampleWaterRequest = FALSE; + waterSampleStartTime = 0; + filterFlushStartTime = 0; + filterFlushPublishTimerCounter = 0; + pendingStartDGRequest = FALSE; + pendingStartDGFlushRequest = FALSE; + pendingStartDGHeatDisinfectRequest = FALSE; + pendingStartDGChemicalDisinfectRequest = FALSE; + pendingStartDGHeatDisinfectActiveCoolRequest = FALSE; + pendingStartDGROPermeateSampleRequest = FALSE; // Reset the heaters efficiency for another treatment resetHeatersEstimationGain(); - - // Initialize the reservoirs parameters for another treatment. - // This is to make sure the boolean flag for the first fill is set to TRUE. - initReservoirs(); } /*********************************************************************//** @@ -117,13 +122,34 @@ *************************************************************************/ U32 transitionToStandbyMode( void ) { + MESSAGE_T usageMsg; + // re-initialize standby mode each time we transition to standby mode initStandbyMode(); - deenergizeActuators(); + deenergizeActuators( PARK_CONC_PUMPS ); setCPLDCleanLEDColor( CPLD_CLEAN_LED_OFF ); + // Upon transition to mode standby set CD1 and CD2 calibration records to be picked to the normal + // table. If the chemical disinfect fails, the mode transitions back to mode standby. + setCondcutivitySensorCalTable( CONDUCTIVITYSENSORS_CD1_SENSOR, CAL_DATA_CD1_COND_SENSOR ); + setCondcutivitySensorCalTable( CONDUCTIVITYSENSORS_CD2_SENSOR, CAL_DATA_CD2_COND_SENSOR ); + +#ifndef _RELEASE_ + setHeatNelsonSupportMode( NELSON_NONE ); + setChemNelsonSupportMode( NELSON_NONE ); +#endif + + // Initialize the reservoirs parameters for another treatment. + // This is to make sure the boolean flag for the first fill is set to TRUE. + initReservoirs(); + + // Send DG usage data to HD + usageMsg.hdr.msgID = MSG_ID_HD_DG_USAGE_INFO_REQUEST; + usageMsg.hdr.payloadLen = 0; + handleHDRequestDGUsageInfo( &usageMsg ); + return standbyState; } @@ -136,6 +162,12 @@ *************************************************************************/ U32 execStandbyMode( void ) { + if ( TRUE == areInletWaterConditionsAlarmsActive() ) + { + setValveState( VSP, VALVE_STATE_CLOSED ); + standbyState = DG_STANDBY_MODE_STATE_PAUSE; + } + // execute current Standby state switch ( standbyState ) { @@ -155,6 +187,10 @@ standbyState = handleStandbySampleWaterState(); break; + case DG_STANDBY_MODE_STATE_PAUSE: + standbyState = handleStandbyPauseState(); + break; + default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_STANDBY_MODE_INVALID_EXEC_STATE, standbyState ) standbyState = DG_STANDBY_MODE_STATE_IDLE; @@ -166,6 +202,34 @@ /*********************************************************************//** * @brief + * The areInletWaterConditionsAlarmsActive function checks whether the inlet + * water conditions are out of range and any of their alarms are active. + * @details Inputs: none + * @details Outputs: None + * @return TRUE if any of the alarms are active, otherwise, FALSE + *************************************************************************/ +static BOOL areInletWaterConditionsAlarmsActive( void ) +{ + // Check inlet water conductivity, temperature, pressure, and RO rejection ratio + BOOL status = FALSE; + + checkInletWaterConductivity(); + checkInletWaterTemperature(); + checkInletWaterPressure(); + + status |= isAlarmConditionActive( ALARM_ID_DG_INLET_WATER_CONDUCTIVITY_IN_LOW_RANGE ); + status |= isAlarmConditionActive( ALARM_ID_DG_INLET_WATER_CONDUCTIVITY_IN_HIGH_RANGE ); + status |= isAlarmConditionActive( ALARM_ID_DG_INLET_WATER_TEMPERATURE_IN_HIGH_RANGE ); + status |= isAlarmConditionActive( ALARM_ID_DG_INLET_WATER_TEMPERATURE_IN_LOW_RANGE ); + status |= isAlarmConditionActive( ALARM_ID_DG_OUTLET_PRIMARY_CONDUCTIVITY_OUT_OF_RANGE ); + status |= isAlarmConditionActive( ALARM_ID_DG_INLET_WATER_PRESSURE_IN_HIGH_RANGE ); + status |= isAlarmConditionActive( ALARM_ID_DG_INLET_WATER_PRESSURE_IN_LOW_RANGE ); + + return status; +} + +/*********************************************************************//** + * @brief * The handleStandbyIdleState function executes the idle state of the * standby mode state machine. * @details Inputs: pendingSampleWaterRequest, pendingStartDGRequest, @@ -188,12 +252,10 @@ // if HD requests water sample, go to water sample state else if ( TRUE == flushFilterRequest ) { + setValveState( VPI, VALVE_STATE_OPEN ); flushFilterRequest = FALSE; filterFlushStartTime = getMSTimerCount(); - - setValveState( VPI, VALVE_STATE_OPEN ); - - state = DG_STANDBY_MODE_STATE_FLUSH_FILTER; + state = DG_STANDBY_MODE_STATE_FLUSH_FILTER; } else if ( TRUE == pendingStartDGRequest ) { @@ -204,22 +266,35 @@ else if ( TRUE == pendingStartDGFlushRequest ) { pendingStartDGFlushRequest = FALSE; - requestNewOperationMode( DG_MODE_FLUS ); } else if ( TRUE == pendingStartDGHeatDisinfectRequest ) { pendingStartDGHeatDisinfectRequest = FALSE; - requestNewOperationMode( DG_MODE_HEAT ); } else if ( TRUE == pendingStartDGChemicalDisinfectRequest ) { pendingStartDGChemicalDisinfectRequest = FALSE; - requestNewOperationMode( DG_MODE_CHEM ); } + else if ( TRUE == pendingStartDGHeatDisinfectActiveCoolRequest ) + { + pendingStartDGHeatDisinfectActiveCoolRequest = FALSE; + requestNewOperationMode( DG_MODE_HCOL ); + } + else if ( TRUE == pendingStartDGChemicalDisinfectFlushRequest ) + { + pendingStartDGChemicalDisinfectFlushRequest = FALSE; + requestNewOperationMode( DG_MODE_CHFL ); + } + else if ( TRUE == pendingStartDGROPermeateSampleRequest ) + { + pendingStartDGROPermeateSampleRequest = FALSE; + requestNewOperationMode( DG_MODE_ROPS ); + } + return state; } @@ -236,8 +311,6 @@ DG_STANDBY_MODE_STATE_T state = DG_STANDBY_MODE_STATE_FLUSH_FILTER; U32 filterFlushTimePeriod_ms = getU32OverrideValue( &filterFlushTimePeriod ); - checkInletWaterPressure(); - if ( TRUE == didTimeout( filterFlushStartTime, filterFlushTimePeriod_ms ) ) { setValveState( VPI, VALVE_STATE_CLOSED ); @@ -252,7 +325,7 @@ data.countdown = data.timeout - ( calcTimeSince( filterFlushStartTime ) / MS_PER_SECOND ); filterFlushPublishTimerCounter = 0; - broadcastData( MSG_ID_DG_FILTER_FLUSH_PROGRESS, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&data, sizeof( STANDBY_MODE_DATA_T ) ); + broadcastData( MSG_ID_DG_FILTER_FLUSH_PROGRESS_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&data, sizeof( STANDBY_MODE_DATA_T ) ); } if ( TRUE == endSampleWaterRequest ) @@ -280,7 +353,6 @@ if ( TRUE == startSampleWaterRequest ) { - startSampleWaterRequest = FALSE; waterSampleStartTime = getMSTimerCount(); setValveState( VPI, VALVE_STATE_OPEN ); setValveState( VSP, VALVE_STATE_OPEN ); @@ -294,6 +366,8 @@ state = DG_STANDBY_MODE_STATE_IDLE; } + startSampleWaterRequest = FALSE; + return state; } @@ -309,11 +383,12 @@ { DG_STANDBY_MODE_STATE_T state = DG_STANDBY_MODE_STATE_SAMPLE_WATER; - // After HD requests to stop or 10 seconds has elapsed, close and return to idle state + // After HD requests to stop or 10 seconds has elapsed, close and return to idle state if ( ( TRUE == stopSampleWaterRequest ) || ( TRUE == didTimeout( waterSampleStartTime, MAX_WATER_SAMPLE_TIME_MS ) ) ) { stopSampleWaterRequest = FALSE; setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPI, VALVE_STATE_CLOSED ); state = DG_STANDBY_MODE_STATE_FLUSH_FILTER_IDLE; } @@ -322,60 +397,26 @@ /*********************************************************************//** * @brief - * The isDisinfectValid function checks whether the last disinfect has been - * voided or not + * The handleStandbyPauseState function executes the pause state. * @details Inputs: none - * @details Outputs: none - * @return TRUE if the disinfect is still valid otherwise, FALSE - ***********************************************************************/ -static BOOL isDisinfectValid( void ) + * @details Outputs: filterFlushStartTime + * @return the next state + *************************************************************************/ +static DG_STANDBY_MODE_STATE_T handleStandbyPauseState( void ) { - BOOL status = TRUE; - DG_USAGE_INFO_RECORD_T dgUsageInfo; + DG_STANDBY_MODE_STATE_T state = DG_STANDBY_MODE_STATE_PAUSE; - // No need to check the CRC of the record because the record'sCRC has been checked in NV POST. - getNVRecord2Driver( GET_USAGE_RECORD, (U08*)&dgUsageInfo, sizeof( DG_USAGE_INFO_RECORD_T ), 0, ALARM_ID_NO_ALARM ); - - if ( FALSE == dgUsageInfo.isDisinfected ) + if ( FALSE == areInletWaterConditionsAlarmsActive() ) { - status = FALSE; - - activateAlarmNoData( ALARM_ID_DG_DISINFECT_HAS_BEEN_EXPIRED ); + filterFlushStartTime = getMSTimerCount(); + state = DG_STANDBY_MODE_STATE_FLUSH_FILTER; } - return status; + return state; } /*********************************************************************//** * @brief - * The isServiceTimeValid function checks whether the last service time is - * still within the interval or not. - * @details Inputs: none - * @details Outputs: none - * @return TRUE if the service time is still valid otherwise, FALSE - ***********************************************************************/ -static BOOL isServiceTimeValid( void ) -{ - BOOL status = TRUE; - DG_SERVICE_RECORD_T dgServiceRecord; - - // No need to check the CRC of the record because the record'sCRC has been checked in NV POST. - getNVRecord2Driver( GET_SRV_RECORD, (U08*)&dgServiceRecord, sizeof( DG_SERVICE_RECORD_T ), 0, ALARM_ID_NO_ALARM ); - - if ( ( ( getRTCTimestamp() - dgServiceRecord.lastServiceEpochDate ) / MS_PER_SECOND > DG_SRVC_TIME_INTERVAL_S ) || - ( 0 == dgServiceRecord.lastServiceEpochDate ) ) - { - // Compare the current time in epoch to the last service data in epoch and convert them to seconds - status = FALSE; - - activateAlarmNoData( ALARM_ID_DG_SERIVCE_TIME_INTERVAL_HAS_ELAPSED ); - } - - return status; -} - -/*********************************************************************//** - * @brief * The requestWaterSample function handles an HD request to sample water. * @details Inputs: standbyState * @details Outputs: pendingSampleWaterRequest @@ -444,23 +485,8 @@ *************************************************************************/ BOOL requestDGStart( void ) { - BOOL result = FALSE; - BOOL disinfectStatus = TRUE; - BOOL serviceStatus = TRUE; + BOOL result = FALSE; -/*#ifndef _RELEASE_ - if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_SERVICE_AND_DISINFECT_CHECK ) ) - { - disinfectStatus = TRUE; - serviceStatus = TRUE; - } - else -#endif - { - disinfectStatus = isDisinfectValid(); - serviceStatus = isServiceTimeValid(); - }*/ - if ( DG_STANDBY_MODE_STATE_IDLE == standbyState ) { result = TRUE; @@ -475,6 +501,29 @@ /*********************************************************************//** * @brief + * The signalAbortWaterSampling function handles an HD request to abort water + * sampling (return to standby idle state). + * @details Inputs: none + * @details Outputs: standby mode variable initialized + * @return TRUE if request accepted, FALSE if not + *************************************************************************/ +BOOL signalAbortWaterSampling( void ) +{ + BOOL result = FALSE; + + if ( ( DG_MODE_STAN == getCurrentOperationMode() ) && ( standbyState != DG_STANDBY_MODE_STATE_IDLE ) ) + { + result = TRUE; + initStandbyMode(); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPI, VALVE_STATE_CLOSED ); + } + + return result; +} + +/*********************************************************************//** + * @brief * The startDGFlush function starts DG flush mode. * @details Inputs: standbyState * @details Outputs: none @@ -488,7 +537,10 @@ if ( ( DG_MODE_STAN == getCurrentOperationMode() ) && ( DG_STANDBY_MODE_STATE_IDLE == standbyState ) || ( DG_MODE_SOLO == getCurrentOperationMode() ) ) { DG_CMD_RESPONSE_T cmdResponse; + DG_USAGE_INFO_RECORD_T usageInfo; + getNVRecord2Driver( GET_USAGE_RECORD, (U08*)&usageInfo, sizeof( DG_USAGE_INFO_RECORD_T ), 0, ALARM_ID_NO_ALARM ); + OPN_CLS_STATE_T concCap = getSwitchStatus( CONCENTRATE_CAP ); OPN_CLS_STATE_T diaCap = getSwitchStatus( DIALYSATE_CAP ); cmdResponse.commandID = DG_CMD_START_FLUSH; @@ -500,6 +552,10 @@ { concCap = STATE_CLOSED; diaCap = STATE_CLOSED; + // Using the caps switch to disable the chemical disinfect date checks + // This is for debug builds only to simulate that a chem flush has been done after chem + usageInfo.lastChemDisFlushCompleteDateEpoch = 40; + usageInfo.lastChemDisStartDateEpoch = 32; } #endif @@ -509,6 +565,11 @@ cmdResponse.rejectCode = ( STATE_OPEN == getSwitchStatus( DIALYSATE_CAP ) ? REQUEST_REJECT_REASON_DG_DIALYSATE_CAP_OPEN : REQUEST_REJECT_REASON_DG_CONCENTRATE_CAP_OPEN ); } + else if ( usageInfo.lastChemDisFlushCompleteDateEpoch < usageInfo.lastChemDisStartDateEpoch ) + { + cmdResponse.rejected = TRUE; + cmdResponse.rejectCode = REQUEST_REJECT_REASON_DG_CHEM_FLUSH_NOT_COMPLETED; + } else { pendingStartDGFlushRequest = TRUE; @@ -533,21 +594,28 @@ BOOL status = FALSE; // If DG is in standby mode and the standby mode is in Idle state or if DG is in solo mode, request DG heat disinfect - if ( ( DG_MODE_STAN == getCurrentOperationMode() ) && ( DG_STANDBY_MODE_STATE_IDLE == standbyState ) || ( DG_MODE_SOLO == getCurrentOperationMode() ) ) + if ( ( ( DG_MODE_STAN == getCurrentOperationMode() ) && ( DG_STANDBY_MODE_STATE_IDLE == standbyState ) ) || ( DG_MODE_SOLO == getCurrentOperationMode() ) ) { DG_CMD_RESPONSE_T cmdResponse; - - cmdResponse.commandID = DG_CMD_START_HEAT_DISINFECT; - cmdResponse.rejected = FALSE; - cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_NONE; + DG_USAGE_INFO_RECORD_T usageInfo; OPN_CLS_STATE_T concCap = getSwitchStatus( CONCENTRATE_CAP ); OPN_CLS_STATE_T diaCap = getSwitchStatus( DIALYSATE_CAP ); + getNVRecord2Driver( GET_USAGE_RECORD, (U08*)&usageInfo, sizeof( DG_USAGE_INFO_RECORD_T ), 0, ALARM_ID_NO_ALARM ); + + cmdResponse.commandID = DG_CMD_START_HEAT_DISINFECT; + cmdResponse.rejected = FALSE; + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_NONE; + #ifndef _RELEASE_ if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_CAPS_MONITOR ) ) { concCap = STATE_CLOSED; diaCap = STATE_CLOSED; + // Using the caps switch to disable the chemical disinfect date checks + // This is for debug builds only to simulate that a chem flush has been done after chem + usageInfo.lastChemDisFlushCompleteDateEpoch = 40; + usageInfo.lastChemDisStartDateEpoch = 32; } #endif @@ -557,6 +625,11 @@ cmdResponse.rejectCode = ( STATE_OPEN == getSwitchStatus( DIALYSATE_CAP ) ? REQUEST_REJECT_REASON_DG_DIALYSATE_CAP_OPEN : REQUEST_REJECT_REASON_DG_CONCENTRATE_CAP_OPEN ); } + else if ( usageInfo.lastChemDisFlushCompleteDateEpoch < usageInfo.lastChemDisStartDateEpoch ) + { + cmdResponse.rejected = TRUE; + cmdResponse.rejectCode = REQUEST_REJECT_REASON_DG_CHEM_FLUSH_NOT_COMPLETED; + } else { pendingStartDGHeatDisinfectRequest = TRUE; @@ -571,6 +644,67 @@ /*********************************************************************//** * @brief + * The startDGHeatDisinfectActiveCool function starts heat disinfect active + * cool mode. + * @details Inputs: standbyState + * @details Outputs: none + * @return: TRUE if the switch was successful + *************************************************************************/ +BOOL startDGHeatDisinfectActiveCool( void ) +{ + BOOL status = FALSE; + + // If DG is in standby mode and the standby mode is in Idle state or if DG is in solo mode, request DG heat disinfect + if ( ( DG_MODE_STAN == getCurrentOperationMode() ) && ( DG_STANDBY_MODE_STATE_IDLE == standbyState ) || ( DG_MODE_SOLO == getCurrentOperationMode() ) ) + { + DG_CMD_RESPONSE_T cmdResponse; + DG_USAGE_INFO_RECORD_T usageInfo; + OPN_CLS_STATE_T concCap = getSwitchStatus( CONCENTRATE_CAP ); + OPN_CLS_STATE_T diaCap = getSwitchStatus( DIALYSATE_CAP ); + + getNVRecord2Driver( GET_USAGE_RECORD, (U08*)&usageInfo, sizeof( DG_USAGE_INFO_RECORD_T ), 0, ALARM_ID_NO_ALARM ); + + cmdResponse.commandID = DG_CMD_START_HEAT_DISINFECT; + cmdResponse.rejected = FALSE; + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_NONE; + +#ifndef _RELEASE_ + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_CAPS_MONITOR ) ) + { + concCap = STATE_CLOSED; + diaCap = STATE_CLOSED; + // Using the caps switch to disable the chemical disinfect date checks + // This is for debug builds only to simulate that a chem flush has been done after chem + usageInfo.lastChemDisFlushCompleteDateEpoch = 40; + usageInfo.lastChemDisStartDateEpoch = 32; + } +#endif + + if ( ( STATE_OPEN == concCap ) || ( STATE_OPEN == diaCap ) ) + { + cmdResponse.rejected = TRUE; + cmdResponse.rejectCode = ( STATE_OPEN == getSwitchStatus( DIALYSATE_CAP ) ? REQUEST_REJECT_REASON_DG_DIALYSATE_CAP_OPEN : + REQUEST_REJECT_REASON_DG_CONCENTRATE_CAP_OPEN ); + } + else if ( usageInfo.lastChemDisFlushCompleteDateEpoch < usageInfo.lastChemDisStartDateEpoch ) + { + cmdResponse.rejected = TRUE; + cmdResponse.rejectCode = REQUEST_REJECT_REASON_DG_CHEM_FLUSH_NOT_COMPLETED; + } + else + { + pendingStartDGHeatDisinfectActiveCoolRequest = TRUE; + status = TRUE; + } + + sendCommandResponseMsg( &cmdResponse ); + } + + return status; +} + +/*********************************************************************//** + * @brief * The startDGChemicalDisinfect function starts chemical disinfect mode. * @details Inputs: standbyState * @details Outputs: none @@ -589,6 +723,53 @@ cmdResponse.commandID = DG_CMD_START_CHEM_DISINFECT; cmdResponse.rejected = FALSE; cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_NONE; + OPN_CLS_STATE_T diaCap = getSwitchStatus( DIALYSATE_CAP ); + +#ifndef _RELEASE_ + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_CAPS_MONITOR ) ) + { + diaCap = STATE_CLOSED; + } +#endif + + // When chemical disinfect is about to be started, dialysate caps must be closed + if ( STATE_OPEN == diaCap ) + { + cmdResponse.rejected = TRUE; + cmdResponse.rejectCode = REQUEST_REJECT_REASON_DG_DIALYSATE_CAP_OPEN; + } + else + { + pendingStartDGChemicalDisinfectRequest = TRUE; + status = TRUE; + } + + sendCommandResponseMsg( &cmdResponse ); + } + + return status; +} + +/*********************************************************************//** + * @brief + * The startDGChemicalDisinfectFlush function starts chemical disinfect flush mode. + * @details Inputs: standbyState + * @details Outputs: none + * @return: TRUE if the switch was successful + *************************************************************************/ +BOOL startDGChemicalDisinfectFlush( void ) +{ + BOOL status = FALSE; + DG_CMD_RESPONSE_T cmdResponse; + + cmdResponse.commandID = DG_CMD_START_CHEM_DISINFECT_FLUSH; + cmdResponse.rejected = FALSE; + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_NONE; + + // If DG is in standby mode and the standby mode is in Idle, request chemical disinfect flush + // Chemical disinfect flush cannot be run in solo mode because the user has to confirm that the acid is inserted or removed + if ( ( DG_MODE_STAN == getCurrentOperationMode() ) && ( DG_STANDBY_MODE_STATE_IDLE == standbyState ) ) + { OPN_CLS_STATE_T concCap = getSwitchStatus( CONCENTRATE_CAP ); OPN_CLS_STATE_T diaCap = getSwitchStatus( DIALYSATE_CAP ); @@ -600,22 +781,91 @@ } #endif - // When chemical disinfect is about to be started, both caps must be closed if ( ( STATE_OPEN == concCap ) || ( STATE_OPEN == diaCap ) ) { cmdResponse.rejected = TRUE; cmdResponse.rejectCode = ( STATE_OPEN == getSwitchStatus( DIALYSATE_CAP ) ? REQUEST_REJECT_REASON_DG_DIALYSATE_CAP_OPEN : REQUEST_REJECT_REASON_DG_CONCENTRATE_CAP_OPEN ); - } + } else { - pendingStartDGChemicalDisinfectRequest = TRUE; - status = TRUE; + pendingStartDGChemicalDisinfectFlushRequest = TRUE; + status = TRUE; } + } + else + { + cmdResponse.rejected = TRUE; + cmdResponse.rejectCode = REQUEST_REJECT_REASON_DG_NOT_IN_STANDBY_IDLE_STATE; + } - sendCommandResponseMsg( &cmdResponse ); + sendCommandResponseMsg( &cmdResponse ); + + return status; +} + +/*********************************************************************//** + * @brief + * The startDGROPermeateSample function starts RO permeate sample mode. + * @details Inputs: standbyState + * @details Outputs: pendingStartDGChemicalDisinfectFlushRequest + * @return: TRUE if the switch was successful + *************************************************************************/ +BOOL startDGROPermeateSample( void ) +{ + BOOL status = FALSE; + DG_CMD_RESPONSE_T cmdResponse; + + cmdResponse.commandID = DG_CMD_START_RO_PERMEATE_SAMPLE; + cmdResponse.rejected = FALSE; + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_NONE; + + // If DG is in standby mode and the standby mode is in Idle, request RO permeate sample + if ( ( DG_MODE_STAN == getCurrentOperationMode() ) && ( DG_STANDBY_MODE_STATE_IDLE == standbyState ) ) + { + DG_USAGE_INFO_RECORD_T usageInfo; + OPN_CLS_STATE_T concCap = getSwitchStatus( CONCENTRATE_CAP ); + OPN_CLS_STATE_T diaCap = getSwitchStatus( DIALYSATE_CAP ); + + getNVRecord2Driver( GET_USAGE_RECORD, (U08*)&usageInfo, sizeof( DG_USAGE_INFO_RECORD_T ), 0, ALARM_ID_NO_ALARM ); + +#ifndef _RELEASE_ + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_CAPS_MONITOR ) ) + { + concCap = STATE_CLOSED; + diaCap = STATE_CLOSED; + // Using the caps switch to disable the chemical disinfect date checks. + // This is for debug builds only to simulate that a chem flush has been done after chem + usageInfo.lastChemDisFlushCompleteDateEpoch = 40; + usageInfo.lastChemDisStartDateEpoch = 32; + } +#endif + + if ( ( STATE_OPEN == concCap ) || ( STATE_OPEN == diaCap ) ) + { + cmdResponse.rejected = TRUE; + cmdResponse.rejectCode = ( STATE_OPEN == getSwitchStatus( DIALYSATE_CAP ) ? REQUEST_REJECT_REASON_DG_DIALYSATE_CAP_OPEN : + REQUEST_REJECT_REASON_DG_CONCENTRATE_CAP_OPEN ); + } + else if ( usageInfo.lastChemDisFlushCompleteDateEpoch < usageInfo.lastChemDisStartDateEpoch ) + { + cmdResponse.rejected = TRUE; + cmdResponse.rejectCode = REQUEST_REJECT_REASON_DG_CHEM_FLUSH_NOT_COMPLETED; + } + else + { + pendingStartDGROPermeateSampleRequest = TRUE; + status = TRUE; + } } + else + { + cmdResponse.rejected = TRUE; + cmdResponse.rejectCode = REQUEST_REJECT_REASON_DG_NOT_IN_STANDBY_IDLE_STATE; + } + sendCommandResponseMsg( &cmdResponse ); + return status; }