/************************************************************************** * * Copyright (c) 2024-2026 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) Arpita Srivastava * @date (last) 18-May-2026 * * @author (original) Sean Nash * @date (original) 01-Aug-2024 * ***************************************************************************/ #include "AirTrap.h" #include "BloodFlow.h" #include "Buttons.h" #include "Bubbles.h" #include "DDInterface.h" #include "Messaging.h" #include "ModeInitPOST.h" #include "ModePostTreat.h" #include "ModePreTreat.h" #include "ModeTreatment.h" #include "ModeStandby.h" #include "OperationModes.h" #include "Switches.h" #include "SystemCommTD.h" #include "SyringePump.h" #include "TxParams.h" #include "Valves.h" #include "Valve3Way.h" /** * @addtogroup TDStandbyMode * @{ */ // ********** private definitions ********** #define USER_COMMAND_CANCEL 0 ///< Cancel treatment workflow command code. #define USER_COMMAND_INITIATE 1 ///< Initiate treatment workflow command code. /// DG cleaning mode status data structure typedef struct { BOOL startCleaningMode; ///< Flag to indicate to start cleaning mode. DD_COMMAND_T startRequestCmdID; ///< DG cleaning mode start request command ID. ALARM_ID_T alarmID; ///< The informative alarm to trigger for each cleaning mode. DD_OP_MODE_T ddOpMode; ///< DG operation mode. BOOL sampleRqstTrgrd; ///< Flag to indicate the sample alarm has been triggered (for RO perm and chem flush). GENERIC_CONFIRM_ID_T sampleRequestID; ///< Sample request pass/fail message status. GENERIC_CONFIRM_ID_T stopRequestCmdID; ///< Stop DG cleaning request command ID } DD_CLEANING_MODE_STATUS_T; // ********** private data ********** static TD_STANDBY_STATE_T currentStandbyState; ///< Current state (sub-mode) of standby mode. static BOOL treatStartReqReceived; ///< Flag indicates user has requested initiation of a treatment. static GENERIC_CONFIRM_ID_T disinfectCancelReqID; ///< ID of requested cancel disinfect mode. static BOOL homingInitiated; ///< Boolean flag to indicate homing is initiated. static DD_CLEANING_MODE_STATUS_T currentDDCleaningMode; ///< Current DG cleaning mode status. static BOOL flagNoDisinfectRequired = FALSE; ///< Flag indicates disinfect not required on next mode entry. // ********** private function prototypes ********** static TD_STANDBY_STATE_T handleStandbyModeStartState( void ); static TD_STANDBY_STATE_T handleStandbyModeWaitForTreatmentState( void ); static void clearCurrentCleaningModeStatus( void ); static void setStandbyWaitForTreatmentActuators( void ); static TD_STANDBY_STATE_T handleStandbyModeWaitForDDCleaningModeStartState( void ); static TD_STANDBY_STATE_T handleStandbyModeDDCleaningModeInProgressState( void ); static void handleChemFlushSampleCollection( void ); static void handleROPermeateSampleCollection( void ); static TD_STANDBY_STATE_T handleStandbyModeWaitForDDCleaningModeCmdResponseState( void ); /*********************************************************************//** * @brief * The initStandbyMode function initializes the Standby Mode Unit. * @details \b Inputs: none * @details \b Outputs: currentStandbyState, treatStartReqReceived * @return none *************************************************************************/ void initStandbyMode( void ) { currentStandbyState = STANDBY_START_STATE; treatStartReqReceived = FALSE; disinfectCancelReqID = GENERIC_CONFIRM_ID_NONE; homingInitiated = FALSE; } /*********************************************************************//** * @brief * The transitionToStandbyMode function prepares for transition to standby mode. * @details \b Inputs: none * @details \b Outputs: Standby Mode unit re-initialized, DD interface initialized, * actuators off. * @return initial state *************************************************************************/ U32 transitionToStandbyMode( void ) { // TD_OP_MODE_T previousOpMode = getPreviousOperationMode(); //ToDo U08 requestPayload[3] = { 0U, 0U, 0U }; // Re-initialize when transitioning to standby mode initStandbyMode(); resetDDInterface(); resetAirTrap(); resetBloodPumpRotorCount(); resetPreLoadStatus(); setVenousBubbleDetectionEnabled( H18_BBLD, FALSE ); setCurrentSubState( NO_SUB_STATE ); // clearNoRetriggerFlag(); // Alarm flag clearCurrentCleaningModeStatus(); // Set user alarm recovery actions allowed in this mode setAlarmUserActionEnabled( ALARM_USER_ACTION_RESUME, FALSE ); setAlarmUserActionEnabled( ALARM_USER_ACTION_RINSEBACK, FALSE ); setAlarmUserActionEnabled( ALARM_USER_ACTION_END_TREATMENT, FALSE ); setStandbyWaitForTreatmentActuators(); // Standby currently supports Start and Wait For Treatment states. // Disinfect/cleaning states are not enabled until the handlers are implemented. flagNoDisinfectRequired = FALSE; doorClosedRequired( FALSE ); currentStandbyState = STANDBY_START_STATE; // Request DD service record and usage information from DD // sendDDServiceRequestToDD(); //ToDo: Service record id not available // broadcastData( MSG_ID_TD_DD_REQUEST_SERVICE_RECORD_FROM_TD, COMM_BUFFER_OUT_CAN_TD_2_DD, requestPayload, sizeof( requestPayload ) ); broadcastData( MSG_ID_TD_DD_USAGE_INFO_REQUEST, COMM_BUFFER_OUT_CAN_TD_2_DD, requestPayload, sizeof( requestPayload ) ); // sendDDUsageInfoRequestToDD(); //TODO need to enable return currentStandbyState; } /*********************************************************************//** * @brief * The execStandbyMode function executes the Standby Mode state machine. * @details \b Inputs: currentStandbyState * @details \b Outputs: currentStandbyState * @return current state (sub-mode) *************************************************************************/ U32 execStandbyMode( void ) { BOOL stop = isStopButtonPressed(); if ( TRUE == stop ) { // Ignore stop button in this mode. } // State machine for standby mode switch ( currentStandbyState ) { case STANDBY_START_STATE: currentStandbyState = handleStandbyModeStartState(); break; case STANDBY_WAIT_FOR_TREATMENT_STATE: currentStandbyState = handleStandbyModeWaitForTreatmentState(); break; // case STANDBY_WAIT_FOR_DISINFECT_STATE: //// currentStandbyState = handleStandbyModeWaitForDisinfectState(); // break; // // case STANDBY_WAIT_FOR_DD_CLEANING_MODE_CMD_RESPONSE_STATE: // currentStandbyState = handleStandbyModeWaitForDDCleaningModeCmdResponseState(); // break; // // case STANDBY_WAIT_FOR_DD_CLEANING_MODE_TO_START_STATE: // currentStandbyState = handleStandbyModeWaitForDDCleaningModeStartState(); // break; // // case STANDBY_CLEANING_MODE_IN_PROGRESS_STATE: // currentStandbyState = handleStandbyModeDDCleaningModeInProgressState(); // break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_STANDBY_INVALID_STATE, currentStandbyState ); currentStandbyState = STANDBY_START_STATE; break; } return currentStandbyState; } /*********************************************************************//** * @brief * The handleStandbyModeStartState function handles the standby start state. * This state waits for the door to be closed and then initiates homing of * pumps and valves and transitions to the wait for treatment state. * @details \b Inputs: * @details \b Outputs: * @return next state of the standby mode state machine *************************************************************************/ static TD_STANDBY_STATE_T handleStandbyModeStartState( void ) { TD_STANDBY_STATE_T state = STANDBY_START_STATE; // If we haven't already initiated homing of actuators, initiate now if ( homingInitiated != TRUE ) { VALVE_T valve; // Home pumps and valves for ( valve = H1_VALV; valve < NUM_OF_VALVES; ++valve ) { homeValve( valve, VALVE_NO_FORCE_HOME, VALVE_CARTRIDGE_MAY_BE_PRESENT ); } if ( FALSE == isSyringePumpHome() ) { retractSyringePump(); } homingInitiated = TRUE; } else { // If homing has been initiated, wait for syringe pump to home and the verify force sensor calibration if ( ( TRUE == isSyringePumpHome() ) && ( TRUE == isSyringePumpStopped() ) && ( VALVE_POSITION_A_INSERT_EJECT == getValvePosition( H1_VALV ) ) && ( VALVE_POSITION_A_INSERT_EJECT == getValvePosition( H19_VALV ) ) ) { syringePumpVerifyForceSensorDACCalibration(); homingInitiated = FALSE; // reset for next time setStandbyWaitForTreatmentActuators(); state = STANDBY_WAIT_FOR_TREATMENT_STATE; // Go to wait for treatment state after above check } } return state; } /*********************************************************************//** * @brief * The handleStandbyModeWaitForTreatmentState function handles wait for * treatment state. * @details \b Inputs: treatStartReqReceived * @details \b Outputs: treatStartReqReceived * @return next state of the standby mode state machine *************************************************************************/ static TD_STANDBY_STATE_T handleStandbyModeWaitForTreatmentState( void ) { TD_STANDBY_STATE_T state = STANDBY_WAIT_FOR_TREATMENT_STATE; DD_OP_MODE_T ddOperationMode = getDDOpMode(); F32 bicarbConvFactor = BICARBONATE_CONVERSION_FACTOR; // switch ( ddOperationMode ) // { // case DD_MODE_GENE: // // If DD is in idle generation state while we are in standby mode, transition DD to standby too // cmdStopDD(); // break; // // // If DD is any of the cleaning modes, set the TD standby to be in the corresponding cleaning mode // case DD_MODE_HEAT: // case DD_MODE_HCOL: // case DD_MODE_ROPS: // setRequestedCleaningMode( ddOperationMode ); // state = STANDBY_WAIT_FOR_DD_CLEANING_MODE_TO_START_STATE; // // DD cleaning mode handling is not enabled yet. // // Stay in Wait For Treatment until DD returns to a supported standby state. // break; // // default: // // Do nothing. There are other DD modes that TD standby does not need to act upon them. // break; // } // If DD is communicating and we don't yet have DD version info, request it if ( TRUE == isDDCommunicating() ) { if ( FALSE == getDDCompatibility()) { U08*fwbuf = NULL; sendMessage( MSG_ID_FW_VERSIONS_REQUEST, COMM_BUFFER_OUT_CAN_TD_2_DD, (U08*)(&fwbuf), 3 ); } } // If treatment start is requested by user, initiate treatment workflow (transition to treatment params mode). if ( TRUE == treatStartReqReceived ) { PRESSURE_LIMIT_CHANGE_RESPONSE_T respRecord = { TRUE, REQUEST_REJECT_REASON_NONE, 0, 0, 0, 0 }; // Initialize treatment modes before starting a new treatment initPreTreatmentMode(); initTreatmentMode(); initPostTreatmentMode(); resetAirTrap(); // Send UI default pressure settings since user is not asked to set them. respRecord.artPresLimitWindowmmHg = getSysConfigTreatmentParameterU32DefaultValue( TREATMENT_PARAM_ART_PRES_LIMIT_WINDOW ); respRecord.venPresLimitWindowmmHg = getSysConfigTreatmentParameterU32DefaultValue( TREATMENT_PARAM_VEN_PRES_LIMIT_WINDOW ); respRecord.venPresLimitAsymmetricmmHg = getSysConfigTreatmentParameterU32DefaultValue( TREATMENT_PARAM_VEN_PRES_LIMIT_ASYMMETRIC ); respRecord.tmpPresLimitWindowmmHg = getSysConfigTreatmentParameterU32DefaultValue( TREATMENT_PARAM_TMP_PRES_LIMIT_WINDOW ); sendPressureLimitsChangeResponse( &respRecord ); // start DD pre-gen // TODO cmdStartPreGenerateDialysate( (F32)getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), getTreatmentParameterF32( TREATMENT_PARAM_DIALYSATE_TEMPERATURE ), getTreatmentParameterF32( TREATMENT_PARAM_ACID_CONCENTRATE_CONV_FACTOR ), bicarbConvFactor, getTreatmentParameterU32( TREATMENT_PARAM_SODIUM ), getTreatmentParameterU32( TREATMENT_PARAM_BICARBONATE ) ); // Start treatment workflow with pretreatment mode requestNewOperationMode( MODE_PRET ); treatStartReqReceived = FALSE; } return state; } /*********************************************************************//** * @brief * The setStandbyWaitForTreatmentActuators function sets TD actuators to * the required Standby: Wait For Treatment state. * @details \b Inputs: none * @details \b Outputs: TD actuators set to standby state. * @return none *************************************************************************/ static void setStandbyWaitForTreatmentActuators( void ) { // Pumps should be off. signalBloodPumpHardStop(); stopSyringePump(); // Set air trap valves to closed position. set3WayValveState( H13_VALV, VALVE_3WAY_COMMON_TO_CLOSED_STATE ); set3WayValveState( H20_VALV, VALVE_3WAY_COMMON_TO_CLOSED_STATE ); // Set pinch valves to load / insert-eject position. setValvePosition( H1_VALV, VALVE_POSITION_A_INSERT_EJECT ); setValvePosition( H19_VALV, VALVE_POSITION_A_INSERT_EJECT ); // TODO: Add remaining Standby actuator settings when existing control // functions are confirmed: // H12 Air Pump Off // H5 Ejector Off // Dialyzer Bypassed // Qd 0 // Quf 0 // Qs 0 } /*********************************************************************//** * @brief * The signalUserInitiateTreatment function handles user initiation of a * treatment. * @details \b Inputs: none * @details \b Outputs: treatStartReqReceived * @param message initiate/reject treatment workflow message from UI which * includes the command code (0=cancel, 1=initiate). * @return TRUE if signal accepted, FALSE if not *************************************************************************/ BOOL signalUserInitiateTreatment( MESSAGE_T *message ) { BOOL result = FALSE; U32 cmd = 0; TD_OP_MODE_T mode = getCurrentOperationMode(); REQUEST_REJECT_REASON_CODE_T rejReason = REQUEST_REJECT_REASON_NONE; UI_RESPONSE_PAYLOAD_T response; memset( &response, 0, sizeof( UI_RESPONSE_PAYLOAD_T ) ); // Verify message payload length is valid. if ( sizeof( U32 ) == message->hdr.payloadLen ) { memcpy( &cmd, message->payload, sizeof( U32 ) ); if ( USER_COMMAND_INITIATE == cmd ) { // Verify TD is in Standby mode and waiting for treatment start request. if ( ( MODE_STAN != mode ) || ( STANDBY_WAIT_FOR_TREATMENT_STATE != currentStandbyState ) ) { rejReason = REQUEST_REJECT_REASON_NOT_ALLOWED_IN_CURRENT_MODE; } #ifndef TEST_UI_ONLY // Verify DD is communicating. else if ( TRUE != isDDCommunicating() ) { rejReason = REQUEST_REJECT_REASON_DD_COMM_LOST; } // Verify DD is ready and not busy with flush/disinfect/cleaning/generation. else if ( ( DD_MODE_STAN != getDDOpMode() ) || ( DD_STANDBY_MODE_STATE_IDLE != getDDSubMode() ) ) { rejReason = REQUEST_REJECT_REASON_DD_BUSY; } else if ( FALSE == getDDCompatibility() ) { rejReason = REQUEST_REJECT_REASON_DD_INCOMPATIBLE; } // ToDo: Need to uncomment below after implementation // else if ( TRUE == isDDDisinfectionOverdue() ) // { // rejReason = REQUEST_REJECT_REASON_DISINFECT_HAS_BEEN_EXPIRED; // } // else if ( TRUE == isDDFlushOverdue() ) // { // rejReason = REQUEST_REJECT_REASON_FILTER_FLUSH_HAS_BEEN_EXPIRED; // } // else if ( TRUE == isDDTemperatureTooHigh() ) // { // rejReason = REQUEST_REJECT_REASON_DD_TEMPERATURE_OUT_OF_RANGE; // } // else if ( TRUE == isDDServiceOverdue() ) // { // rejReason = REQUEST_REJECT_REASON_DD_SERVICE_IS_DUE; // } // else if ( TRUE == isTDServiceOverdue() ) // { // rejReason = REQUEST_REJECT_REASON_TD_SERVICE_IS_DUE; // } // else if ( FALSE == isFPStandbymode() ) // { // rejReason = REQUEST_REJECT_REASON_FP_BUSY; // } // else if ( TRUE == isfpServiceOverdue() ) // { // rejReason = REQUEST_REJECT_REASON_FP_SERVICE_IS_DUE; // } #endif else { // Low battery is a warning only, not a rejection. //ToDo // if ( TRUE == isBatteryRemainingCapacityLessThan60Wh() ) // { // SET_ALARM( ALARM_ID_TD_LOW_BATTERY_CHARGE ); // } // If request to start treatment not rejected, set flag to initiate treatment workflow. result = TRUE; treatStartReqReceived = TRUE; } } else if ( USER_COMMAND_CANCEL == cmd ) { //Cancel is not currently supported here. //Keep rejected unless signalUserCancelTreatment() is implemented/enabled. rejReason = REQUEST_REJECT_REASON_NOT_ALLOWED_IN_CURRENT_MODE; } else { rejReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; } } else { rejReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; } // Respond to request to start treatment. response.accepted = result; response.rejectionReason = rejReason; sendMessage( MSG_ID_TD_RESP_INITIATE_TREATMENT_WORKFLOW, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08*) &response, sizeof( UI_RESPONSE_PAYLOAD_T ) ); return result; } /*********************************************************************//** * @brief * The signalAlarmActionToStandbyMode function executes the given alarm action * as appropriate while in Standby Mode. * @details \b Inputs: none * @details \b Outputs: given alarm action executed * @param action ID of alarm action to execute * @return none *************************************************************************/ void signalAlarmActionToStandbyMode( ALARM_ACTION_T action ) { switch ( action ) { case ALARM_ACTION_STOP: if ( isAlarmActive( ALARM_ID_TD_VENOUS_BUBBLE_DETECTED ) != TRUE ) { // no stop action in standby mode } // if Dialin enabled bubble detection, stop on venous bubble detection alarm else { // Pumps should be off signalBloodPumpHardStop(); stopSyringePump(); // Set valves to safe positions set3WayValveState( H13_VALV, VALVE_3WAY_COMMON_TO_CLOSED_STATE ); set3WayValveState( H20_VALV, VALVE_3WAY_COMMON_TO_CLOSED_STATE ); setValvePosition( H1_VALV, VALVE_POSITION_C_CLOSE ); setValvePosition( H19_VALV, VALVE_POSITION_C_CLOSE ); } break; default: // do not handle other actions in standby mode break; } } /*********************************************************************//** * @brief * The clearCurrentCleaningModeStatus function clears the DG cleaning mode * variables. * @details \b Inputs: none * @details \b Outputs: currentDGCleaningMode * @return none *************************************************************************/ static void clearCurrentCleaningModeStatus( void ) { currentDDCleaningMode.startCleaningMode = FALSE; currentDDCleaningMode.alarmID = ALARM_ID_NO_ALARM; currentDDCleaningMode.startRequestCmdID = DD_CMD_NONE; currentDDCleaningMode.ddOpMode = DD_MODE_FAUL; currentDDCleaningMode.sampleRqstTrgrd = FALSE; currentDDCleaningMode.sampleRequestID = GENERIC_CONFIRM_ID_NONE; currentDDCleaningMode.stopRequestCmdID = GENERIC_CONFIRM_ID_NONE; } /*********************************************************************//** * @brief * The handleStandbyModeWaitForDDCleaningModeStartState function handles * the standby mode wait for DD cleaning mode start state. * @details Inputs: currentDDCleaningMode * @details Outputs: none * @return next state of the standby mode state machine *************************************************************************/ static TD_STANDBY_STATE_T handleStandbyModeWaitForDDCleaningModeStartState( void ) { TD_STANDBY_STATE_T state = STANDBY_WAIT_FOR_DD_CLEANING_MODE_TO_START_STATE; if ( currentDDCleaningMode.ddOpMode == getDDOpMode() ) { state = STANDBY_CLEANING_MODE_IN_PROGRESS_STATE; activateAlarmNoData( currentDDCleaningMode.alarmID ); } return state; } /*********************************************************************//** * @brief * The handleStandbyModeDDCleaningModeInProgressState function handles * the standby mode DD cleaning mode in progress state. * @details \b Inputs: currentDDCleaningMode * @details \b Outputs: none * @return next state of the standby mode state machine *************************************************************************/ static TD_STANDBY_STATE_T handleStandbyModeDDCleaningModeInProgressState( void ) { TD_STANDBY_STATE_T state = STANDBY_CLEANING_MODE_IN_PROGRESS_STATE; if ( DD_MODE_CHFL == currentDDCleaningMode.ddOpMode ) { handleChemFlushSampleCollection(); } else if ( DD_MODE_ROPS == currentDDCleaningMode.ddOpMode ) { handleROPermeateSampleCollection(); } if ( getDDOpMode() != currentDDCleaningMode.ddOpMode ) { state = STANDBY_WAIT_FOR_TREATMENT_STATE; clearAlarm( currentDDCleaningMode.alarmID ); // In case alarm 306 has been triggered, and it was not cleared, clear it upon exiting the disinfection mode. clearAlarm( ALARM_ID_DD_TURN_OFF_INLET_WATER_VALVES ); clearCurrentCleaningModeStatus(); } else { // If we are in the cleaning modes and the corresponding placeholder alarm is not active, reactivate it. if ( FALSE == isAlarmActive( currentDDCleaningMode.alarmID ) ) { activateAlarmNoData( currentDDCleaningMode.alarmID ); } } return state; } /*********************************************************************//** * @brief * The handleChemFlushSampleCollection function handles the chemical disinfect * flush mode's sample collection. In this state of the chemical disinfect * flush mode, user interaction is needed. * @details \b Inputs: currentDDCleaningMode * @details \b Outputs: currentDDCleaningMode * @return none *************************************************************************/ static void handleChemFlushSampleCollection( void ) { U08 *payloadPtr = NULL; if ( ( FALSE == currentDDCleaningMode.sampleRqstTrgrd ) && ( TRUE == isAlarmActive( ALARM_ID_DD_CHEM_DISINFECT_FLUSH_FLUSH_SAMPLE ) ) ) { // Check if the flush sample alarm has been raised for the first time in the sample flush state currentDDCleaningMode.sampleRqstTrgrd = TRUE; } else if ( ( TRUE == currentDDCleaningMode.sampleRqstTrgrd ) && ( FALSE == isAlarmActive( ALARM_ID_DD_CHEM_DISINFECT_FLUSH_FLUSH_SAMPLE ) ) ) { GENERIC_CONFIRMATION_REQUEST_T genericConfRequest; // Sample flush alarm has been triggered and the user has cleared the alarm by pressing Ok. The user is collecting sample. // Send the notification to the UI to prompt the pass/fail screen so the user can choose whether the sampling after flush passed or failed currentDDCleaningMode.sampleRqstTrgrd = FALSE; genericConfRequest.requestID = (U32)GENERIC_CONFIRM_ID_DISINFECT_CHEM_FLUSH_SAMPLE_PASS_FAIL; genericConfRequest.requestType = (U32)GENERIC_CONFIRM_CMD_REQUEST_OPEN; genericConfRequest.rejectReason = 0; genericConfRequest.genericPayload1 = 0.0F; genericConfRequest.genericPayload2 = 0.0F; genericConfRequest.genericPayload3 = 0.0F; genericConfRequest.genericPayload4 = 0.0F; // currentDDCleaningMode.sampleRequestID = addConfirmationRequest( &genericConfRequest ); //ToDo } if ( currentDDCleaningMode.sampleRequestID != GENERIC_CONFIRM_ID_NONE ) { // There is a user confirm CONFIRMATION_REQUEST_STATUS_T status = CONFIRMATION_REQUEST_STATUS_ACCEPTED; //getConfirmationRequestStatus( currentDDCleaningMode.sampleRequestID, 0.0F, 0.0F, 0.0F, 0.0F ); //Todo U32 sampleStatus = 0; switch( status ) { // If the request status is accepted send a 1 to DG case CONFIRMATION_REQUEST_STATUS_ACCEPTED: sampleStatus = (U32)CONFIRMATION_REQUEST_STATUS_ACCEPTED; currentDDCleaningMode.sampleRequestID = GENERIC_CONFIRM_ID_NONE; memcpy( payloadPtr, &sampleStatus, sizeof( U32 ) ); broadcastData( MSG_ID_TD_SEND_CHEM_FLUSH_SAMPLE_PASS_FAIL_TO_DD, COMM_BUFFER_OUT_CAN_TD_2_DD, (U08*) &payloadPtr, 3 ); // handleSendChemFlushPassFailToDD( sampleStatus ); break; // If the request timed out or rejected, it is 0 or failure to DG case CONFIRMATION_REQUEST_STATUS_TIMEOUT: case CONFIRMATION_REQUEST_STATUS_REJECTED: memcpy( payloadPtr, &sampleStatus, sizeof( U32 ) ); broadcastData( MSG_ID_TD_SEND_CHEM_FLUSH_SAMPLE_PASS_FAIL_TO_DD, COMM_BUFFER_OUT_CAN_TD_2_DD, (U08*) &payloadPtr, 3 ); currentDDCleaningMode.sampleRequestID = GENERIC_CONFIRM_ID_NONE; // handleSendChemFlushPassFailToDD( sampleStatus ); break; case CONFIRMATION_REQUEST_STATUS_PENDING: case CONFIRMATION_REQUEST_STATUS_UNUSED: default: // Nothing to do break; } } } /*********************************************************************//** * @brief * The handleROPermeateSampleCollection function handles the RO permeate * sample collection with the user * @details \b Inputs: currentDDCleaningMode * @details \b Outputs: currentDDCleaningMode * @return none *************************************************************************/ static void handleROPermeateSampleCollection( void ) { UI_OFF_BUTTON_PAYLOAD_T cmd; if ( ( FALSE == currentDDCleaningMode.sampleRqstTrgrd ) && ( TRUE == isAlarmActive( ALARM_ID_DD_RO_PERMEATE_SAMPLE_REMOVE_DIA_CAP ) ) ) { // Check if the flush sample alarm has been raised for the first time in the sample flush state currentDDCleaningMode.sampleRqstTrgrd = TRUE; } else if ( ( TRUE == currentDDCleaningMode.sampleRqstTrgrd ) && ( FALSE == isAlarmActive( ALARM_ID_DD_RO_PERMEATE_SAMPLE_REMOVE_DIA_CAP ) ) ) { GENERIC_CONFIRMATION_REQUEST_T genericConfRequest; // Sample flush alarm has been triggered and the user has cleared the alarm by pressing Ok. The user is collecting sample. // Send the notification to the UI to prompt the pass/fail screen so the user can choose whether the sampling after flush passed or failed currentDDCleaningMode.sampleRqstTrgrd = FALSE; genericConfRequest.requestID = (U32)GENERIC_CONFIRM_ID_RO_PERMEATE_SAMPLE_STOP_OR_DISPENSE; genericConfRequest.requestType = (U32)GENERIC_CONFIRM_CMD_REQUEST_OPEN; genericConfRequest.rejectReason = 0; genericConfRequest.genericPayload1 = 0.0F; genericConfRequest.genericPayload2 = 0.0F; genericConfRequest.genericPayload3 = 0.0F; genericConfRequest.genericPayload4 = 0.0F; // currentDDCleaningMode.sampleRequestID = addConfirmationRequest( &genericConfRequest ); } if ( currentDDCleaningMode.sampleRequestID != GENERIC_CONFIRM_ID_NONE ) { // There is a user confirm CONFIRMATION_REQUEST_STATUS_T status = CONFIRMATION_REQUEST_STATUS_ACCEPTED; //getConfirmationRequestStatus( currentDDCleaningMode.sampleRequestID, 0.0F, 0.0F, 0.0F, 0.0F ); cmd.id = GENERIC_CONFIRM_ID_DISINFECT_STOP_RO_PERMEATE_SAMPLE; switch( status ) { // If the request status is accepted send a 1 to DG case CONFIRMATION_REQUEST_STATUS_ACCEPTED: cmd.command = GENERIC_CONFIRM_CMD_ACCEPT_CLOSE; cmd.reason = REQUEST_REJECT_REASON_NONE; sendMessage( MSG_ID_TD_SEND_RO_PERMEATE_SAMPLE_DISPENSE_REQUEST_TO_DD, COMM_BUFFER_OUT_CAN_TD_2_DD, (U08 *)&cmd, sizeof( UI_OFF_BUTTON_PAYLOAD_T ) ); currentDDCleaningMode.sampleRequestID = GENERIC_CONFIRM_ID_NONE; break; // If the request timed out or rejected, it is 0 or failure to DG case CONFIRMATION_REQUEST_STATUS_TIMEOUT: cmd.command = GENERIC_CONFIRM_CMD_TIMEOUT_CLOSE; cmd.reason = REQUEST_REJECT_REASON_NONE; sendMessage( MSG_ID_TD_SEND_RO_PERMEATE_SAMPLE_DISPENSE_REQUEST_TO_DD, COMM_BUFFER_OUT_CAN_TD_2_DD, (U08 *)&cmd, sizeof( UI_OFF_BUTTON_PAYLOAD_T ) ); currentDDCleaningMode.sampleRequestID = GENERIC_CONFIRM_ID_NONE; break; case CONFIRMATION_REQUEST_STATUS_REJECTED: cmd.command = GENERIC_CONFIRM_CMD_REJECT; cmd.reason = REQUEST_REJECT_REASON_NONE; sendMessage( MSG_ID_TD_SEND_RO_PERMEATE_SAMPLE_DISPENSE_REQUEST_TO_DD, COMM_BUFFER_OUT_CAN_TD_2_DD, (U08 *)&cmd, sizeof( UI_OFF_BUTTON_PAYLOAD_T ) ); currentDDCleaningMode.sampleRequestID = GENERIC_CONFIRM_ID_NONE; break; case CONFIRMATION_REQUEST_STATUS_PENDING: case CONFIRMATION_REQUEST_STATUS_UNUSED: default: // Nothing to do break; } } } /*********************************************************************//** * @brief * The handleStandbyModeWaitForDDCleaningModeCmdResponseState function handles * the standby mode wait for DD cleaning mode command response state. * @details \b Inputs: currentDDCleaningMode * @details \b Outputs: currentDDCleaningMode * @return next state of the standby mode state machine *************************************************************************/ static TD_STANDBY_STATE_T handleStandbyModeWaitForDDCleaningModeCmdResponseState( void ) { DD_CMD_RESPONSE_T ddCmdResp; TD_STANDBY_STATE_T state = STANDBY_WAIT_FOR_DD_CLEANING_MODE_CMD_RESPONSE_STATE; UI_OFF_BUTTON_PAYLOAD_T cmd; if ( TRUE == getDDCommandResponse( currentDDCleaningMode.startRequestCmdID, &ddCmdResp ) ) { // Assume the command will be rejected and it goes back to wait for disinfect command state = STANDBY_WAIT_FOR_DISINFECT_STATE; currentDDCleaningMode.startCleaningMode = FALSE; if ( DD_CMD_REQUEST_REJECT_REASON_NONE == ddCmdResp.rejectCode ) { state = STANDBY_WAIT_FOR_DD_CLEANING_MODE_TO_START_STATE; cmd.command = GENERIC_CONFIRM_CMD_ACCEPT_CLOSE; } else { cmd.command = GENERIC_CONFIRM_CMD_REJECT; } cmd.reason = ddCmdResp.rejectCode; cmd.id = GENERIC_CONFIRM_ID_DISINFECT_STOP_WATERFLUSH; sendMessage( MSG_ID_TD_DISINFECT_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08 *)&cmd, sizeof( UI_OFF_BUTTON_PAYLOAD_T ) ); } return state; } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /**@}*/