/************************************************************************** * * 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) 23-Jul-2024 * * @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 "ModeFill.h" #include "ModeHeatDisinfect.h" #include "ModeStandby.h" #include "NVDataMgmt.h" #include "OperationModes.h" #include "Pressures.h" #include "Reservoirs.h" #include "ROPump.h" #include "RTC.h" #include "SystemComm.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "TemperatureSensors.h" #include "Timers.h" #include "Valves.h" /** * @addtogroup DGStandbyMode * @{ */ // ********** private definitions ********** #define FILTER_FLUSH_TIME_MS ( 120 * MS_PER_SECOND ) ///< Duration of filter flush state (in ms). #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. // ********** private data ********** static DG_STANDBY_MODE_STATE_T standbyState; ///< Currently active standby state. static BOOL stopSampleWaterRequest; ///< Flag indicating HD has requested to stop sample water static BOOL startSampleWaterRequest; ///< Flag indicating HD has requested to start sample water static BOOL flushFilterRequest; ///< Flag indicating HD has requested to flush filters static BOOL endSampleWaterRequest; ///< Flag indicating HD has requested to end sample water static BOOL pendingStartDGRequest; ///< Flag indicating HD has requested DG start (go to generation idle mode). static U32 waterSampleStartTime; ///< Time stamp for start of water sample state. static U32 filterFlushStartTime; ///< Time stamp for start of filter flush state. static U32 filterFlushPublishTimerCounter; ///< Filter flush data publish timer counter. 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 BOOL haveDGInstitutionalValuesBeenRcvd; ///< Flag indicating DG has received DG institutional values. 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 void checkDGInstitutionalValuesReceived( 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 ); /*********************************************************************//** * @brief * The initStandbyMode function initializes the standby mode module. * @details Inputs: none * @details Outputs: standbyState, stopSampleWaterRequest, startSampleWaterRequest, * flushFilterRequest, endSampleWaterRequest, waterSampleStartTime, * filterFlushStartTime, filterFlushPublishTimerCounter, pendingStartDGRequest, * pendingStartDGHeatDisinfectActiveCoolRequest, * pendingStartDGROPermeateSampleRequest, haveDGInstitutionalValuesBeenRcvd * @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; pendingStartDGHeatDisinfectActiveCoolRequest = FALSE; pendingStartDGROPermeateSampleRequest = FALSE; haveDGInstitutionalValuesBeenRcvd = FALSE; // Reset the heaters efficiency for another treatment resetHeatersEstimationGain(); } /*********************************************************************//** * @brief * The transitionToStandbyMode function prepares for transition to standby mode. * @details Inputs: none * @details Outputs: Re-initialized standby mode * @return initial state *************************************************************************/ U32 transitionToStandbyMode( void ) { MESSAGE_T usageMsg; // re-initialize standby mode each time we transition to standby mode initStandbyMode(); 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 // The message ID will not be put here because the messages list script will pick this up for another send command // The only important item is the payload length that must be 0 for the handler usageMsg.hdr.msgID = 0; usageMsg.hdr.payloadLen = 0; handleHDRequestDGUsageInfo( &usageMsg ); return standbyState; } /*********************************************************************//** * @brief * The execStandbyMode function executes the standby mode state machine. * @details Inputs: none * @details Outputs: Standby mode state machine executed * @return current state *************************************************************************/ U32 execStandbyMode( void ) { if ( TRUE == areInletWaterConditionsAlarmsActive() ) { setValveState( VSP, VALVE_STATE_CLOSED ); standbyState = DG_STANDBY_MODE_STATE_PAUSE; } checkDGInstitutionalValuesReceived(); // execute current Standby state switch ( standbyState ) { case DG_STANDBY_MODE_STATE_IDLE: standbyState = handleStandbyIdleState(); break; case DG_STANDBY_MODE_STATE_FLUSH_FILTER: standbyState = handleStandbyFlushFilterState(); break; case DG_STANDBY_MODE_STATE_FLUSH_FILTER_IDLE: standbyState = handleStandbyFlushFilterIdleState(); break; case DG_STANDBY_MODE_STATE_SAMPLE_WATER: 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; break; } return standbyState; } /*********************************************************************//** * @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 checkDGInstitutionalValuesReceived function requests the DG institutional * values from HD if HD is in standby and the values have not been received yet. * @details Inputs: haveDGInstitutionalValuesBeenRcvd * @details Outputs: None * @return none *************************************************************************/ static void checkDGInstitutionalValuesReceived( void ) { HD_MODE_SUB_MODE_T mode; getHDOperationMode( &mode ); if ( (mode.hdMode >= MODE_STAN ) && ( FALSE == haveDGInstitutionalValuesBeenRcvd ) ) { sendDGInstitutionalValuesRequestToHD(); } } /*********************************************************************//** * @brief * The handleStandbyIdleState function executes the idle state of the * standby mode state machine. * @details Inputs: pendingSampleWaterRequest, pendingStartDGRequest, * pendingStartDGFlushRequest, pendingStartDGHeatDisinfectRequest, * pendingStartDGChemicalDisinfectRequest * @details Outputs: Idle state of the standby mode executed, * pendingStartDGFlushRequest, pendingStartDGHeatDisinfectRequest, * pendingStartDGChemicalDisinfectRequest * @return the next state *************************************************************************/ static DG_STANDBY_MODE_STATE_T handleStandbyIdleState( void ) { DG_STANDBY_MODE_STATE_T state = DG_STANDBY_MODE_STATE_IDLE; // go to standby solo mode if HD is turned off or stops communicating. if ( FALSE == isHDCommunicating() ) { // TODO if HD comm loss, should we wait an hour or so before going to solo standby? requestNewOperationMode( DG_MODE_SOLO ); } // if HD requests water sample, go to water sample state else if ( TRUE == flushFilterRequest ) { setValveState( VPI, VALVE_STATE_OPEN ); flushFilterRequest = FALSE; filterFlushStartTime = getMSTimerCount(); state = DG_STANDBY_MODE_STATE_FLUSH_FILTER; } else if ( TRUE == pendingStartDGRequest ) { pendingStartDGRequest = FALSE; signalSyncToHD(); requestBaroSensorMFGInfoCheck(); requestNewOperationMode( DG_MODE_GENE ); } 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; } /*********************************************************************//** * @brief * The handleStandbyFilterFlushState function executes the flush filter state * of the standby mode state machine. * @details Inputs: filterFLushStartTime * @details Outputs: Flushed the filters * @return the next state *************************************************************************/ static DG_STANDBY_MODE_STATE_T handleStandbyFlushFilterState( void ) { DG_STANDBY_MODE_STATE_T state = DG_STANDBY_MODE_STATE_FLUSH_FILTER; U32 filterFlushTimePeriod_ms = getU32OverrideValue( &filterFlushTimePeriod ); if ( TRUE == didTimeout( filterFlushStartTime, filterFlushTimePeriod_ms ) ) { setValveState( VPI, VALVE_STATE_CLOSED ); state = DG_STANDBY_MODE_STATE_FLUSH_FILTER_IDLE; } if ( ++filterFlushPublishTimerCounter >= FILTER_FLUSH_DATA_PUBLISH_INTERVAL ) { STANDBY_MODE_DATA_T data; data.timeout = filterFlushTimePeriod_ms / MS_PER_SECOND; data.countdown = data.timeout - ( calcTimeSince( filterFlushStartTime ) / MS_PER_SECOND ); filterFlushPublishTimerCounter = 0; broadcastData( MSG_ID_DG_FILTER_FLUSH_PROGRESS_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&data, sizeof( STANDBY_MODE_DATA_T ) ); } if ( TRUE == endSampleWaterRequest ) { endSampleWaterRequest = FALSE; setValveState( VPI, VALVE_STATE_CLOSED ); state = DG_STANDBY_MODE_STATE_IDLE; } return state; } /*********************************************************************//** * @brief * The handleStandbyFlushFilterIdleState function executes the flush filter * idle state of the standby mode state machine. * @details Inputs: filterFLushStartTime, startSampleWaterRequest, endSampleWaterRequest * @details Outputs: Flushed the filters, startSampleWaterRequest, endSampleWaterRequest, * waterSampleStartTime * @return the next state *************************************************************************/ static DG_STANDBY_MODE_STATE_T handleStandbyFlushFilterIdleState( void ) { DG_STANDBY_MODE_STATE_T state = DG_STANDBY_MODE_STATE_FLUSH_FILTER_IDLE; if ( TRUE == startSampleWaterRequest ) { waterSampleStartTime = getMSTimerCount(); setValveState( VPI, VALVE_STATE_OPEN ); setValveState( VSP, VALVE_STATE_OPEN ); state = DG_STANDBY_MODE_STATE_SAMPLE_WATER; } if ( TRUE == endSampleWaterRequest ) { endSampleWaterRequest = FALSE; setValveState( VPI, VALVE_STATE_CLOSED ); state = DG_STANDBY_MODE_STATE_IDLE; } startSampleWaterRequest = FALSE; return state; } /*********************************************************************//** * @brief * The handleStandbySampleWaterState function executes the sample water state * of the standby mode state machine. * @details Inputs: stopSampleWaterRequest, waterSampleStartTime * @details Outputs: Finished sample water and closed valve * @return the next state *************************************************************************/ static DG_STANDBY_MODE_STATE_T handleStandbySampleWaterState( void ) { 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 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; } return state; } /*********************************************************************//** * @brief * The handleStandbyPauseState function executes the pause state. * @details Inputs: none * @details Outputs: filterFlushStartTime * @return the next state *************************************************************************/ static DG_STANDBY_MODE_STATE_T handleStandbyPauseState( void ) { DG_STANDBY_MODE_STATE_T state = DG_STANDBY_MODE_STATE_PAUSE; if ( FALSE == areInletWaterConditionsAlarmsActive() ) { filterFlushStartTime = getMSTimerCount(); state = DG_STANDBY_MODE_STATE_FLUSH_FILTER; } return state; } /*********************************************************************//** * @brief * The requestWaterSample function handles an HD request to sample water. * @details Inputs: standbyState * @details Outputs: pendingSampleWaterRequest * @return TRUE if request accepted, FALSE if not. *************************************************************************/ void waterSampleCommandHandler( SAMPLE_WATER_CMD_T sampleWaterCmd ) { DG_CMD_RESPONSE_T cmdResponse; cmdResponse.commandID = DG_CMD_SAMPLE_WATER; cmdResponse.rejected = TRUE; cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_INVALID_MODE; switch ( sampleWaterCmd ) { case SAMPLE_WATER_CMD_STOP: if ( ( DG_MODE_STAN == getCurrentOperationMode() ) && ( DG_STANDBY_MODE_STATE_SAMPLE_WATER == standbyState ) ) { stopSampleWaterRequest = TRUE; cmdResponse.rejected = FALSE; cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_NONE; } break; case SAMPLE_WATER_CMD_START: if ( ( DG_MODE_STAN == getCurrentOperationMode() ) && ( DG_STANDBY_MODE_STATE_FLUSH_FILTER_IDLE == standbyState ) ) { startSampleWaterRequest = TRUE; cmdResponse.rejected = FALSE; cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_NONE; } break; case SAMPLE_WATER_CMD_FLUSH: if ( ( DG_MODE_STAN == getCurrentOperationMode() ) && ( DG_STANDBY_MODE_STATE_IDLE == standbyState ) ) { flushFilterRequest = TRUE; cmdResponse.rejected = FALSE; cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_NONE; } break; case SAMPLE_WATER_CMD_END: if ( DG_MODE_STAN == getCurrentOperationMode() ) { endSampleWaterRequest = TRUE; cmdResponse.rejected = FALSE; cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_NONE; } break; default: cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_INVALID_PARAMETER; break; } sendCommandResponseMsg( &cmdResponse ); } /*********************************************************************//** * @brief * The requestDGStart function handles an HD request to start (go to generation idle mode). * @details Inputs: standbyState * @details Outputs: pendingSampleWaterRequest * @return TRUE if request accepted, FALSE if not. *************************************************************************/ BOOL requestDGStart( void ) { BOOL result = FALSE; if ( ( DG_MODE_STAN == getCurrentOperationMode() ) && ( DG_STANDBY_MODE_STATE_IDLE == standbyState ) ) { result = TRUE; pendingStartDGRequest = TRUE; // Reset the volume accumulator for the next run resetROGenerateVolumeL(); } return result; } /*********************************************************************//** * @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 * @return: TRUE if the switch was successful, otherwise FALSE *************************************************************************/ BOOL startDGFlush( void ) { BOOL result = FALSE; // If DG is in standby mode or in the solo mode and the standby mode is in Idle state, request DG flush 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; 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 { pendingStartDGFlushRequest = TRUE; result = TRUE; } sendCommandResponseMsg( &cmdResponse ); } return result; } /*********************************************************************//** * @brief * The startDGHeatDisinfect function starts heat disinfect mode. * @details Inputs: standbyState * @details Outputs: none * @param isPassive: boolean flag to indicate whether this is passive cool heat * or active cool heat disinfect * @return: TRUE if the switch was successful *************************************************************************/ BOOL startDGHeatDisinfect( BOOL isPassive ) { 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 = ( FALSE == isPassive ? DG_CMD_START_HEAT_DISINFECT_ACTIVE_COOL : DG_CMD_START_HEAT_DISINFECT_PASSIVE_COOL ); 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 { pendingStartDGHeatDisinfectRequest = TRUE; status = TRUE; } sendCommandResponseMsg( &cmdResponse ); } return status; } /*********************************************************************//** * @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_ACTIVE_COOL; 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 * @return: TRUE if the switch was successful *************************************************************************/ BOOL startDGChemicalDisinfect( void ) { BOOL status = FALSE; // If DG is in standby mode and the standby mode is in Idle, request chemical disinfect // Chemical disinfect 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 ) ) { DG_CMD_RESPONSE_T cmdResponse; 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 ); #ifndef _RELEASE_ if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_CAPS_MONITOR ) ) { concCap = STATE_CLOSED; diaCap = STATE_CLOSED; } #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 { pendingStartDGChemicalDisinfectFlushRequest = TRUE; status = TRUE; } } else { cmdResponse.rejected = TRUE; cmdResponse.rejectCode = REQUEST_REJECT_REASON_DG_NOT_IN_STANDBY_IDLE_STATE; } 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; } /*********************************************************************//** * @brief * The getCurrentStandbyState function returns the current state of standby mode. * @details Inputs: standbyState * @details Outputs: none * @return the current state of standby mode. *************************************************************************/ DG_STANDBY_MODE_STATE_T getCurrentStandbyState( void ) { return standbyState; } /*********************************************************************//** * @brief * The getDGInstitutionalValues function sets the signal DG institutional * values have been received. * @details Inputs: none * @details Outputs: haveDGInstitutionalValuesBeenRcvd * @return none *************************************************************************/ void signalDGInstituionalValuesReceived( void ) { haveDGInstitutionalValuesBeenRcvd = TRUE; } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testSetFilterFlushTimePeriodOverride function overrides the filter * flush time period. * @details Inputs: none * @details Outputs: filterFlushTimePeriod * @param value override concentrate pump data publish interval with (in ms) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetFilterFlushTimePeriodOverride( U32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; filterFlushTimePeriod.override = OVERRIDE_KEY; filterFlushTimePeriod.ovData = value; } return result; } /*********************************************************************//** * @brief * The testResetFilterFlushTimePeriodOverride function resets the * override of the filter flush time period. * @details Inputs: none * @details Outputs: filterFlushTimePeriod * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetFilterFlushTimePeriodOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; filterFlushTimePeriod.override = OVERRIDE_RESET; filterFlushTimePeriod.ovData = filterFlushTimePeriod.ovInitData; } return result; } /**@}*/