/************************************************************************** * * Copyright (c) 2019-2021 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 TreatmentEnd.c * * @author (last) Sean Nash * @date (last) 04-Feb-2021 * * @author (original) Sean * @date (original) 04-Feb-2021 * ***************************************************************************/ #include "AirTrap.h" #include "BloodFlow.h" #include "DialInFlow.h" #include "DialOutFlow.h" #include "ModeTreatment.h" #include "OperationModes.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "TreatmentEnd.h" #include "Valves.h" /** * @addtogroup TreatmentEnd * @{ */ // ********** private definitiions *********** /// Target flow rate for blood while waiting for user to initiate final rinseback. #define TX_END_BP_FLOW_RATE_ML_MIN 100 /// Max time to wait for user to initiate final rinseback. static const U32 TX_END_TIMEOUT_MS = ( ( 15 * 60 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ); // TODO - get time from Systems /// Maximum time in this mode before blood sitting alarm given (in general task intervals). static const U32 MAX_TIME_BLOOD_SITTING = ( ( 5 * SEC_PER_MIN * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ); /// Maximum time in this mode before blood sitting warning given (in general task intervals). static const U32 WARN_TIME_BLOOD_SITTING = ( ( 4 * SEC_PER_MIN * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ); // ********** private data ********** static TREATMENT_END_STATE_T treatmentEndState; ///< Current state of the treatment end sub-mode. static U32 txEndTimerCtr; ///< Timer counter (in GP task intervals) counts time spent waiting for user to initiate final rinseback. static U32 bloodSittingTimerCtr; ///< Timer counter tracks time in paused state while blood is sitting. static BOOL txEndAlarmResumeRequested; ///< Flag indicates user requesting resume from alarm. static BOOL txEndAlarmRinsebackRequested; ///< Flag indicates user requesting rinseback from alarm. static BOOL txEndAlarmEndTreatmentRequested; ///< Flag indicates user requesting end treatment from alarm. static BOOL txEndRinsebackRequested; ///< Flag indicates user requesting final rinseback. // ********** private function prototypes ********** static void resetTreatmentEndFlags( void ); static void setupForTxEndWait4RinsebackState( void ); static void setupForTxEndPausedState( void ); static TREATMENT_END_STATE_T handleTxEndWait4RinsebackState( void ); static TREATMENT_END_STATE_T handleTxEndPausedState( void ); static BOOL handleTxEndRinsebackUserAction( REQUEST_REJECT_REASON_CODE_T *rejReason ); /*********************************************************************//** * @brief * The initTreatmentEnd function initializes the Treatment End sub-mode * module. * @details Inputs: none * @details Outputs: Treatment End sub-mode module initialized. * @return none *************************************************************************/ void initTreatmentEnd( void ) { treatmentEndState = TREATMENT_END_WAIT_FOR_RINSEBACK_STATE; txEndTimerCtr = 0; bloodSittingTimerCtr = 0; resetTreatmentEndFlags(); } /*********************************************************************//** * @brief * The resetTreatmentEndFlags function resets the treatment end request flags. * @details Inputs: none * @details Outputs: Treatment end request flags reset to FALSE. * @return none *************************************************************************/ static void resetTreatmentEndFlags( void ) { txEndAlarmResumeRequested = FALSE; txEndAlarmRinsebackRequested = FALSE; txEndAlarmEndTreatmentRequested = FALSE; txEndRinsebackRequested = FALSE; } /*********************************************************************//** * @brief * The transitionToTreatmentEnd function prepares for transition to treatment * end sub-mode. * @details Inputs: none * @details Outputs: actuators set for initial state of treatment end sub-mode * @return none *************************************************************************/ void transitionToTreatmentEnd( void ) { initTreatmentEnd(); // Stop any DG fill that may be in progress cmdStopDGFill(); // Set valves setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); setValvePosition( VBA, VALVE_POSITION_B_OPEN ); setValvePosition( VBV, VALVE_POSITION_B_OPEN ); // Ensure all pumps except BP stopped signalDialInPumpHardStop(); signalDialOutPumpHardStop(); stopSyringePump(); setBloodPumpTargetFlowRate( TX_END_BP_FLOW_RATE_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); cmdStopDGTrimmerHeater(); // Continue air trap control startAirTrapControl(); // Set user alarm recovery actions allowed in this sub-mode setAlarmUserActionEnabled( ALARM_USER_ACTION_RESUME, FALSE ); setAlarmUserActionEnabled( ALARM_USER_ACTION_RINSEBACK, TRUE ); setAlarmUserActionEnabled( ALARM_USER_ACTION_END_TREATMENT, TRUE ); } /*********************************************************************//** * @brief * The setupForTxEndWait4RinsebackState function sets actuators appropriately * for treatment end wait for rinseback state. * @details Inputs: none * @details Outputs: arterial and venous lines opened, blood pump started, * and air trap leveling control is started. * @return none *************************************************************************/ static void setupForTxEndWait4RinsebackState( void ) { // Open VBA and VBV valves to allow flow from saline bag and to patient venous line setValvePosition( VBA, VALVE_POSITION_B_OPEN ); setValvePosition( VBV, VALVE_POSITION_B_OPEN ); // Start blood pump at Tx End slow flow rate setBloodPumpTargetFlowRate( TX_END_BP_FLOW_RATE_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); bloodSittingTimerCtr = 0; // Start air trap leveling control startAirTrapControl(); } /*********************************************************************//** * @brief * The setupForTxEndPausedState function sets actuators appropriately * for treatment end paused state. * @details Inputs: none * @details Outputs: Blood pump stopped, arterial and venous lines closed, * and air trap leveling control is stopped. * @return none *************************************************************************/ static void setupForTxEndPausedState( void ) { // Stop blood pump signalBloodPumpHardStop(); // Close arterial and venous lines setValvePosition( VBA, VALVE_POSITION_C_CLOSE ); setValvePosition( VBV, VALVE_POSITION_C_CLOSE ); // Stop air trap leveling control endAirTrapControl(); } /*********************************************************************//** * @brief * The execTreatmentEnd function executes the Treatment End sub-mode * state machine. * @details Inputs: treatmentEndState * @details Outputs: treatmentEndState * @return none *************************************************************************/ void execTreatmentEnd( void ) { txEndTimerCtr++; switch ( treatmentEndState ) { case TREATMENT_END_WAIT_FOR_RINSEBACK_STATE: treatmentEndState = handleTxEndWait4RinsebackState(); break; case TREATMENT_END_PAUSED_STATE: treatmentEndState = handleTxEndPausedState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_TREATMENT_END_INVALID_STATE, treatmentEndState ); break; } // Re-circulate flags should be handled by now - reset in case not handled by current state resetTreatmentEndFlags(); } /*********************************************************************//** * @brief * The handleTxEndWait4RinsebackState function handles the treatment end * wait for rinseback state operations. * @details Inputs: flags * @details Outputs: flags handled * @return next treatment end wait for rinseback state *************************************************************************/ static TREATMENT_END_STATE_T handleTxEndWait4RinsebackState( void ) { TREATMENT_END_STATE_T result = TREATMENT_END_WAIT_FOR_RINSEBACK_STATE; // Is alarm stop or user reconnect requested? if ( TRUE == doesAlarmStatusIndicateStop() ) { setupForTxEndPausedState(); result = TREATMENT_END_PAUSED_STATE; } // Is treatment end requested? else if ( TRUE == txEndAlarmEndTreatmentRequested ) { signalEndTreatment(); } // Is final rinseback requested? else if ( ( TRUE == txEndRinsebackRequested ) || ( TRUE == txEndAlarmRinsebackRequested ) ) { signalGoToRinseback(); } // Has max time waiting for user to initiate final rinseback been exceeded? else if ( txEndTimerCtr > TX_END_TIMEOUT_MS ) { activateAlarmNoData( ALARM_ID_END_TREATMENT_TIMEOUT_ALARM ); } return result; } /*********************************************************************//** * @brief * The handleTxEndPausedState function handles the treatment end paused * state operations. * @details Inputs: flags * @details Outputs: flags handled * @return next Treatment end paused state *************************************************************************/ static TREATMENT_END_STATE_T handleTxEndPausedState( void ) { TREATMENT_END_STATE_T result = TREATMENT_END_PAUSED_STATE; bloodSittingTimerCtr++; // Is final rinseback requested? if ( ( TRUE == txEndRinsebackRequested ) || ( TRUE == txEndAlarmRinsebackRequested ) ) { signalGoToRinseback(); } // Is slow blood flow resume requested? else if ( TRUE == txEndAlarmResumeRequested ) { setupForTxEndWait4RinsebackState(); result = TREATMENT_END_WAIT_FOR_RINSEBACK_STATE; } // Is treatment end requested? else if ( TRUE == txEndAlarmEndTreatmentRequested ) { signalEndTreatment(); } else { // Ensure we do not sit in stopped state for too long if ( bloodSittingTimerCtr > WARN_TIME_BLOOD_SITTING ) { activateAlarmNoData( ALARM_ID_BLOOD_SITTING_WARNING ); } if ( bloodSittingTimerCtr > MAX_TIME_BLOOD_SITTING ) { // Raise the alarm activateAlarmNoData( ALARM_ID_TREATMENT_STOPPED_NO_RINSEBACK ); } } return result; } /*********************************************************************//** * @brief * The signalTreatmentEndAlarmResumeUserAction function signals the treatment end * sub-mode to stop per an active alarm. * @details Inputs: none * @details Outputs: txEndAlarmResumeRequested * @return none *************************************************************************/ void signalTreatmentEndAlarmResumeUserAction( void ) { txEndAlarmResumeRequested = TRUE; } /*********************************************************************//** * @brief * The signalTreatmentEndAlarmRinsebackUserAction function signals the treatment end * sub-mode to stop per an active alarm. * @details Inputs: none * @details Outputs: txEndAlarmRinsebackRequested * @return none *************************************************************************/ void signalTreatmentEndAlarmRinsebackUserAction( void ) { txEndAlarmRinsebackRequested = TRUE; } /*********************************************************************//** * @brief * The signalTreatmentEndAlarmEndTxUserAction function signals the treatment end * sub-mode to stop per an active alarm. * @details Inputs: none * @details Outputs: txEndAlarmEndTreatmentRequested * @return none *************************************************************************/ void signalTreatmentEndAlarmEndTxUserAction( void ) { txEndAlarmEndTreatmentRequested = TRUE; } /*********************************************************************//** * @brief * The signalTreatmentEndUserAction function signals a treatment end user * action has been requested. The request is handled and responded to. * @details Inputs: none * @details Outputs: action handled, request responded to * @param action User action requested * @return none *************************************************************************/ void signalTreatmentEndUserAction( REQUESTED_TREATMENT_END_USER_ACTIONS_T action ) { BOOL accepted = FALSE; REQUEST_REJECT_REASON_CODE_T rejReason = REQUEST_REJECT_REASON_NONE; // Reject user action requests if any alarm is currently active. User must clear alarm first. if ( FALSE == isAnyAlarmActive() ) { switch ( action ) { case REQUESTED_USER_ACTION_TX_END_RINSEBACK_START: accepted = handleTxEndRinsebackUserAction( &rejReason ); break; default: rejReason = REQUEST_REJECT_REASON_INVALID_COMMAND; break; } } else { rejReason = REQUEST_REJECT_REASON_ALARM_IS_ACTIVE; } // Respond to user action request sendTreatmentEndCmdResponse( accepted, (U32)rejReason ); } /*********************************************************************//** * @brief * The handleTxEndRinsebackUserAction function handles a end treatment rinseback * user action request. It is assumed that the calling function will set * the reject reason parameter to None beforehand. * @details Inputs: treatmentEndState * @details Outputs: rinseback action handled * @param rejReason Code indicating reason for rejection * @return TRUE if user action accepted, FALSE if not *************************************************************************/ static BOOL handleTxEndRinsebackUserAction( REQUEST_REJECT_REASON_CODE_T *rejReason ) { BOOL result = FALSE; if ( TREATMENT_END_WAIT_FOR_RINSEBACK_STATE == treatmentEndState ) { result = TRUE; txEndRinsebackRequested = TRUE; } else { *rejReason = REQUEST_REJECT_REASON_ACTION_DISABLED_IN_CURRENT_STATE; } return result; } /*********************************************************************//** * @brief * The getCurrentTreatmentEndState function returns the current state of the * treatment end sub-mode. * @details Inputs: treatmentEndState * @details Outputs: none * @return treatmentEndState *************************************************************************/ TREATMENT_END_STATE_T getCurrentTreatmentEndState( void ) { return treatmentEndState; } /**@}*/