/************************************************************************** * * Copyright (c) 2019-2020 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 TreatmentStop.c * * @author (last) Sean Nash * @date (last) 24-Sep-2020 * * @author (original) Sean * @date (original) 15-Jan-2020 * ***************************************************************************/ #include "AirTrap.h" #include "BloodFlow.h" #include "DGInterface.h" #include "DialInFlow.h" #include "DialOutFlow.h" #include "ModeTreatment.h" #include "OperationModes.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "TreatmentStop.h" #include "Valves.h" /** * @addtogroup TreatmentStop * @{ */ // ********** private definitions ********** /// Maximum time in this mode before blood sitting warning given (in general task intervals). static const U32 MAX_TIME_BLOOD_SITTING = ( ( 5 * SEC_PER_MIN * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ); /// Treatment stop status broadcast interval. static const U32 TREATMENT_STOP_DATA_PUBLISH_INTERVAL = ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ); // ********** private data ********** static TREATMENT_STOP_STATE_T currentTxStopState; ///< Current treatment stop state. static U32 bloodSittingTimerCtr; ///< Timer counter tracks time in this mode while blood is sitting. static U32 stopPublishTimerCtr; ///< Timer counter (in GP task intervals) counts time to next status broadcast. // ********** private function prototypes ********** static TREATMENT_STOP_STATE_T handleTreatmentStopRecircState( void ); static TREATMENT_STOP_STATE_T handleTreatmentStopNoRecircState( void ); static void publishTreatmentStopData( void ); /*********************************************************************//** * @brief * The initTreatmentStop function initializes the Treatment Stop sub-mode * module. * @details Inputs: none * @details Outputs: Treatment Stop sub-mode module initialized. * @return none *************************************************************************/ void initTreatmentStop( void ) { currentTxStopState = TREATMENT_STOP_RECIRC_STATE; bloodSittingTimerCtr = 0; stopPublishTimerCtr = 0; } /*********************************************************************//** * @brief * The transitionToTreatmentStop function prepares for transition to treatment * stop sub-mode. * @details Inputs: none * @details Outputs: none * @return none *************************************************************************/ void transitionToTreatmentStop( void ) { // Set user alarm recovery actions allowed in this sub-mode setAlarmUserActionEnabled( ALARM_USER_ACTION_RESUME, TRUE ); if ( TRUE == getRinsebackCompleted() ) { // block rinseback action if already done setAlarmUserActionEnabled( ALARM_USER_ACTION_RINSEBACK, FALSE ); } else { setAlarmUserActionEnabled( ALARM_USER_ACTION_RINSEBACK, TRUE ); } setAlarmUserActionEnabled( ALARM_USER_ACTION_END_TREATMENT, TRUE ); // Ensure all pumps except DPi stopped signalBloodPumpHardStop(); signalDialOutPumpHardStop(); stopSyringePump(); // Start out assuming we re-circulate dialysate while stopped setDialInPumpTargetFlowRate( DIALYSATE_FLOW_RATE_FOR_RECIRC, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); // Set valves to safe state setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); setValvePosition( VBA, VALVE_POSITION_C_CLOSE ); setValvePosition( VBV, VALVE_POSITION_C_CLOSE ); // Stop air trap control endAirTrapControl(); // Reset saline bolus state in case alarm interrupted one resetSalineBolus(); // Should always have an alarm active in treatment stop sub-mode so that user can take action if ( FALSE == isAnyAlarmActive() ) { if ( TRUE == getRinsebackCompleted() ) { activateAlarmNoData( ALARM_ID_TREATMENT_STOPPED_AFTER_RINSEBACK ); // No escalation after rinseback because no blood in blood line } else { //activateAlarmNoData( ALARM_ID_TREATMENT_STOPPED_BY_USER ); } // coming back to stop state via non-alarm path, so no audio - just want alarm for its options signalAlarmSilence( ALARM_SILENCE_CMD_CANCEL ); } } /*********************************************************************//** * @brief * The execTreatmentStop function executes the Treatment Stop sub-mode * state machine. * @details Inputs: none * @details Outputs: none * @return none *************************************************************************/ void execTreatmentStop( void ) { // Ensure we do not sit in stopped state for too long if ( ++bloodSittingTimerCtr > MAX_TIME_BLOOD_SITTING ) { activateAlarmNoData( ALARM_ID_TREATMENT_STOPPED_NO_RINSEBACK ); } // Execute treatment stop sub-mode state machine switch ( currentTxStopState ) { case TREATMENT_STOP_RECIRC_STATE: currentTxStopState = handleTreatmentStopRecircState(); break; case TREATMENT_STOP_NO_RECIRC_STATE: currentTxStopState = handleTreatmentStopNoRecircState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_TREATMENT_STOP_INVALID_STATE, currentTxStopState ); break; } // Broadcast treatment stop status publishTreatmentStopData(); } /*********************************************************************//** * @brief * The handleTreatmentStopRecircState function handles the re-circ dialysate * state operations. * @details Inputs: active alarms * @details Outputs: dialysate re-circulation stopped if active alarm blocks * @return next treatment stop state *************************************************************************/ static TREATMENT_STOP_STATE_T handleTreatmentStopRecircState( void ) { TREATMENT_STOP_STATE_T result = TREATMENT_STOP_RECIRC_STATE; // if any active alarm(s) blocks dialysate re-circulation, stop it if ( TRUE == isDialysateRecircBlocked() ) { signalDialInPumpHardStop(); cmdStopDGTrimmerHeater(); result = TREATMENT_STOP_NO_RECIRC_STATE; } return result; } /*********************************************************************//** * @brief * The handleTreatmentStopNoRecircState function handles the no re-circ dialysate * state operations. * @details Inputs: none * @details Outputs: none * @return next treatment stop state *************************************************************************/ static TREATMENT_STOP_STATE_T handleTreatmentStopNoRecircState( void ) { TREATMENT_STOP_STATE_T result = TREATMENT_STOP_NO_RECIRC_STATE; // nothing to do in this state - alarm user response will take us to appropriate next sub-mode return result; } /*********************************************************************//** * @brief * The getCurrentTreatmentStopState function returns the current state of the * treatment stop sub-mode. * @details Inputs: currentTxStopState * @details Outputs: none * @return currentTxStopState *************************************************************************/ TREATMENT_STOP_STATE_T getCurrentTreatmentStopState( void ) { return currentTxStopState; } /*********************************************************************//** * @brief * The publishTreatmentStopData function publishes treatment stop progress to UI * at 1 Hz interval. * @details Inputs: stopPublishTimerCtr, bloodSittingTimerCtr * @details Outputs: treatment stop data published * @return none *************************************************************************/ static void publishTreatmentStopData( void ) { if ( ++stopPublishTimerCtr >= TREATMENT_STOP_DATA_PUBLISH_INTERVAL ) { U32 timeout = MAX_TIME_BLOOD_SITTING / ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ); U32 countdown = ( bloodSittingTimerCtr >= MAX_TIME_BLOOD_SITTING ? 0 : ( MAX_TIME_BLOOD_SITTING - bloodSittingTimerCtr ) / ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ); stopPublishTimerCtr = 0; broadcastTreatmentStopData( timeout, countdown ); } } /**@}*/