/************************************************************************** * * Copyright (c) 2025-2025 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 StateTxDialysis.c * * @author (last) Sean * @date (last) 15-Apr-2025 * * @author (original) Sean * @date (original) 15-Apr-2025 * ***************************************************************************/ #include "TDCommon.h" #include "AirTrap.h" #include "BloodFlow.h" #include "Buttons.h" #include "DDInterface.h" #include "Messaging.h" #include "ModeTreatment.h" #include "ModeTxParams.h" //#include "NVDataMgmt.h" #include "OperationModes.h" #include "StateTxDialysis.h" //#include "Switches.h" #include "TaskGeneral.h" #include "Valves.h" /** * @addtogroup StateTxDialysis * @{ */ // ********** private definitions ********** // ********** private data ********** static DIALYSIS_STATE_T currentDialysisState; ///< Current state of the dialysis sub-mode state machine. static U32 setBloodFlowRate; ///< Currently set blood flow rate (from prescription). static U32 setDialysateFlowRate; ///< Currently set dialysate flow rate (from prescription). static F32 setUFVolumeL; ///< Currently set total ultrafiltration volume (in L) for treatment (from prescription). static F32 setUFRateLHr; ///< Currently set ultrafiltration rate (in L/hr from prescription). static OVERRIDE_F32_T measUFVolumeL; ///< Current total measured volume (in L) for ultrafiltration . static BOOL ufPauseRequested; ///< Flag indicates UF pause has been requested by user. static BOOL ufResumeRequested; ///< Flag indicates UF resume has been requested by user. static BOOL autoResumeUF; ///< Flag indicates UF should be auto-resumed after saline bolus completes. // ********** private function prototypes ********** static void transitionToDialysisState( DIALYSIS_STATE_T newState ); static DIALYSIS_STATE_T handleDialysisUltrafiltrationState( void ); static DIALYSIS_STATE_T handleDialysisUltrafiltrationPausedState( void ); static void updateUFVolume( void ); /*********************************************************************//** * @brief * The initDialysis function initializes the Dialysis sub-mode module. * Calling this function will reset dialysis and therefore should only * be called when a new treatment is due to begin. * @details \b Inputs: none * @details \b Outputs: Dialysis sub-mode module initialized. * @return none *************************************************************************/ void initDialysis( void ) { currentDialysisState = DIALYSIS_UF_STATE; measUFVolumeL.data = 0.0F; measUFVolumeL.ovData = 0.0F; measUFVolumeL.ovInitData = 0.0F; measUFVolumeL.override = OVERRIDE_RESET; setBloodFlowRate = 0; setDialysateFlowRate = 0; setUFVolumeL = 0.0F; setUFRateLHr = 0.0F; ufPauseRequested = FALSE; ufResumeRequested = FALSE; autoResumeUF = FALSE; } /*********************************************************************//** * @brief * The transitionToDialysis function prepares for transition to dialysis sub-mode. * This function will reset anything required for resuming dialysis in a * treatment that has already begun. It does not reset everything as dialysis * may be stopped and resumed multiple times due to alarms or user intervention * and we don't want to start the treatment all over again. * @details \b Inputs: none * @details \b Outputs: none * @return none *************************************************************************/ void transitionToDialysis( void ) { PUMP_CONTROL_MODE_T mode = PUMP_CONTROL_MODE_CLOSED_LOOP; // doorClosedRequired( TRUE, TRUE ); // Set user alarm recovery actions allowed in this sub-mode setAlarmUserActionEnabled( ALARM_USER_ACTION_RESUME, TRUE ); setAlarmUserActionEnabled( ALARM_USER_ACTION_RINSEBACK, TRUE ); setAlarmUserActionEnabled( ALARM_USER_ACTION_END_TREATMENT, TRUE ); // Set actuators as appropriate for state cmdStartGenerateDialysate( setDialysateFlowRate, setUFRateLHr, getTreatmentParameterF32( TREATMENT_PARAM_DIALYSATE_TEMPERATURE ), FALSE, (ACID_CONCENTRATE_TYPE_T)getTreatmentParameterU32( TREATMENT_PARAM_ACID_CONCENTRATE ), (BICARB_CONCENTRATE_TYPE_T)getTreatmentParameterU32( TREATMENT_PARAM_BICARB_CONCENTRATE ) ); transitionToDialysisState( currentDialysisState ); // Set substate for event setCurrentSubState( (U32)currentDialysisState ); } /*********************************************************************//** * @brief * The transitionToDialysisState function sets all actuators as appropriate * go the given new dialysis state. * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if invalid state is given * @details \b Inputs: none * @details \b Outputs: none * @param newState The new state that we are transitioning to. * @return none *************************************************************************/ static void transitionToDialysisState( DIALYSIS_STATE_T newState ) { switch ( newState ) { case DIALYSIS_UF_STATE: setValvePosition( H1_VALV, VALVE_POSITION_B_OPEN ); // set arterial valve to pump blood from patient setValvePosition( H19_VALV, VALVE_POSITION_B_OPEN ); // set venous valve to open, allowing blood to return to patient setBloodPumpTargetFlowRate( setBloodFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); cmdChangeQuf( setUFRateLHr ); // Start auto-control of air trap valve startAirTrapControl(); break; case DIALYSIS_UF_PAUSED_STATE: // Set valves for dialysis setValvePosition( H1_VALV, VALVE_POSITION_B_OPEN ); // set arterial valve to pump blood from patient setValvePosition( H19_VALV, VALVE_POSITION_B_OPEN ); // set venous valve to open, allowing blood to return to patient // Restart pumps setBloodPumpTargetFlowRate( setBloodFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); cmdChangeQuf( 0.0F ); // Start auto-control of air trap valve startAirTrapControl(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TX_DIALYSIS_INVALID_STATE1, (U32)newState ) break; } } /*********************************************************************//** * @brief * The getDialysisState function gets the current dialysis state. * @details \b Inputs: currentDialysisState * @details \b Outputs: none * @return currentDialysisState *************************************************************************/ DIALYSIS_STATE_T getDialysisState( void ) { return currentDialysisState; } /*********************************************************************//** * @brief * The getUltrafiltrationVolumeDrawn function gets the current total * ultrafiltration volume (in L) drawn from the patient so far. * @details \b Inputs: measUFVolumeL * @details \b Outputs: none * @return Total ultrafiltration volume (in L) drawn from the patient so far. *************************************************************************/ F32 getUltrafiltrationVolumeDrawn( void ) { F32 result = getF32OverrideValue( &measUFVolumeL ); return result; } /*********************************************************************//** * @brief * The setDialysisBloodPumpFlowRate function sets the blood pump flow rate parameter. * This function should be called prior to beginning dialysis treatment * and when the user changes the blood flow rate during treatment. * @details \b Inputs: none * @details \b Outputs: setBloodFlowRate * @param bPFlow target blood pump flow rate (in mL/min) * @return none *************************************************************************/ void setDialysisBloodPumpFlowRate( U32 bPFlow ) { setBloodFlowRate = bPFlow; // Make rate changes in real time if currently performing dialysis. if ( TREATMENT_DIALYSIS_STATE == getTreatmentState() ) { setBloodPumpTargetFlowRate( setBloodFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); } } /*********************************************************************//** * @brief * The setDialysisDDParams function sets the dialysate rate and ultrafiltration * volume and rate parameters. * @details \b Inputs: none * @details \b Outputs: setDialysateFlowRate, setDialysateFlowRate, setUFRateLHr * @param qd target dialysate flow rate (in mL/min) * @param ufVol target ultrafiltration volume (in L) * @param quf target ultrafiltration flow rate (in L/hr) * @return none *************************************************************************/ void setDialysisDDParams( U32 qd, F32 ufVol, F32 quf ) { setDialysateFlowRate = qd; setDialysateFlowRate = ufVol; setUFRateLHr = quf; } /*********************************************************************//** * @brief * The signalPauseResumeUF function handles a request to pause or resume * ultrafiltration. * @details \b Message \b Sent: MSG_ID_TD_UF_PAUSE_RESUME_RESPONSE * @details \b Message \b Sent: UF_START_PAUSE_EVENT / UF_START_RESUME_EVENT * @details \b Inputs: currentDialysisState, setUFRateLHr * @details \b Outputs: ufPauseRequested, ufResumeRequested * @param message Message from UI which includes a flag indicating whether * to pause or resume ultrafiltration. * @return TRUE if pause *************************************************************************/ BOOL signalPauseResumeUF( MESSAGE_T *message ) { TREATMENT_STATE_T trtState = getTreatmentState(); TD_OP_MODE_T currMode = getCurrentOperationMode(); UI_RESPONSE_PAYLOAD_T response; response.accepted = FALSE; response.rejectionReason = REQUEST_REJECT_REASON_NONE; // Verify payload length is valid if ( sizeof( BOOL ) == message->hdr.payloadLen ) { BOOL payload; memcpy( &payload, message->payload, sizeof( BOOL ) ); // Handle request to resume ultrafiltration if ( TRUE == payload ) { ufResumeRequested = TRUE; if ( ( MODE_TREA == currMode ) && ( TREATMENT_DIALYSIS_STATE == trtState ) && ( DIALYSIS_UF_PAUSED_STATE == currentDialysisState ) ) { response.accepted = TRUE; if ( setUFRateLHr > 0.0 ) { //sendTreatmentLogEventData( UF_START_RESUME_EVENT, 0.0, setUFRateLHr ); } } else { if ( MODE_TREA != currMode ) { response.rejectionReason = REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE; } else if ( ( TREATMENT_DIALYSIS_STATE != trtState ) || ( DIALYSIS_UF_PAUSED_STATE != currentDialysisState ) ) { response.rejectionReason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; } else { response.rejectionReason = REQUEST_REJECT_REASON_UF_NOT_PAUSED; } } } // Handle request to pause ultrafiltration else { ufPauseRequested = TRUE; if ( ( MODE_TREA == currMode ) && ( TREATMENT_DIALYSIS_STATE == trtState ) && ( DIALYSIS_UF_STATE == currentDialysisState ) ) { response.accepted = TRUE; if ( setUFRateLHr > 0.0 ) { //sendTreatmentLogEventData( UF_PAUSE_EVENT, setUFRateLHr, 0.0 ); } } else { if ( MODE_TREA != currMode ) { response.rejectionReason = REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE; } else if ( ( TREATMENT_DIALYSIS_STATE != trtState ) || ( DIALYSIS_UF_STATE != currentDialysisState ) ) { response.rejectionReason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; } else { response.rejectionReason = REQUEST_REJECT_REASON_UF_NOT_IN_PROGESS; } } } } else { response.rejectionReason = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; } // Send response w/ reason code if rejected sendMessage( MSG_ID_TD_UF_PAUSE_RESUME_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08*)(&response), sizeof( UI_RESPONSE_PAYLOAD_T ) ); return response.accepted; } /*********************************************************************//** * @brief * The pauseDialysis function pauses dialysis. This function will be called * by Treatment Mode when an alarm occurs or the user pressed the stop button. * Dialysis may be resumed later. * @details Inputs: none * @details Outputs: Pumps stopped. DD commanded to bypass. * @return none *************************************************************************/ void pauseDialysis( void ) { // Stop pumps signalBloodPumpHardStop(); // Tell DD to bypass dialyzer while alarm has dialysis paused cmdBypassDialyzer( TRUE ); } /*********************************************************************//** * @brief * The execDialysis function executes the Dialysis sub-mode state machine. * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if state is invalid * @details \b Message \b Sent: TD_EVENT_SUB_STATE_CHANGE when state changes * @details \b Inputs: currentDialysisState * @details \b Outputs: currentDialysisState * @return none *************************************************************************/ void execDialysis( void ) { DIALYSIS_STATE_T priorSubState = currentDialysisState; // Dialysis state machine switch ( currentDialysisState ) { case DIALYSIS_UF_STATE: currentDialysisState = handleDialysisUltrafiltrationState(); break; case DIALYSIS_UF_PAUSED_STATE: currentDialysisState = handleDialysisUltrafiltrationPausedState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TX_DIALYSIS_INVALID_STATE1, (U32)currentDialysisState ) break; } // Update total UF volume drawn updateUFVolume(); if ( priorSubState != currentDialysisState ) { setCurrentSubState( (U32)currentDialysisState ); SEND_EVENT_WITH_2_U32_DATA( TD_EVENT_SUB_STATE_CHANGE, priorSubState, currentDialysisState ); } } /*********************************************************************//** * @brief * The handleDialysisUltrafiltrationState function handles the ultrafiltration * state of the Dialysis state machine. * @details \b Inputs: ufPauseRequested * @details \b Outputs: ufPauseRequested * @return next Dialysis state. *************************************************************************/ static DIALYSIS_STATE_T handleDialysisUltrafiltrationState( void ) { DIALYSIS_STATE_T result = DIALYSIS_UF_STATE; if ( TRUE == ufPauseRequested ) { ufPauseRequested = FALSE; transitionToDialysisState( DIALYSIS_UF_PAUSED_STATE ); result = DIALYSIS_UF_PAUSED_STATE; } return result; } /*********************************************************************//** * @brief * The handleDialysisUltrafiltrationPausedState function handles the * ultrafiltration paused state of the Dialysis state machine. * @details \b Inputs: ufResumeRequested * @details \b Outputs: ufResumeRequested * @return next Dialysis state. *************************************************************************/ static DIALYSIS_STATE_T handleDialysisUltrafiltrationPausedState( void ) { DIALYSIS_STATE_T result = DIALYSIS_UF_PAUSED_STATE; if ( TRUE == ufResumeRequested ) { ufResumeRequested = FALSE; transitionToDialysisState( DIALYSIS_UF_STATE ); result = DIALYSIS_UF_STATE; } return result; } /*********************************************************************//** * @brief * The updateUFVolume function updates the total measured ultrafiltration * volume based on set rate and whether or not DD is currently running * the ultrafiltration pump. * @details \b Inputs: none * @details \b Outputs: measUFVolumeL * @return none *************************************************************************/ static void updateUFVolume( void ) { // Update total UF volume drawn measUFVolumeL.data = 0.0F; // TODO } /**@}*/