/************************************************************************** * * Copyright (c) 2025-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 ModePostTreat.h * * @author (last) Praneeth Bunne * @date (last) 13-Apr-2026 * * @author (original) Praneeth Bunne * @date (original) 13-Apr-2026 * ***************************************************************************/ #include "BloodFlow.h" #include "Buttons.h" #include "Ejector.h" #include "Messaging.h" #include "ModePostTreat.h" #include "OperationModes.h" #include "PeristalticPump.h" #include "TaskGeneral.h" #include "TDDefs.h" /** * @addtogroup TDPostTreatmentMode * @{ */ // ********** private definitions ********** ///< Auto eject timeout interval (ms/task time) #define AUTO_EJECT_OPERATION_TIMEOUT_INTERVAL ( ( 10 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Blood pump flow rate (mL/min) for the ejecting operation #define AUTO_EJECT_BLOOD_FLOW_RATE_ML_MIN 100U // ********** private data ********** static BOOL autoEjectReqReceived; ///< Flag indicating that user confirmed to eject tubeset static U32 autoEjectTimerCounter; ///< Timer counter shared across all auto-eject sub-states static TD_POST_TREATMENT_STATE_T currentPostTreatmentState; ///< Current Post-Treatment sub-state static POST_TX_AUTO_EJECT_STATE_T currentPostTxAutoEjectState; ///< Current Post-Treatment Auto Eject sub-state // ********** private function prototypes ********** static void setPostTreatStateTransition( TD_POST_TREATMENT_STATE_T state ); static TD_POST_TREATMENT_STATE_T handlePatientDisconnectionState( void ); static TD_POST_TREATMENT_STATE_T handleAutoEjectState( void ); static TD_POST_TREATMENT_STATE_T handleDisposableRemovalState(void ); static TD_POST_TREATMENT_STATE_T handleVerifyState( void ); static POST_TX_AUTO_EJECT_STATE_T handleAutoEjectAwaitConfirmState( void ); static POST_TX_AUTO_EJECT_STATE_T handleAutoEjectHomingState( void ); static POST_TX_AUTO_EJECT_STATE_T handleAutoEjectExtendingEjectorState( void ); static POST_TX_AUTO_EJECT_STATE_T handleAutoEjectEjectingState( void ); static POST_TX_AUTO_EJECT_STATE_T handleAutoEjectRetractingEjectorState( void ); /*********************************************************************//** * @brief * The initPostTreatmentMode function initializes the Post-Treatment mode. * @details Inputs: none * @details Outputs: Resets all Post-Treatment sub-state variables. * @return none **************************************************************************/ void initPostTreatmentMode( void ) { currentPostTreatmentState = TD_POST_TREATMENT_AUTO_EJECT_STATE; currentPostTxAutoEjectState = POST_TX_AUTO_EJECT_STATE_AWAIT_CONFIRMATION; autoEjectReqReceived = FALSE; autoEjectTimerCounter = 0; setPostTreatStateTransition( currentPostTreatmentState ); } /*********************************************************************//** * @brief * The transitionToPostTreatmentMode function prepares the system for * entry into Post-Treatment mode. * @details Inputs: none * @details Outputs: Initializes mode specific state and returns the starting * Post-Treatment sub-state. * @return Initial Post-Treatment sub-state **************************************************************************/ U32 transitionToPostTreatmentMode( void ) { initPostTreatmentMode(); return (U32)currentPostTreatmentState; } /*********************************************************************//** * @brief * The setPostTreatStateTransition function sets the actuators and variables * for the state transition in Post-Treatment mode. * @details Inputs: Valve states, Pump speed * @details Outputs: Actuate valves, pumps as desired * @Param state Post-Treatment state enum * @return none **************************************************************************/ static void setPostTreatStateTransition( TD_POST_TREATMENT_STATE_T state ) { switch( state ) { case TD_POST_TREATMENT_PATIENT_DISCONNECTION_STATE: //TODO: actuator configuration; break; case TD_POST_TREATMENT_AUTO_EJECT_STATE: signalBloodPumpHardStop(); break; case TD_POST_TREATMENT_DISPOSABLE_REMOVAL_STATE: //TODO: actuator configuration; break; case TD_POST_TREATMENT_VERIFY_STATE: //TODO: actuator configuration; break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_POST_TREATMENT_INVALID_STATE1, currentPostTreatmentState ); break; } } /*********************************************************************//** * @brief * The execPostTreatmentMode function executes the Post-Treatment * mode state machine. * @details Inputs: stop button status and system conditions via helpers. * @details Outputs: Advances the Post-Treatment sub-state * @return current Post-Treatment sub-state. *************************************************************************/ U32 execPostTreatmentMode( void ) { BOOL stop = isStopButtonPressed(); TD_POST_TREATMENT_STATE_T prevPostTreatmentState = currentPostTreatmentState; // Execute mode state machine switch ( currentPostTreatmentState ) { case TD_POST_TREATMENT_PATIENT_DISCONNECTION_STATE: //currentPostTreatmentState = handlePatientDisconnectionState(); break; case TD_POST_TREATMENT_AUTO_EJECT_STATE: currentPostTreatmentState = handleAutoEjectState(); break; case TD_POST_TREATMENT_DISPOSABLE_REMOVAL_STATE: //currentPostTreatmentState = handleDisposableRemovalState(); break; case TD_POST_TREATMENT_VERIFY_STATE: //currentPostTreatmentState = handleVerifyState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_POST_TREATMENT_INVALID_STATE, currentPostTreatmentState ); break; } if ( prevPostTreatmentState != currentPostTreatmentState) { setPostTreatStateTransition( currentPostTreatmentState ); } return (U32)currentPostTreatmentState; } /*********************************************************************//** * @brief * The handlePatientDisconnectionState function executes the Post-Treatment * mode Patient Disconnection state machine. * @details Inputs: TODO fill up if any * @details Outputs: TODO fill up if any * @return next post-treatment mode state *************************************************************************/ static TD_POST_TREATMENT_STATE_T handlePatientDisconnectionState( void ) { TD_POST_TREATMENT_STATE_T state = TD_POST_TREATMENT_PATIENT_DISCONNECTION_STATE; // TODO: Transition to Auto Eject state on completion when implemented // state = TD_POST_TREATMENT_AUTO_EJECT_STATE; return state; } /*********************************************************************//** * @brief * The handleAutoEjectState function executes the Post-Treatment * mode Auto Eject state machine. * @details Inputs: currentPostTxAutoEjectState * @details Outputs: Advances the Post-Treatment Auto Eject sub-state * and next Post-Treatment top-level state when eject is complete. * @return next post-treatment mode state *************************************************************************/ static TD_POST_TREATMENT_STATE_T handleAutoEjectState( void ) { TD_POST_TREATMENT_STATE_T state = TD_POST_TREATMENT_AUTO_EJECT_STATE; switch ( currentPostTxAutoEjectState ) { case POST_TX_AUTO_EJECT_STATE_AWAIT_CONFIRMATION: currentPostTxAutoEjectState = handleAutoEjectAwaitConfirmState(); break; case POST_TX_AUTO_EJECT_STATE_HOMING: currentPostTxAutoEjectState = handleAutoEjectHomingState(); break; case POST_TX_AUTO_EJECT_STATE_EXTENDING_EJECTOR: currentPostTxAutoEjectState = handleAutoEjectExtendingEjectorState(); break; case POST_TX_AUTO_EJECT_STATE_EJECTING: currentPostTxAutoEjectState = handleAutoEjectEjectingState(); break; case POST_TX_AUTO_EJECT_STATE_RETRACTING_EJECTOR: currentPostTxAutoEjectState = handleAutoEjectRetractingEjectorState(); if ( NUM_OF_POST_TX_AUTO_EJECT_SUB_STATES == currentPostTxAutoEjectState ) { state = TD_POST_TREATMENT_DISPOSABLE_REMOVAL_STATE; } break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_POST_TX_AUTO_EJECT_INVALID_STATE, (U32)currentPostTxAutoEjectState ); break; } return state; } /*********************************************************************//** * @brief * The handleDisposableRemovalState function executes the Post-Treatment * mode Disposable Removal state machine. * @details Inputs: TODO fill up if any * @details Outputs: TODO fill up if any * @return next post-treatment mode state *************************************************************************/ static TD_POST_TREATMENT_STATE_T handleDisposableRemovalState( void ) { TD_POST_TREATMENT_STATE_T state = TD_POST_TREATMENT_DISPOSABLE_REMOVAL_STATE; // TODO: Transition to Verify state on completion when implemented // state = TD_POST_TREATMENT_VERIFY_STATE; return state; } /*********************************************************************//** * @brief * The handleVerifyState function executes the Post-Treatment * mode Verify state machine. * @details Inputs: TODO fill up if any * @details Outputs: TODO fill up if any * @return next post-treatment mode state *************************************************************************/ static TD_POST_TREATMENT_STATE_T handleVerifyState( void ) { TD_POST_TREATMENT_STATE_T state = TD_POST_TREATMENT_VERIFY_STATE; // TODO return state; } /*********************************************************************//** * @brief * The handleAutoEjectAwaitConfirmState function handles the Await confirm * sub-state of the Post-Treatment Auto-Eject state machine. * Waits for the user request to auto-eject * @details Inputs: autoEjectReqReceived * @details Outputs: autoEjectReqReceived * @return next Auto-Eject sub-state *************************************************************************/ static POST_TX_AUTO_EJECT_STATE_T handleAutoEjectAwaitConfirmState( void ) { POST_TX_AUTO_EJECT_STATE_T subState = POST_TX_AUTO_EJECT_STATE_AWAIT_CONFIRMATION; if ( TRUE == autoEjectReqReceived ) { homeBloodPump(); autoEjectTimerCounter = 0; autoEjectReqReceived = FALSE; subState = POST_TX_AUTO_EJECT_STATE_HOMING; } return subState; } /*********************************************************************//** * @brief * The handleAutoEjectHomingState function handles the Homing sub-state * of the Post-Treatment Auto-Eject state machine. * Homes the blood pump (H4) * @details Inputs: autoEjectTimerCounter * @details Outputs: autoEjectTimerCounter * @return next Auto-Eject sub-state *************************************************************************/ static POST_TX_AUTO_EJECT_STATE_T handleAutoEjectHomingState( void ) { POST_TX_AUTO_EJECT_STATE_T subState = POST_TX_AUTO_EJECT_STATE_HOMING; if ( ++autoEjectTimerCounter >= AUTO_EJECT_OPERATION_TIMEOUT_INTERVAL) { signalBloodPumpHardStop(); SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_AUTO_LOAD_EJECT_BP_TIMEOUT, (U32)isPeristalticPumpHome(), autoEjectTimerCounter ); } else if ( TRUE == isPeristalticPumpHome() ) { extendEjector(); autoEjectTimerCounter = 0; subState = POST_TX_AUTO_EJECT_STATE_EXTENDING_EJECTOR; } return subState; } /*********************************************************************//** * @brief * The handleAutoEjectExtendingEjectorState function handles the * Extending Ejector sub-state of the Post-Treatment Auto-Eject * state machine. Extends the ejector pin (H5) to engage the tubeset. * @details Inputs: autoEjectTimerCounter * @details Outputs: autoEjectTimerCounter * @return next Auto-Eject sub-state *************************************************************************/ static POST_TX_AUTO_EJECT_STATE_T handleAutoEjectExtendingEjectorState( void ) { POST_TX_AUTO_EJECT_STATE_T subState = POST_TX_AUTO_EJECT_STATE_EXTENDING_EJECTOR; if ( ++autoEjectTimerCounter >= AUTO_EJECT_OPERATION_TIMEOUT_INTERVAL ) { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_AUTO_EJECT_EJECTOR_TIMEOUT, (U32)getEjectorState(), autoEjectTimerCounter ); } else if ( EJECTOR_STATE_EXTENDED == getEjectorState() ) { setBloodPumpTargetFlowRate( AUTO_EJECT_BLOOD_FLOW_RATE_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); autoEjectTimerCounter = 0; subState = POST_TX_AUTO_EJECT_STATE_EJECTING; } return subState; } /*********************************************************************//** * @brief * The handleAutoEjectEjectingState function handles the Ejecting sub-state * of the Post-Treatment Auto-Eject state machine. Rotates the blood pump (H4) * forward at 100 mL/min with the ejector extended to push the tubeset * out of the rotor. * @details Inputs: autoEjectTimerCounter * @details Outputs: autoEjectTimerCounter * @return next Auto-Eject sub-state *************************************************************************/ static POST_TX_AUTO_EJECT_STATE_T handleAutoEjectEjectingState( void ) { POST_TX_AUTO_EJECT_STATE_T subState = POST_TX_AUTO_EJECT_STATE_EJECTING; if ( ++autoEjectTimerCounter >= AUTO_EJECT_OPERATION_TIMEOUT_INTERVAL ) { signalBloodPumpHardStop(); SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_AUTO_LOAD_EJECT_BP_TIMEOUT, isPeristalticPumpHome(), autoEjectTimerCounter ); } else if ( TRUE == isPeristalticPumpHome() ) { signalBloodPumpHardStop(); retractEjector(); autoEjectTimerCounter = 0; subState = POST_TX_AUTO_EJECT_STATE_RETRACTING_EJECTOR; } return subState; } /*********************************************************************//** * @brief * The handleAutoEjectRetractingEjectorState function handles the * Retracting Ejector sub-state of the Post-Treatment Auto-Eject state * machine. Retracts the ejector pin (H5) after the tubeset has been ejected. * @details Inputs: autoEjectTimerCounter * @details Outputs: autoEjectTimerCounter * @return next Auto-Eject sub-state *************************************************************************/ static POST_TX_AUTO_EJECT_STATE_T handleAutoEjectRetractingEjectorState( void ) { POST_TX_AUTO_EJECT_STATE_T subState = POST_TX_AUTO_EJECT_STATE_RETRACTING_EJECTOR; if ( ++autoEjectTimerCounter >= AUTO_EJECT_OPERATION_TIMEOUT_INTERVAL ) { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_AUTO_EJECT_EJECTOR_TIMEOUT, (U32)getEjectorState(), autoEjectTimerCounter ); } else if ( EJECTOR_STATE_RETRACTED == getEjectorState() ) { autoEjectTimerCounter = 0; subState = NUM_OF_POST_TX_AUTO_EJECT_SUB_STATES; } return subState; } /*********************************************************************//** * @brief * The handleAutoEjectRequest function handles a UI request to remove the * disposable tubeset. * @details Inputs: none * @details Outputs: autoEjectReqReceived * @param message UI message which includes the user confirmation to * eject the tubeset * @return TRUE if confirmation/rejection accepted, FALSE if not *************************************************************************/ BOOL handleAutoEjectRequest( MESSAGE_T *message ) { BOOL result = FALSE; BOOL notInValidState = FALSE; TD_OP_MODE_T mode = getCurrentOperationMode(); UI_RESPONSE_PAYLOAD_T response; REQUEST_REJECT_REASON_CODE_T rejReason = REQUEST_REJECT_REASON_INVALID_PAYLOAD_LENGTH; if ( 0 == message->hdr.payloadLen ) { notInValidState = ( ( ( TD_POST_TREATMENT_AUTO_EJECT_STATE != currentPostTreatmentState ) || ( POST_TX_AUTO_EJECT_STATE_AWAIT_CONFIRMATION != currentPostTxAutoEjectState ) ) ? TRUE : FALSE ); if ( ( mode != MODE_POST ) || ( TRUE == notInValidState ) ) { rejReason = REQUEST_REJECT_REASON_NOT_ALLOWED_IN_CURRENT_MODE; } else { autoEjectReqReceived = TRUE; result = TRUE; rejReason = REQUEST_REJECT_REASON_NONE; } } response.accepted = result; response.rejectionReason = rejReason; sendMessage( MSG_ID_TD_ADJUST_DISPOSABLES_REMOVAL_CONFIRM_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08*)(&response), sizeof( UI_RESPONSE_PAYLOAD_T ) ); return result; } /**@}*/