/************************************************************************** * * 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 "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 autoEjectHomePosCleared; ///< Flag indicating BP rotor has left home position during ejection revolution static BOOL setEntryActuatorCmdIssued; ///< Flag indicates actuator command has been issued on current sub-state entry 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 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 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_HOMING; autoEjectHomePosCleared = FALSE; setEntryActuatorCmdIssued = FALSE; autoEjectTimerCounter = 0; } /*********************************************************************//** * @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(); signalBloodPumpHardStop(); return (U32)currentPostTreatmentState; } /*********************************************************************//** * @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(); if ( TRUE == stop ) { activateAlarmNoData( ALARM_ID_TD_TREATMENT_STOPPED_BY_USER ); } // 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; } return (U32)currentPostTreatmentState; } /*********************************************************************//** * @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 current post-treatment sub-state *************************************************************************/ static TD_POST_TREATMENT_STATE_T handleAutoEjectState( void ) { TD_POST_TREATMENT_STATE_T state = TD_POST_TREATMENT_AUTO_EJECT_STATE; POST_TX_AUTO_EJECT_STATE_T prevAutoEjectSubState = currentPostTxAutoEjectState; switch ( currentPostTxAutoEjectState ) { 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_TREATMENT_INVALID_STATE, (U32)currentPostTxAutoEjectState ); break; } if ( prevAutoEjectSubState != currentPostTxAutoEjectState ) { autoEjectTimerCounter = 0; setEntryActuatorCmdIssued = FALSE; } return state; } /*********************************************************************//** * @brief * The handleAutoEjectHomingState function handles the Homing sub-state * of the Post-Treatment Auto-Eject state machine. * Homes both the blood pump (H4) and ejector (H5) * @details Inputs: setEntryActuatorCmdIssued, autoEjectTimerCounter * @details Outputs: setEntryActuatorCmdIssued, 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; // Issue both homing commands once on state entry if( FALSE == setEntryActuatorCmdIssued ) { homeBloodPump(); homeEjector(); setEntryActuatorCmdIssued = TRUE; } if( ++autoEjectTimerCounter >= AUTO_EJECT_OPERATION_TIMEOUT_INTERVAL) { signalBloodPumpHardStop(); if( TRUE == isPumpHomeInProgress() ) { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_AUTO_LOAD_EJECT_BP_TIMEOUT, (U32)isPeristalticPumpHome(), autoEjectTimerCounter ); } if( EJECTOR_STATE_RETRACTED != getEjectorState() ) { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_AUTO_EJECT_EJECTOR_TIMEOUT, (U32)getEjectorState(), autoEjectTimerCounter ); } requestNewOperationMode( MODE_FAUL); } else { BOOL bpHomed = ( FALSE == isPumpHomeInProgress() ); BOOL ejectorHomed = ( EJECTOR_STATE_RETRACTED == getEjectorState() ); if( ( TRUE == bpHomed ) && ( TRUE == ejectorHomed ) ) { 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: setEntryActuatorCmdIssued, autoEjectTimerCounter * @details Outputs: setEntryActuatorCmdIssued, 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 ( FALSE == setEntryActuatorCmdIssued ) { extendEjector(); setEntryActuatorCmdIssued = TRUE; } if ( ++autoEjectTimerCounter >= AUTO_EJECT_OPERATION_TIMEOUT_INTERVAL ) { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_AUTO_EJECT_EJECTOR_TIMEOUT, (U32)getEjectorState(), autoEjectTimerCounter ); requestNewOperationMode( MODE_FAUL); } else if ( EJECTOR_STATE_EXTENDED == getEjectorState() ) { 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: autoEjectHomePosCleared, autoEjectTimerCounter * @details Outputs: autoEjectHomePosCleared, 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; setBloodPumpTargetFlowRate( AUTO_EJECT_BLOOD_FLOW_RATE_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP); if( ++autoEjectTimerCounter >= AUTO_EJECT_OPERATION_TIMEOUT_INTERVAL ) { signalBloodPumpHardStop(); SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_AUTO_LOAD_EJECT_BP_TIMEOUT, autoEjectHomePosCleared, isPeristalticPumpHome() ); requestNewOperationMode( MODE_FAUL); } else { if( FALSE == autoEjectHomePosCleared ) { if( FALSE == isPeristalticPumpHome() ) { autoEjectHomePosCleared = TRUE; } } else if( TRUE == isPeristalticPumpHome() ) { signalBloodPumpHardStop(); 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: setEntryActuatorCmdIssued, autoEjectTimerCounter * @details Outputs: setEntryActuatorCmdIssued, 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 ( FALSE == setEntryActuatorCmdIssued ) { retractEjector(); setEntryActuatorCmdIssued = TRUE; } if ( ++autoEjectTimerCounter >= AUTO_EJECT_OPERATION_TIMEOUT_INTERVAL ) { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_AUTO_EJECT_EJECTOR_TIMEOUT, (U32)getEjectorState(), autoEjectTimerCounter ); requestNewOperationMode( MODE_FAUL); } else if ( EJECTOR_STATE_RETRACTED == getEjectorState() ) { subState = NUM_OF_POST_TX_AUTO_EJECT_SUB_STATES; } return subState; } /**@}*/