Index: firmware/App/Modes/TreatmentStop.c =================================================================== diff -u -r04334ed8d1e927939718b1d62fb01afef0a2b9a9 -r254faac62b851c393c5df753eade2dc880b83247 --- firmware/App/Modes/TreatmentStop.c (.../TreatmentStop.c) (revision 04334ed8d1e927939718b1d62fb01afef0a2b9a9) +++ firmware/App/Modes/TreatmentStop.c (.../TreatmentStop.c) (revision 254faac62b851c393c5df753eade2dc880b83247) @@ -1,75 +1,501 @@ -/**********************************************************************//** - * - * Copyright (c) 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 - * - * @date 15-Jan-2020 - * @author S. Nash - * - * @brief State machine for the treatment stop sub-mode of treatment mode. - * - **************************************************************************/ +/************************************************************************** +* +* Copyright (c) 2020-2022 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) Dara Navaei +* @date (last) 23-May-2022 +* +* @author (original) Sean +* @date (original) 15-Jan-2020 +* +***************************************************************************/ -#include "Buttons.h" +#include "AirTrap.h" +#include "BloodFlow.h" +#include "BloodLeak.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 ********** + +/// Treatment stop status broadcast interval. +#define TREATMENT_STOP_DATA_PUBLISH_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) +/// Target flow rate for re-circulation of saline on blood-side circuit. +#define RECIRC_BP_FLOW_RATE_ML_MIN 100 + // ********** 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. +/// Interval (in task intervals) at which to publish treatment stop sub-mode data to CAN bus. +static OVERRIDE_U32_T treatmentStopPublishInterval = { TREATMENT_STOP_DATA_PUBLISH_INTERVAL, TREATMENT_STOP_DATA_PUBLISH_INTERVAL, TREATMENT_STOP_DATA_PUBLISH_INTERVAL, 0 }; + // ********** private function prototypes ********** +static TREATMENT_STOP_STATE_T handleTreatmentStopRecircState( void ); +static TREATMENT_STOP_STATE_T handleTreatmentStopNoRecircState( void ); +static void setupForDialysateRecirculationState( void ); +static void setupForBloodRecirculationState( void ); +static TREATMENT_STOP_STATE_T handleTreatmentStopAlarmsAndSignals( TREATMENT_STOP_STATE_T state ); +static TREATMENT_STOP_STATE_T handleTreatmentStopDialysateRecircState( void ); +static TREATMENT_STOP_STATE_T handleTreatmentStopBloodRecircState( void ); +static void handleTreatmentStopBloodSittingTimer( void ); + +static void publishTreatmentStopData( void ); + /*********************************************************************//** - * @brief initTreatmentStop + * @brief * The initTreatmentStop function initializes the Treatment Stop sub-mode * module. - * @details - * Inputs : none - * Outputs : Treatment Stop sub-mode module initialized. + * @details Inputs: none + * @details Outputs: Treatment Stop sub-mode module initialized. * @return none *************************************************************************/ void initTreatmentStop( void ) { + currentTxStopState = TREATMENT_STOP_RECIRC_STATE; + bloodSittingTimerCtr = 0; + stopPublishTimerCtr = TREATMENT_STOP_DATA_PUBLISH_INTERVAL; } /*********************************************************************//** - * @brief transitionToTreatmentStop - * The transitionToTreatmentStop function prepares for transition to treatment \n + * @brief + * The transitionToTreatmentStop function prepares for transition to treatment * stop sub-mode. - * @details - * Inputs : none - * Outputs : none + * @details Inputs: none + * @details Outputs: none * @return none *************************************************************************/ void transitionToTreatmentStop( void ) { + initTreatmentStop(); + + // 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 syringe pump is stopped + stopSyringePump(); + + // Set Dialysate valves to bypass filter for recirculation + setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); + setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); + + setupForBloodRecirculationState(); + + setupForDialysateRecirculationState(); + + // 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 execTreatmentStop - * The execTreatmentStop function executes the Treatment Stop sub-mode \n + * @brief + * The setupForDialysateRecirculationState function sets actuators appropriately + * for Dialysate recirculation 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 setupForDialysateRecirculationState( void ) +{ + // Re-circulate dialysate side of dialyzer w/ heating to maintain temperature + doorClosedRequired( TRUE, TRUE ); + setDialInPumpTargetFlowRate( DIALYSATE_FLOW_RATE_FOR_RECIRC, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); + cmdStartDGTrimmerHeater(); +} + +/*********************************************************************//** + * @brief + * The setupForBloodRecirculationState function sets actuators appropriately + * for Blood recirculation state. + * @details Inputs: none + * @details Outputs: arterial and venous lines closed, blood pump started, + * and air trap leveling control is started. + * @return none + *************************************************************************/ +static void setupForBloodRecirculationState( void ) +{ + doorClosedRequired( TRUE, TRUE ); + // Open VBA and VBV valves to patient for blood recirculation + setValvePosition( VBA, VALVE_POSITION_B_OPEN ); + setValvePosition( VBV, VALVE_POSITION_B_OPEN ); + // Start blood pump at re-circulate flow rate + setBloodPumpTargetFlowRate( RECIRC_BP_FLOW_RATE_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); + // Start air trap leveling control + startAirTrapControl(); + // Reset blood sitting timer, it is now circulating + bloodSittingTimerCtr = 0; +} + +/*********************************************************************//** + * @brief + * The setupForDialysateRecirculationStopState function sets actuators appropriately + * for dialysate re-circulation stopped 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 setupForDialysateRecirculationStopState( void ) +{ + // Stop dialysate side of dialyzer and heating + signalDialInPumpHardStop(); + cmdStopDGTrimmerHeater(); +} + +/*********************************************************************//** + * @brief + * The setupForBloodRecirculationStopState function sets actuators appropriately + * for blood re-circulation stopped 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 setupForBloodRecirculationStopState( 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 execTreatmentStop function executes the Treatment Stop sub-mode * state machine. - * @details - * Inputs : none - * Outputs : none + * @details Inputs: none + * @details Outputs: none * @return none *************************************************************************/ void execTreatmentStop( void ) { - // TODO - test code - remove later - if ( TRUE == isStopButtonPressed() ) + // Execute treatment stop sub-mode state machine + switch ( currentTxStopState ) { - requestNewOperationMode( MODE_POST ); + case TREATMENT_STOP_RECIRC_STATE: + currentTxStopState = handleTreatmentStopRecircState(); + break; + + case TREATMENT_STOP_RECIRC_DIALYSATE_ONLY_STATE: + currentTxStopState = handleTreatmentStopDialysateRecircState(); + break; + + case TREATMENT_STOP_RECIRC_BLOOD_ONLY_STATE: + currentTxStopState = handleTreatmentStopBloodRecircState(); + 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 handleTreatmentStopAlarmsAndSignals function handles the Alarms and User Signals + * operations to set new states. + * @details Inputs: state, flags + * @details Outputs: flags handled + * @return next treatment re-circulation state + *************************************************************************/ +static TREATMENT_STOP_STATE_T handleTreatmentStopAlarmsAndSignals( TREATMENT_STOP_STATE_T state ) +{ + TREATMENT_STOP_STATE_T result = state; + bool bloodRecircBlocked = isBloodRecircBlocked(); + bool dialysateRecircBlocked = isDialysateRecircBlocked(); + + // Both unblocked and not in recirculate both state + if ( (TREATMENT_STOP_RECIRC_STATE != state) && ( FALSE == dialysateRecircBlocked ) + && ( FALSE == bloodRecircBlocked ) ) + { + setupForBloodRecirculationState(); + setupForDialysateRecirculationState(); + result = TREATMENT_STOP_RECIRC_STATE; + } + + // Both blocked and not in stopped state + if ( (TREATMENT_STOP_NO_RECIRC_STATE != state) && ( TRUE == dialysateRecircBlocked ) + && ( TRUE == bloodRecircBlocked ) ) + { + setupForBloodRecirculationStopState(); + setupForDialysateRecirculationStopState(); + result = TREATMENT_STOP_NO_RECIRC_STATE; + } + + // Dialysate recirculation blocked and not in blood recirc state + if ( ( TREATMENT_STOP_RECIRC_BLOOD_ONLY_STATE != state ) + && ( TRUE == dialysateRecircBlocked ) + && ( FALSE == bloodRecircBlocked ) ) + { + setupForDialysateRecirculationStopState(); + result = TREATMENT_STOP_RECIRC_BLOOD_ONLY_STATE; + } + + // Blood recirculation blocked and not in dialysate recirc state + if ( ( TREATMENT_STOP_RECIRC_DIALYSATE_ONLY_STATE != state ) + && ( TRUE == bloodRecircBlocked ) + && ( FALSE == dialysateRecircBlocked ) ) + { + setupForBloodRecirculationStopState(); + result = TREATMENT_STOP_RECIRC_DIALYSATE_ONLY_STATE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleTreatmentStopRecircState function handles the re-circ dialysate + * and blood 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; + + result = handleTreatmentStopAlarmsAndSignals( result ); + + return result; +} + +/*********************************************************************//** + * @brief + * The handleTreatmentStopDialysateRecircState function handles the Dialysate only + * re-circulating state operations. + * @details Inputs: flags + * @details Outputs: flags handled + * @return next treatment re-circulation state + *************************************************************************/ +static TREATMENT_STOP_STATE_T handleTreatmentStopDialysateRecircState( void ) +{ + TREATMENT_STOP_STATE_T result = TREATMENT_STOP_RECIRC_DIALYSATE_ONLY_STATE; + + handleTreatmentStopBloodSittingTimer(); + + result = handleTreatmentStopAlarmsAndSignals(result); + + return result; +} + +/*********************************************************************//** + * @brief + * The handleTreatmentStopBloodRecircState function handles the Blood only + * re-circulating state operations. + * @details Inputs: flags + * @details Outputs: flags handled + * @return next treatment re-circulation state + *************************************************************************/ +static TREATMENT_STOP_STATE_T handleTreatmentStopBloodRecircState( void ) +{ + TREATMENT_STOP_STATE_T result = TREATMENT_STOP_RECIRC_BLOOD_ONLY_STATE; + + result = handleTreatmentStopAlarmsAndSignals(result); + + 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; + + doorClosedRequired( FALSE, FALSE ); + + handleTreatmentStopBloodSittingTimer(); + + result = handleTreatmentStopAlarmsAndSignals( result ); + + return result; +} + +/*********************************************************************//** + * @brief + * The handleTreatmentStopBloodSittingTimer function handles the no re-circ + * blood timer. It should only be called when Blood is NOT circulating. + * Increments and checks for warning and alarm timeouts. + * @details Inputs: none + * @details Outputs: none + * @return next treatment stop state + *************************************************************************/ +static void handleTreatmentStopBloodSittingTimer( void ) +{ + // Ensure we do not sit in stopped state for too long (if blood in line) + if ( getRinsebackCompleted() != TRUE ) + { + if ( ++bloodSittingTimerCtr > WARN_TIME_BLOOD_SITTING ) + { + activateAlarmNoData( ALARM_ID_BLOOD_SITTING_WARNING ); + } + if ( bloodSittingTimerCtr > MAX_TIME_BLOOD_SITTING ) + { + // Activate the alarm + activateAlarmNoData( ALARM_ID_TREATMENT_STOPPED_NO_RINSEBACK ); + } + } + else + { + bloodSittingTimerCtr = 0; + } +} +/*********************************************************************//** + * @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 >= getU32OverrideValue( &treatmentStopPublishInterval ) ) + { + TREATMENT_STOP_PAYLOAD_T data; + + // Set to zero so UI will not update unless needed below + data.timeout = 0; + data.countdown = 0; + + if ( getRinsebackCompleted() != TRUE ) + { + if ( bloodSittingTimerCtr > 0 ) + { + data.timeout = MAX_TIME_BLOOD_SITTING / ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ); + data.countdown = ( bloodSittingTimerCtr >= MAX_TIME_BLOOD_SITTING ? 0 : ( MAX_TIME_BLOOD_SITTING - bloodSittingTimerCtr ) / ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ); + } + } + stopPublishTimerCtr = 0; + broadcastData( MSG_ID_HD_TREATMENT_STOP_TIMER_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( TREATMENT_STOP_PAYLOAD_T ) ); + } +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testSetTreatmentStopPublishIntervalOverride function sets the override of the + * treatment stop sub-mode data publication interval. + * @details Inputs: none + * @details Outputs: treatmentStopPublishInterval + * @param ms milliseconds between treatment stop sub-mode broadcasts + * @return TRUE if override set successful, FALSE if not + *************************************************************************/ +BOOL testSetTreatmentStopPublishIntervalOverride( U32 ms ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + U32 intvl = ms / TASK_GENERAL_INTERVAL; + + result = TRUE; + treatmentStopPublishInterval.ovData = intvl; + treatmentStopPublishInterval.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetTreatmentStopPublishIntervalOverride function resets the override of the + * treatment stop sub-mode data publication interval. + * @details Inputs: none + * @details Outputs: treatmentStopPublishInterval + * @return TRUE if override reset successful, FALSE if not + *************************************************************************/ +BOOL testResetTreatmentStopPublishIntervalOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + treatmentStopPublishInterval.override = OVERRIDE_RESET; + treatmentStopPublishInterval.ovData = treatmentStopPublishInterval.ovInitData; + } + + return result; +} + /**@}*/