#include "BloodFlow.h" #include "Dialysis.h" #include "ModeTreatment.h" #include "ModeTreatmentParams.h" #include "OperationModes.h" #include "PresOccl.h" #include "SalineBolus.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "Timers.h" #include "TreatmentStop.h" #include "Valves.h" /** * @addtogroup Dialysis * @{ */ // ********** private definitions ********** static const U32 SALINE_BOLUS_DATA_PUB_INTERVAL = ( MS_PER_SECOND / TASK_GENERAL_INTERVAL); ///< Saline bolus data broadcast interval (ms/task time) count. // ********** private data ********** static SALINE_BOLUS_STATE_T currentSalineBolusState; ///< Current state of the saline bolus state machine. static U32 salineBolusBroadcastTimerCtr; ///< Saline bolus data broadcast timer counter used to schedule when to transmit data. static BOOL salineBolusStartRequested; ///< Flag indicates a saline bolus start has been requested by user. static BOOL salineBolusAbortRequested; ///< Flag indicates a salien bolus abort has been requested by user. static F32 totalSalineVolumeDelivered_mL; ///< Volume (mL) in total of saline delivered so far (cumulative for all boluses including current one). static F32 bolusSalineVolumeDelivered_mL; ///< Volume (mL) of current bolus delivered so far (calculated from measured blood flow rate). static U32 bolusSalineLastVolumeTimeStamp; ///< Time stamp for last saline volume update. // ********** private function prototypes ********** static SALINE_BOLUS_STATE_T handleSalineBolusIdleState( void ); static SALINE_BOLUS_STATE_T handleSalineBolusWait4Pumps2Stop( void ); static SALINE_BOLUS_STATE_T handleSalineBolusInProgressState( void ); /*********************************************************************//** * @brief * The initSalineBolus function initializes the Saline Bolus module. * Calling this function will reset saline bolus and therefore should only * be called when a new treatment is due to begin. * @details Inputs: none * @details Outputs: currentSalineBolusState, salineBolusBroadcastTimerCtr, * totalSalineVolumeDelivered_mL, bolusSalineVolumeDelivered_mL, * salineBolusStartRequested, salineBolusAbortRequested * @return none *************************************************************************/ void initSalineBolus( void ) { currentSalineBolusState = SALINE_BOLUS_STATE_IDLE; salineBolusBroadcastTimerCtr = 0; totalSalineVolumeDelivered_mL = 0.0; bolusSalineVolumeDelivered_mL = 0.0; salineBolusStartRequested = FALSE; salineBolusAbortRequested = FALSE; bolusSalineLastVolumeTimeStamp = getMSTimerCount(); } /*********************************************************************//** * @brief * The resetSalineBolus function resets the saline bolus variables. * @details Inputs: currentSalineBolusState * @details Outputs: bolusSalineVolumeDelivered_mL, salineBolusStartRequested, * salineBolusAbortRequested, currentSalineBolusState * @return none *************************************************************************/ void resetSalineBolus( void ) { bolusSalineVolumeDelivered_mL = 0.0; salineBolusStartRequested = FALSE; salineBolusAbortRequested = FALSE; currentSalineBolusState = SALINE_BOLUS_STATE_IDLE; resetUF(); } /*********************************************************************//** * @brief * The execSalineBolus function executes the saline bolus state machine. * @details Inputs: currentSalineBolusState * @details Outputs: currentSalineBolusState * @return Current saline bolus state machine. *************************************************************************/ SALINE_BOLUS_STATE_T execSalineBolus( void ) { SALINE_BOLUS_STATE_T priorSubState = currentSalineBolusState; switch ( currentSalineBolusState ) { case SALINE_BOLUS_STATE_IDLE: currentSalineBolusState = handleSalineBolusIdleState(); break; case SALINE_BOLUS_STATE_WAIT_FOR_PUMPS_STOP: currentSalineBolusState = handleSalineBolusWait4Pumps2Stop(); break; case SALINE_BOLUS_STATE_IN_PROGRESS: currentSalineBolusState = handleSalineBolusInProgressState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_DIALYSIS_INVALID_SALINE_BOLUS_STATE, currentSalineBolusState ) currentSalineBolusState = SALINE_BOLUS_STATE_IDLE; break; } if ( priorSubState != currentSalineBolusState ) { setCurrent4thLevelState( (U32)currentSalineBolusState ); SEND_EVENT_WITH_2_U32_DATA( HD_EVENT_SUB_STATE_CHANGE, priorSubState, currentSalineBolusState ); } return currentSalineBolusState; } /*********************************************************************//** * @brief * The getSalineBolusState function gets the current saline bolus state. * @details Inputs: currentSalineBolusState * @details Outputs: none * @return currentSalineBolusState *************************************************************************/ SALINE_BOLUS_STATE_T getSalineBolusState( void ) { return currentSalineBolusState; } /*********************************************************************//** * @brief * The getTotalSalineBolusVolumeDelivered function gets the current total * saline volume delivered. * @details Inputs: totalSalineVolumeDelivered * @details Outputs: none * @return totalSalineVolumeDelivered *************************************************************************/ F32 getTotalSalineBolusVolumeDelivered( void ) { return totalSalineVolumeDelivered_mL; } /*********************************************************************//** * @brief * The isSalineBolusStartRequested function returns the status of a saline * bolus start request. * @details Inputs: salineBolusStartRequested * @details Outputs: none * @return Saline bolus start request status *************************************************************************/ BOOL isSalineBolusStartRequested( void ) { return salineBolusStartRequested; } /*********************************************************************//** * @brief * The setSalineBolusStartRequestStatus function sets the status of a saline * bolus start request. * @details Inputs: none * @details Outputs: salineBolusStartRequested * @return none *************************************************************************/ void setSalineBolusStartRequestStatus( BOOL status ) { salineBolusStartRequested = status; } /*********************************************************************//** * @brief * The signalStartSalineBolus function handles user request to initiate a * saline bolus. * @details Inputs: set bolus volume, current mode/sub-mode, bolus state * @details Outputs: salineBolusStartRequested, response sent * @return none *************************************************************************/ void signalStartSalineBolus( void ) { BOOL accept = FALSE; REQUEST_REJECT_REASON_CODE_T rejReason = REQUEST_REJECT_REASON_NONE; U32 salineBolusVolume = getTreatmentParameterU32( TREATMENT_PARAM_SALINE_BOLUS_VOLUME ); HD_OP_MODE_T currOpMode = getCurrentOperationMode(); TREATMENT_STATE_T currTreatSubMode = getTreatmentState(); // Must be in treatment mode, dialysis sub-mode or treatment stop sub-mode, saline bolus in idle state in order to start a saline bolus if ( currOpMode != MODE_TREA ) { rejReason = REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE; } else if ( ( currTreatSubMode != TREATMENT_DIALYSIS_STATE ) && ( currTreatSubMode != TREATMENT_STOP_STATE ) ) { rejReason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; } else if ( ( TREATMENT_STOP_STATE == currTreatSubMode ) && ( TREATMENT_STOP_RECOVER_BLOOD_DETECT_STATE == getCurrentTreatmentStopState() ) ) { // If in treatment stop submode but also in blood recover the software cannot do saline bolus rejReason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; } else if ( ( TRUE == isAnyAlarmActive() ) && ( ( TRUE == isBloodRecircBlocked() ) || ( TRUE == isRinseBackBlocked() ) ) ) { // Any alarm can be active but blood recirculation and dialysate recirculation cannot be blocked in their properties in order // to do saline bolus rejReason = REQUEST_REJECT_REASON_SALINE_BOLUS_NOT_ALLOWED; } else if ( currentSalineBolusState != SALINE_BOLUS_STATE_IDLE ) { rejReason = REQUEST_REJECT_REASON_SALINE_BOLUS_IN_PROGRESS; } else { accept = TRUE; salineBolusStartRequested = TRUE; signalInitiatePressureStabilization( USE_NORMAL_STABILIZATION_PERIOD ); } // Send response sendSalineBolusResponse( accept, rejReason, salineBolusVolume ); } /*********************************************************************//** * @brief * The signalAbortSalineBolus function handles user request to abort a * saline bolus. * @details Inputs: set bolus volume, current mode/sub-mode, bolus state * @details Outputs: salineBolusAbortRequested, response sent * @return none *************************************************************************/ void signalAbortSalineBolus( void ) { BOOL accept = FALSE; REQUEST_REJECT_REASON_CODE_T rejReason = REQUEST_REJECT_REASON_NONE; U32 salineBolusVolume = getTreatmentParameterU32( TREATMENT_PARAM_SALINE_BOLUS_VOLUME ); HD_OP_MODE_T currOpMode = getCurrentOperationMode(); TREATMENT_STATE_T currTreatSubMode = getTreatmentState(); SALINE_BOLUS_STATE_T currSalineBolusState = getSalineBolusState(); // Must be in treatment mode, dialysis sub-mode, saline bolus in delivery state in order to abort a saline bolus if ( currOpMode != MODE_TREA ) { rejReason = REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE; } else if ( ( currTreatSubMode != TREATMENT_DIALYSIS_STATE ) && ( currTreatSubMode != TREATMENT_STOP_STATE ) ) { rejReason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; } else if ( currSalineBolusState != SALINE_BOLUS_STATE_IN_PROGRESS ) { rejReason = REQUEST_REJECT_REASON_SALINE_BOLUS_NOT_IN_PROGRESS; } else { accept = TRUE; salineBolusAbortRequested = TRUE; signalInitiatePressureStabilization( USE_NORMAL_STABILIZATION_PERIOD ); } // Send response sendSalineBolusResponse( accept, rejReason, salineBolusVolume ); } /*********************************************************************//** * @brief * The publishSalineBolusData function publishes the saline bolus and * blood leak zeroing at 1 Hz interval. * @details Inputs: salineBolusBroadcastTimerCtr * @details Outputs: salineBolusBroadcastTimerCtr * @param blood leak zeroing DPi to BLD flush volume in milliliters * @param blood leak zeroing reserver to DPi flush volume in milliliters * @param blood leak zeroing needed after reservoir switch boolean flag * @return none *************************************************************************/ void publishSalineBolusData( F32 bloodLeakZeroingDPi2BLDFlushVolumeML, F32 bloodLeakZeroingRsrvr2DPiFlushVolumeML, U32 bloodLeakZeroingNeededAfterRsrvrSwitch ) { if ( ++salineBolusBroadcastTimerCtr >= SALINE_BOLUS_DATA_PUB_INTERVAL ) { SALINE_BOLUS_DATA_PAYLOAD_T data; data.tgtSalineVolumeMl = getTreatmentParameterU32( TREATMENT_PARAM_SALINE_BOLUS_VOLUME ); data.cumSalineVolumeMl = totalSalineVolumeDelivered_mL; data.bolSalineVolumeMl = bolusSalineVolumeDelivered_mL; data.bloodLeakZeroingDPi2BLDFlushVolumeML = bloodLeakZeroingDPi2BLDFlushVolumeML; data.bloodLeakZeroingRsrvr2DPiFlushVolumeML = bloodLeakZeroingRsrvr2DPiFlushVolumeML; data.bloodLeakZeroingNeededAfterRsrvrSwitch = bloodLeakZeroingNeededAfterRsrvrSwitch; broadcastData( MSG_ID_SALINE_BOLUS_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( SALINE_BOLUS_DATA_PAYLOAD_T ) ); salineBolusBroadcastTimerCtr = 0; } } // ********** private function prototypes ********** /*********************************************************************//** * @brief * The handleSalineBolusIdleState function handles the idle state of the * saline bolus state machine. * @details Inputs: none * @details Outputs: * @return next saline bolus state *************************************************************************/ static SALINE_BOLUS_STATE_T handleSalineBolusIdleState( void ) { SALINE_BOLUS_STATE_T result = SALINE_BOLUS_STATE_IDLE; // Handle saline bolus start request from user if ( TRUE == salineBolusStartRequested ) { salineBolusStartRequested = FALSE; // Cmd all pumps to stop setBloodPumpTargetFlowRate( 0, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); setDialInPumpTargetFlowRate( 0, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); setDialOutPumpTargetRate( 0, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); stopSyringePump(); // Begin saline bolus result = SALINE_BOLUS_STATE_WAIT_FOR_PUMPS_STOP; } return result; } /*********************************************************************//** * @brief * The handleSalineBolusWait4Pumps2Stop function handles the wait for pumps * to stop state of the saline bolus state machine. * @details Inputs: none * @details Outputs: * @return next saline bolus state *************************************************************************/ static SALINE_BOLUS_STATE_T handleSalineBolusWait4Pumps2Stop( void ) { SALINE_BOLUS_STATE_T result = SALINE_BOLUS_STATE_WAIT_FOR_PUMPS_STOP; if ( ( FALSE == isBloodPumpRunning() ) && ( FALSE == isDialInPumpRunning() ) && ( FALSE == isDialOutPumpRunning() ) ) { // Reset bolus data before we start bolusSalineVolumeDelivered_mL = 0.0; bolusSalineLastVolumeTimeStamp = getMSTimerCount(); // Bypass dialyzer setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); // Switch to saline bag setValvePosition( VBA, VALVE_POSITION_C_CLOSE ); // Set to patient in case VBV is closed in treatment stop setValvePosition( VBV, VALVE_POSITION_B_OPEN ); // Start blood pump at saline bolus rate setBloodPumpTargetFlowRate( SALINE_BOLUS_FLOW_RATE, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); // Start dialysate inlet pump at re-circ rate setDialInPumpTargetFlowRate( DIALYSATE_FLOW_RATE_FOR_RECIRC, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); // Begin saline bolus result = SALINE_BOLUS_STATE_IN_PROGRESS; } return result; } /*********************************************************************//** * @brief * The handleSalineBolusInProgressState function handles the in-progress state of the * saline bolus state machine. * @details Inputs: none * @details Outputs: * @return next saline bolus state *************************************************************************/ static SALINE_BOLUS_STATE_T handleSalineBolusInProgressState( void ) { SALINE_BOLUS_STATE_T result = SALINE_BOLUS_STATE_IN_PROGRESS; F32 timeSinceLastVolumeUpdateMin = (F32)calcTimeSince( bolusSalineLastVolumeTimeStamp ) / (F32)( MS_PER_SECOND * SEC_PER_MIN ); F32 bolusTargetVolume = (F32)getTreatmentParameterU32( TREATMENT_PARAM_SALINE_BOLUS_VOLUME ); F32 bldFlowRate = getMeasuredBloodFlowRate(); F32 volSinceLastUpdateMl = bldFlowRate * timeSinceLastVolumeUpdateMin; F32 expVolSinceLastUpdateMl = (F32)getTargetBloodFlowRate() * timeSinceLastVolumeUpdateMin; // Update saline bolus volumes bolusSalineLastVolumeTimeStamp = getMSTimerCount(); bolusSalineVolumeDelivered_mL += volSinceLastUpdateMl; totalSalineVolumeDelivered_mL += volSinceLastUpdateMl; // Check for empty saline bag per arterial line pressure if ( TRUE == isSalineBagEmpty() ) { SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_EMPTY_SALINE_BAG, getMeasuredArterialPressure() ); result = SALINE_BOLUS_STATE_IDLE; } // Determine if bolus is complete if ( bolusSalineVolumeDelivered_mL >= bolusTargetVolume ) { result = SALINE_BOLUS_STATE_IDLE; } // User is aborting saline bolus else if ( TRUE == salineBolusAbortRequested ) { salineBolusAbortRequested = FALSE; result = SALINE_BOLUS_STATE_IDLE; } // Are we stopping the bolus? if ( result != SALINE_BOLUS_STATE_IN_PROGRESS ) { // Hard stop blood and dialysate pumps signalBloodPumpHardStop(); signalDialInPumpHardStop(); // Send last saline bolus data salineBolusBroadcastTimerCtr = SALINE_BOLUS_DATA_PUB_INTERVAL; bolusSalineVolumeDelivered_mL = 0.0; sendTreatmentLogEventData( SALINE_BOLUSES_CHANGE_EVENT, bolusSalineVolumeDelivered_mL, totalSalineVolumeDelivered_mL ); } return result; } /**@}*/