/************************************************************************** * * Copyright (c) 2021-2024 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 TreatmentRecirc.c * * @author (last) Sean Nash * @date (last) 31-Jul-2023 * * @author (original) Sean Nash * @date (original) 20-Jan-2021 * ***************************************************************************/ #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 "TreatmentRecirc.h" #include "Valves.h" /** * @addtogroup TreatmentRecirculate * @{ */ // ********** private definitions ********** /// Re-circulation status broadcast interval. static const U32 RECIRC_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_RECIRC_STATE_T treatmentRecircState; ///< Current state of the treatment re-circulate sub-mode. static U32 recircTimerCtr; ///< Timer counter (in GP task intervals) counts time spent in re-circulation sub-mode. static U32 recircPublishTimerCtr; ///< Timer counter (in GP task intervals) counts time to next status broadcast. static BOOL recircStartRecircRequested; ///< Flag indicates user requesting to start recirculating (confirming disconnected). static BOOL recircReconnectRequested; ///< Flag indicates user requesting re-circulate stop so they can re-connect. static BOOL recircBackToTreatmenRequested; ///< Flag indicates user requesting to go back to treatment (confirming re-connected). static BOOL recircResumeRequested; ///< Flag indicates user requesting resumption of re-circulating. static BOOL recircEndTreatmentRequested; ///< Flag indicates user requesting end of treatment. // ********** private function prototypes ********** static void resetTreatmentRecircFlags( void ); static void setupForRecirculationState( void ); static void setupForRecirculationStopState( void ); static TREATMENT_RECIRC_STATE_T handleRecircDisconnectPatientState( void ); static TREATMENT_RECIRC_STATE_T handleRecircRecircState( void ); static TREATMENT_RECIRC_STATE_T handleRecircStoppedState( void ); static TREATMENT_RECIRC_STATE_T handleRecircReconnectPatientState( void ); static BOOL handleRecircReconnectUserAction( REQUEST_REJECT_REASON_CODE_T *rejReason ); static BOOL handleRecicConfirmReconnectUserAction( REQUEST_REJECT_REASON_CODE_T *rejReason ); static BOOL handleRecircResumeUserAction( REQUEST_REJECT_REASON_CODE_T *rejReason ); static BOOL handleRecircConfirmDisconnectUserAction( REQUEST_REJECT_REASON_CODE_T *rejReason ); static void publishTreatmentRecircData( void ); /*********************************************************************//** * @brief * The initTreatmentRecirc function initializes the Treatment Re-circulate sub-mode * module. * @details Inputs: none * @details Outputs: Treatment Re-circulate sub-mode module initialized. * @return none *************************************************************************/ void initTreatmentRecirc( void ) { treatmentRecircState = TREATMENT_RECIRC_DISCONNECT_PATIENT_STATE; recircTimerCtr = 0; recircPublishTimerCtr = 0; resetTreatmentRecircFlags(); } /*********************************************************************//** * @brief * The resetTreatmentRecircFlags function resets the treatment recirc request flags. * @details Inputs: none * @details Outputs: Treatment recirc request flags reset to FALSE. * @return none *************************************************************************/ static void resetTreatmentRecircFlags( void ) { recircStartRecircRequested = FALSE; recircReconnectRequested = FALSE; recircBackToTreatmenRequested = FALSE; recircResumeRequested = FALSE; recircEndTreatmentRequested = FALSE; } /*********************************************************************//** * @brief * The transitionToTreatmentRecirc function prepares for transition to treatment * re-circulate sub-mode. * @details Inputs: none * @details Outputs: Re-circ sub-mode setup to begin * @return none *************************************************************************/ void transitionToTreatmentRecirc( void ) { initTreatmentRecirc(); setCurrentSubState( (U32)treatmentRecircState ); doorClosedRequired( TRUE, TRUE ); // Set valves to safe state setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); setupForRecirculationStopState(); // Enable venous bubble detection while recirculating setVenousBubbleDetectionEnabled( TRUE ); // Ensure syringe pump is stopped stopSyringePump(); // Stop air trap leveling control endAirTrapControl(); // Re-circulate dialysate side of dialyzer w/ heating to maintain temperature setDialInPumpTargetFlowRate( DIALYSATE_FLOW_RATE_FOR_RECIRC, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); cmdStartDGTrimmerHeater(); // Set user alarm recovery actions allowed in this sub-mode setAlarmUserActionEnabled( ALARM_USER_ACTION_RESUME, FALSE ); setAlarmUserActionEnabled( ALARM_USER_ACTION_RINSEBACK, FALSE ); setAlarmUserActionEnabled( ALARM_USER_ACTION_END_TREATMENT, FALSE ); } /*********************************************************************//** * @brief * The setupForRecirculationState function sets actuators appropriately * for 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 setupForRecirculationState( 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 re-circulate flow rate setBloodPumpTargetFlowRate( RECIRC_BP_FLOW_RATE_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); } /*********************************************************************//** * @brief * The setupForRecirculationStopState function sets actuators appropriately * for 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 setupForRecirculationStopState( void ) { // Stop blood pump signalBloodPumpHardStop(); // Close arterial and venous lines setValvePosition( VBA, VALVE_POSITION_C_CLOSE ); setValvePosition( VBV, VALVE_POSITION_C_CLOSE ); } /*********************************************************************//** * @brief * The execTreatmentRecirc function executes the Treatment circulate sub-mode * state machine. * @details Inputs: treatmentRecircState * @details Outputs: treatmentRecircState, recircTimerCtr, recircEndTreatmentRequested * @return none *************************************************************************/ void execTreatmentRecirc( void ) { TREATMENT_RECIRC_STATE_T priorSubState = treatmentRecircState; // Count time in this sub-mode recircTimerCtr++; switch ( treatmentRecircState ) { case TREATMENT_RECIRC_DISCONNECT_PATIENT_STATE: treatmentRecircState = handleRecircDisconnectPatientState(); break; case TREATMENT_RECIRC_RECIRC_STATE: treatmentRecircState = handleRecircRecircState(); break; case TREATMENT_RECIRC_STOPPED_STATE: treatmentRecircState = handleRecircStoppedState(); break; case TREATMENT_RECIRC_RECONNECT_PATIENT_STATE: treatmentRecircState = handleRecircReconnectPatientState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_TREATMENT_RECIRC_INVALID_STATE, treatmentRecircState ); break; } if ( priorSubState != treatmentRecircState ) { setCurrentSubState( (U32)treatmentRecircState ); SEND_EVENT_WITH_2_U32_DATA( HD_EVENT_SUB_STATE_CHANGE, priorSubState, treatmentRecircState ); } // Re-circulate flags should be handled by now - reset in case not handled by current state resetTreatmentRecircFlags(); // Broadcast recirc status publishTreatmentRecircData(); } /*********************************************************************//** * @brief * The handleRecircDisconnectPatientState function handles the re-circulation * disconnect patient state operations. * @details Inputs: flags * @details Outputs: flags handled * @return next Treatment re-circulation state *************************************************************************/ static TREATMENT_RECIRC_STATE_T handleRecircDisconnectPatientState( void ) { TREATMENT_RECIRC_STATE_T result = TREATMENT_RECIRC_DISCONNECT_PATIENT_STATE; if ( TRUE == recircStartRecircRequested ) { setupForRecirculationState(); result = TREATMENT_RECIRC_RECIRC_STATE; } return result; } /*********************************************************************//** * @brief * The handleRecircRecircState function handles the re-circulating state * operations. * @details Inputs: flags * @details Outputs: flags handled * @return next treatment re-circulation state *************************************************************************/ static TREATMENT_RECIRC_STATE_T handleRecircRecircState( void ) { TREATMENT_RECIRC_STATE_T result = TREATMENT_RECIRC_RECIRC_STATE; // Is alarm stop? if ( TRUE == doesAlarmStatusIndicateStop() ) { setupForRecirculationStopState(); result = TREATMENT_RECIRC_STOPPED_STATE; } // Is user reconnect requested? else if ( TRUE == recircReconnectRequested ) { setupForRecirculationStopState(); result = TREATMENT_RECIRC_RECONNECT_PATIENT_STATE; } // Is end treatment requested? else if ( TRUE == recircEndTreatmentRequested ) { setupForRecirculationStopState(); signalEndTreatment(); // signal end Tx sub-mode } return result; } /*********************************************************************//** * @brief * The handleRecircStoppedState function handles the re-circulation stopped * state operations. * @details Inputs: flags * @details Outputs: flags handled * @return next Treatment re-circulation state *************************************************************************/ static TREATMENT_RECIRC_STATE_T handleRecircStoppedState( void ) { TREATMENT_RECIRC_STATE_T result = TREATMENT_RECIRC_STOPPED_STATE; // Is end treatment requested? if ( TRUE == recircEndTreatmentRequested ) { signalEndTreatment(); } // Is re-circ resume requested? else if ( TRUE == recircResumeRequested ) { setupForRecirculationState(); result = TREATMENT_RECIRC_RECIRC_STATE; } return result; } /*********************************************************************//** * @brief * The handleRecircReconnectPatientState function handles the re-circulation * reconnect patient state operations. * @details Inputs: flags * @details Outputs: flags handled * @return next Treatment re-circulation state *************************************************************************/ static TREATMENT_RECIRC_STATE_T handleRecircReconnectPatientState( void ) { TREATMENT_RECIRC_STATE_T result = TREATMENT_RECIRC_RECONNECT_PATIENT_STATE; // Is back to treatment requested? if ( TRUE == recircBackToTreatmenRequested ) { signalGoToTreatmentStopped(); } // Is end treatment requested? else if ( TRUE == recircEndTreatmentRequested ) { setupForRecirculationStopState(); signalEndTreatment(); // signal end Tx sub-mode } // Is re-circ resume requested? else if ( TRUE == recircResumeRequested ) { setupForRecirculationState(); result = TREATMENT_RECIRC_RECIRC_STATE; } return result; } /*********************************************************************//** * @brief * The signalTreatmentRecircUserAction function signals a re-circ 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 signalTreatmentRecircUserAction( REQUESTED_TREATMENT_RECIRC_USER_ACTIONS_T action ) { GENERIC_CONFIRMATION_REQUEST_T genericConfRequest; 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_RECIRC_RECONNECT: accepted = handleRecircReconnectUserAction( &rejReason ); break; case REQUESTED_USER_ACTION_TX_RECIRC_CONFIRM_RECONNECT: accepted = handleRecicConfirmReconnectUserAction( &rejReason ); break; case REQUESTED_USER_ACTION_TX_RECIRC_RESUME_RC: accepted = handleRecircResumeUserAction( &rejReason ); break; case REQUESTED_USER_ACTION_TX_RECIRC_END_TREATMENT: genericConfRequest.requestID = (U32)GENERIC_CONFIRM_ID_TREATMENT_END; genericConfRequest.requestType = (U32)GENERIC_CONFIRM_CMD_REQUEST_OPEN; genericConfRequest.rejectReason = 0; genericConfRequest.genericPayload1 = 0.0F; genericConfRequest.genericPayload2 = 0.0F; genericConfRequest.genericPayload3 = 0.0F; genericConfRequest.genericPayload4 = 0.0F; // Send message to UI to get user confirmation to end treatment - action initiated only upon receipt of user confirmation from UI addConfirmationRequest( &genericConfRequest ); accepted = TRUE; break; case REQUESTED_USER_ACTION_TX_RECIRC_CONFIRM_DISCONNECT: accepted = handleRecircConfirmDisconnectUserAction( &rejReason ); break; default: rejReason = REQUEST_REJECT_REASON_INVALID_COMMAND; break; } } else { rejReason = REQUEST_REJECT_REASON_ALARM_IS_ACTIVE; } // Respond to user action request sendTreatmentRecircCmdResponse( accepted, (U32)rejReason ); } /*********************************************************************//** * @brief * The handleRecircReconnectUserAction function handles a re-circulate re-connect * user action request. It is assumed that the calling function will set * the reject reason parameter to None beforehand. * @details Inputs: treatmentRecircState * @details Outputs: reconnect action handled * @param rejReason Code indicating reason for rejection * @return TRUE if user action accepted, FALSE if not *************************************************************************/ static BOOL handleRecircReconnectUserAction( REQUEST_REJECT_REASON_CODE_T *rejReason ) { BOOL result = FALSE; if ( treatmentRecircState != TREATMENT_RECIRC_RECIRC_STATE ) { *rejReason = REQUEST_REJECT_REASON_ACTION_DISABLED_IN_CURRENT_STATE; } else if ( TRUE == isTreatmentResumeBlocked() ) { *rejReason = REQUEST_REJECT_REASON_TREATMENT_CANNOT_BE_RESUMED; } else { result = TRUE; recircReconnectRequested = TRUE; } return result; } /*********************************************************************//** * @brief * The handleRecicConfirmReconnectUserAction function handles a re-circulate * back to treatment user action request. It is assumed that the calling * function will set the reject reason parameter to None beforehand. * @details Inputs: treatmentRecircState * @details Outputs: confirmation of reconnection action handled * @param rejReason Code indicating reason for rejection * @return TRUE if user action accepted, FALSE if not *************************************************************************/ static BOOL handleRecicConfirmReconnectUserAction( REQUEST_REJECT_REASON_CODE_T *rejReason ) { BOOL result = FALSE; if ( TREATMENT_RECIRC_RECONNECT_PATIENT_STATE == treatmentRecircState ) { result = TRUE; recircBackToTreatmenRequested = TRUE; } else { *rejReason = REQUEST_REJECT_REASON_ACTION_DISABLED_IN_CURRENT_STATE; } return result; } /*********************************************************************//** * @brief * The handleRecircResumeUserAction function handles a re-circulate resume * user action request. It is assumed that the calling function will set * the reject reason parameter to None beforehand. * @details Inputs: treatmentRecircState * @details Outputs: resumption of re-circulation action handled * @param rejReason Code indicating reason for rejection * @return TRUE if user action accepted, FALSE if not *************************************************************************/ static BOOL handleRecircResumeUserAction( REQUEST_REJECT_REASON_CODE_T *rejReason ) { BOOL result = FALSE; if ( ( TREATMENT_RECIRC_STOPPED_STATE == treatmentRecircState ) || ( TREATMENT_RECIRC_RECONNECT_PATIENT_STATE == treatmentRecircState ) ) { result = TRUE; recircResumeRequested = TRUE; } else { *rejReason = REQUEST_REJECT_REASON_ACTION_DISABLED_IN_CURRENT_STATE; } return result; } /*********************************************************************//** * @brief * The handleRecircConfirmDisconnectUserAction function handles a confirm * patient disconnect user action request. It is assumed that the calling * function will set the reject reason parameter to None beforehand. * @details Inputs: treatmentRecircState * @details Outputs: confirming patient disconnect action handled * @param rejReason Code indicating reason for rejection * @return TRUE if user action accepted, FALSE if not *************************************************************************/ static BOOL handleRecircConfirmDisconnectUserAction( REQUEST_REJECT_REASON_CODE_T *rejReason ) { BOOL result = FALSE; if ( TREATMENT_RECIRC_DISCONNECT_PATIENT_STATE == treatmentRecircState ) { result = TRUE; recircStartRecircRequested = TRUE; } else { *rejReason = REQUEST_REJECT_REASON_ACTION_DISABLED_IN_CURRENT_STATE; } return result; } /*********************************************************************//** * @brief * The getCurrentTreatmentRecircState function returns the current state of the * treatment re-circulate sub-mode. * @details Inputs: treatmentRecircState * @details Outputs: none * @return treatmentRecircState *************************************************************************/ TREATMENT_RECIRC_STATE_T getCurrentTreatmentRecircState( void ) { return treatmentRecircState; } /*********************************************************************//** * @brief * The publishTreatmentRecircData function publishes recirc progress to UI * at 1 Hz interval. * @details Inputs: recircPublishTimerCtr, recircTimerCtr * @details Outputs: recirc data published * @return none *************************************************************************/ static void publishTreatmentRecircData( void ) { if ( ++recircPublishTimerCtr >= RECIRC_DATA_PUBLISH_INTERVAL ) { TREATMENT_RECIRC_PAYLOAD_T data; data.timeout = 0; // currently no timeout or countdown in this mode data.countdown = 0; recircPublishTimerCtr = 0; broadcastData( MSG_ID_HD_RECIRC_PROGRESS_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( TREATMENT_RECIRC_PAYLOAD_T ) ); } } /**@}*/