/************************************************************************** * * Copyright (c) 2024-2025 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) “rkallala” * @date (last) 09-Dec-2025 * * @author (original) Vinayakam Mani * @date (original) 07-Aug-2024 * ***************************************************************************/ #include "BalancingChamber.h" #include "ConcentratePumps.h" #include "ConductivitySensors.h" #include "Heaters.h" #include "ModeFault.h" #include "ModeStandby.h" #include "ModeGenDialysate.h" #include "MessageSupport.h" #include "Messaging.h" //#include "NVDataMgmt.h" #include "OperationModes.h" #include "PermeateTank.h" #include "Pressure.h" #include "SystemCommDD.h" #include "TaskGeneral.h" //#include "Timers.h" #include "Valves.h" /** * @addtogroup DDStandbyMode * @{ */ // ********** private definitions ********** // ********** private data ********** static DD_STANDBY_MODE_STATE_T standbyState; ///< Currently active standby state. static BOOL pendingStartDDPreGenRequest; ///< Flag indicating TD has requested DD start the pre generation dialysate request. static BOOL pendingBalanceChamberSwOnlyRequest; ///< Flag indicating balancing chamber switch only request. //static BOOL pendingStartDDFlushRequest; ///< Flag indicating TD has requested DD start flush. //static BOOL pendingStartDDHeatDisinfectRequest; ///< Flag indicating TD has requested DD start heat disinfect. //static BOOL pendingStartDDHeatDisinfectActiveCoolRequest; ///< Flag indicating TD has requested DD start heat disinfect active cool. //static BOOL pendingStartDGROPermeateSampleRequest; ///< Flag indicating TD has requested DD to command RO to start permeate sample. // ********** private function prototypes ********** static DD_STANDBY_MODE_STATE_T handleStandbyIdleState( void ); static DD_STANDBY_MODE_STATE_T handleStandbyPauseState( void ); /*********************************************************************//** * @brief * The initStandbyMode function initializes the standby mode unit. * @details \b Inputs: none * @details \b Outputs:unit variables initialized. * @return none *************************************************************************/ void initStandbyMode( void ) { standbyState = DD_STANDBY_MODE_STATE_IDLE; pendingStartDDPreGenRequest = FALSE; pendingBalanceChamberSwOnlyRequest = FALSE; // pendingStartDDFlushRequest = FALSE; // pendingStartDDHeatDisinfectRequest = FALSE; // pendingStartDDHeatDisinfectActiveCoolRequest = FALSE; // pendingStartDDROPermeateSampleRequest = FALSE; } /*********************************************************************//** * @brief * The transitionToStandbyMode function prepares for transition to standby mode. * while transition, deenergize all actuators and update DD usage info to TD module. * @details \b Inputs: none * @details \b 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 ); resetPermeateTank(); // // 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( D17_COND, CAL_DATA_CD1_COND_SENSOR ); // setCondcutivitySensorCalTable( D27_COND, CAL_DATA_CD2_COND_SENSOR ); // // // Send DD usage data to TD // 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; //handleTDRequestDDUsageInfo( &usageMsg ); return standbyState; } /*********************************************************************//** * @brief * The execStandbyMode function executes the standby mode state machine. * @details \b Inputs: none * @details \b Outputs: Standby mode state machine executed * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT if stanbyState is invalid. * @return current state *************************************************************************/ U32 execStandbyMode( void ) { // execute current Standby state switch ( standbyState ) { case DD_STANDBY_MODE_STATE_IDLE: standbyState = handleStandbyIdleState(); break; case DD_STANDBY_MODE_STATE_PAUSE: standbyState = handleStandbyPauseState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_STANDBY_MODE_INVALID_EXEC_STATE, standbyState ) standbyState = DD_STANDBY_MODE_STATE_IDLE; break; } return standbyState; } /*********************************************************************//** * @brief * The handleStandbyIdleState function executes the idle state of the * standby mode state machine. * @details \b Inputs: pendingSampleWaterRequest, pendingStartDDPreGenRequest, * pendingStartDDFlushRequest, pendingStartDDHeatDisinfectRequest, * pendingStartDDChemicalDisinfectRequest * @details \b Outputs: Idle state of the standby mode executed, * pendingStartDDFlushRequest, pendingStartDDHeatDisinfectRequest, * pendingStartDDChemicalDisinfectRequest * @details \b Message \Sent: DD_EVENT_TD_COMMUNICATION_LOSS ( Evend Id:8 ) * updates TD communication loss. * @return the next state *************************************************************************/ static DD_STANDBY_MODE_STATE_T handleStandbyIdleState( void ) { DD_STANDBY_MODE_STATE_T state = DD_STANDBY_MODE_STATE_IDLE; //Testing hydChamberWaterInletControl(); //TODO : Define comm loss alarm when TD is turned off or stops communicating // if ( FALSE == isTDCommunicating() ) // { // define the alarm // } if ( TRUE == pendingStartDDPreGenRequest ) { pendingStartDDPreGenRequest = FALSE; requestNewOperationMode( DD_MODE_PREG ); } //Test request to handle only balancing chamber switching else if ( TRUE == pendingBalanceChamberSwOnlyRequest ) { execBalancingChamberControl(); } // else if ( TRUE == pendingStartDDFlushRequest ) // { // pendingStartDDFlushRequest = FALSE; // requestNewOperationMode( DD_MODE_FLUS ); // } // else if ( TRUE == pendingStartDDHeatDisinfectRequest ) // { // pendingStartDDHeatDisinfectRequest = FALSE; // requestNewOperationMode( DD_MODE_HEAT ); // } // else if ( TRUE == pendingStartDDHeatDisinfectActiveCoolRequest ) // { // pendingStartDDHeatDisinfectActiveCoolRequest = FALSE; // // requestNewOperationMode( DD_MODE_HCOL ); // } // else if ( TRUE == pendingStartDDROPermeateSampleRequest ) // { // pendingStartDDROPermeateSampleRequest = FALSE; // requestNewOperationMode( DD_MODE_ROPS ); // } return state; } /*********************************************************************//** * @brief * The handleStandbyPauseState function executes the standby pause state. * @details \b Inputs: Water inlet pressure alarms * @details \b Outputs: state * @return the next state *************************************************************************/ static DD_STANDBY_MODE_STATE_T handleStandbyPauseState( void ) { DD_STANDBY_MODE_STATE_T state = DD_STANDBY_MODE_STATE_PAUSE; return state; } /*********************************************************************//** * @brief * The requestDDPreGenStart function handles an TD request to start/ * go to pre generation dialysis mode. * @details \b Inputs: standbyState * @details \b Outputs: pendingStartDDPreGenRequest * @return TRUE if request accepted, FALSE if not. *************************************************************************/ BOOL requestDDPreGenStart( void ) { BOOL result = FALSE; if ( DD_STANDBY_MODE_STATE_IDLE == standbyState ) { result = TRUE; pendingStartDDPreGenRequest = TRUE; } return result; } /*********************************************************************//** * @brief * The requestBCSwitchingOnlyStart function handles Balancing chamber switching * only start request. * @details \b Inputs: standbyState * @details \b Outputs: pendingBalanceChamberSwOnlyRequest * @return TRUE if request accepted, FALSE if not. *************************************************************************/ BOOL requestBCSwitchingOnlyStart( void ) { BOOL result = FALSE; if ( DD_STANDBY_MODE_STATE_IDLE == standbyState ) { result = TRUE; pendingBalanceChamberSwOnlyRequest = TRUE; } return result; } /*********************************************************************//** * @brief * The requestBCSwitchingOnlyStop function handles Balancing chamber switching * only stop request. * @details \b Inputs: standbyState * @details \b Outputs: pendingBalanceChamberSwOnlyRequest * @return none. *************************************************************************/ void requestBCSwitchingOnlyStop( void ) { pendingBalanceChamberSwOnlyRequest = FALSE; // Close all balancing chamber valves valveControlForBCClosedState(); } /*********************************************************************//** * @brief * The startDDFlush function starts DD flush mode. * @details \b Inputs: standbyState * @details \b Outputs: none * @return: TRUE if the switch was successful, otherwise FALSE *************************************************************************/ BOOL startDDFlush( void ) { BOOL result = FALSE; // // If DD is in standby mode or in the solo mode and the standby mode is in Idle state, request DD flush // if ( ( DD_MODE_STAN == getCurrentOperationMode() ) && ( DD_STANDBY_MODE_STATE_IDLE == standbyState ) || ( DD_MODE_SOLO == getCurrentOperationMode() ) ) // { // DD_CMD_RESPONSE_T cmdResponse; // DD_USAGE_INFO_RECORD_T usageInfo; // // getNVRecord2Driver( GET_USAGE_RECORD, (U08*)&usageInfo, sizeof( DD_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 = DD_CMD_START_FLUSH; // cmdResponse.rejected = FALSE; // cmdResponse.rejectCode = DD_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_DD_DIALYSATE_CAP_OPEN : // REQUEST_REJECT_REASON_DD_CONCENTRATE_CAP_OPEN ); // } // else if ( usageInfo.lastChemDisFlushCompleteDateEpoch < usageInfo.lastChemDisStartDateEpoch ) // { // cmdResponse.rejected = TRUE; // cmdResponse.rejectCode = REQUEST_REJECT_REASON_DD_CHEM_FLUSH_NOT_COMPLETED; // } // else // { // pendingStartDDFlushRequest = TRUE; // result = TRUE; // } // // sendCommandResponseMsg( &cmdResponse ); // } return result; } /*********************************************************************//** * @brief * The startDDHeatDisinfect function starts heat disinfect mode. * @details \b Inputs: standbyState * @details \b Outputs: none * @return: TRUE if the switch was successful *************************************************************************/ BOOL startDDHeatDisinfect( void ) { BOOL status = FALSE; // // If DD is in standby mode and the standby mode is in Idle state or if DD is in solo mode, request DD heat disinfect // if ( ( ( DD_MODE_STAN == getCurrentOperationMode() ) && ( DD_STANDBY_MODE_STATE_IDLE == standbyState ) ) || ( DD_MODE_SOLO == getCurrentOperationMode() ) ) // { // DD_CMD_RESPONSE_T cmdResponse; // DD_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( DD_USAGE_INFO_RECORD_T ), 0, ALARM_ID_NO_ALARM ); // // cmdResponse.commandID = DD_CMD_START_HEAT_DISINFECT; // cmdResponse.rejected = FALSE; // cmdResponse.rejectCode = DD_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_DD_DIALYSATE_CAP_OPEN : // REQUEST_REJECT_REASON_DD_CONCENTRATE_CAP_OPEN ); // } // else if ( usageInfo.lastChemDisFlushCompleteDateEpoch < usageInfo.lastChemDisStartDateEpoch ) // { // cmdResponse.rejected = TRUE; // cmdResponse.rejectCode = REQUEST_REJECT_REASON_DD_CHEM_FLUSH_NOT_COMPLETED; // } // else // { // pendingStartDDHeatDisinfectRequest = TRUE; // status = TRUE; // } // // sendCommandResponseMsg( &cmdResponse ); // } return status; } /*********************************************************************//** * @brief * The startDDHeatDisinfectActiveCool function starts heat disinfect active * cool mode. * @details \b Inputs: standbyState * @details \b Outputs: none * @return: TRUE if the switch was successful *************************************************************************/ BOOL startDDHeatDisinfectActiveCool( void ) { BOOL status = FALSE; // // If DD is in standby mode and the standby mode is in Idle state or if DD is in solo mode, request DD heat disinfect // if ( ( DD_MODE_STAN == getCurrentOperationMode() ) && ( DD_STANDBY_MODE_STATE_IDLE == standbyState ) || ( DD_MODE_SOLO == getCurrentOperationMode() ) ) // { // DD_CMD_RESPONSE_T cmdResponse; // DD_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( DD_USAGE_INFO_RECORD_T ), 0, ALARM_ID_NO_ALARM ); // // cmdResponse.commandID = DD_CMD_START_HEAT_DISINFECT; // cmdResponse.rejected = FALSE; // cmdResponse.rejectCode = DD_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_DD_DIALYSATE_CAP_OPEN : // REQUEST_REJECT_REASON_DD_CONCENTRATE_CAP_OPEN ); // } // else if ( usageInfo.lastChemDisFlushCompleteDateEpoch < usageInfo.lastChemDisStartDateEpoch ) // { // cmdResponse.rejected = TRUE; // cmdResponse.rejectCode = REQUEST_REJECT_REASON_DD_CHEM_FLUSH_NOT_COMPLETED; // } // else // { // pendingStartDDHeatDisinfectActiveCoolRequest = TRUE; // status = TRUE; // } // // sendCommandResponseMsg( &cmdResponse ); // } return status; } /*********************************************************************//** * @brief * The getCurrentStandbyState function returns the current state of standby mode. * @details \b Inputs: standbyState * @details \b Outputs: none * @return the current state of standby mode. *************************************************************************/ DD_STANDBY_MODE_STATE_T getCurrentStandbyState( void ) { return standbyState; } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /**@}*/