Index: firmware/App/Modes/Rinseback.c =================================================================== diff -u -r69ed3f91919e50b68ea448a70db81456fb4946a0 -r346e74cbf78fdf1ea7cd779103476e49c4ee190e --- firmware/App/Modes/Rinseback.c (.../Rinseback.c) (revision 69ed3f91919e50b68ea448a70db81456fb4946a0) +++ firmware/App/Modes/Rinseback.c (.../Rinseback.c) (revision 346e74cbf78fdf1ea7cd779103476e49c4ee190e) @@ -1,14 +1,14 @@ /************************************************************************** * -* Copyright (c) 2021-2022 Diality Inc. - All Rights Reserved. +* Copyright (c) 2021-2023 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 Rinseback.c * -* @author (last) Dara Navaei -* @date (last) 15-Jul-2022 +* @author (last) Sean Nash +* @date (last) 17-Jul-2023 * * @author (original) Sean Nash * @date (original) 20-Jan-2021 @@ -17,6 +17,7 @@ #include "AirTrap.h" #include "BloodFlow.h" +#include "BloodPrime.h" #include "DGInterface.h" #include "DialInFlow.h" #include "DialOutFlow.h" @@ -37,25 +38,20 @@ // ********** private definitions ********** -#define TUBING_RINSEBACK_VOLUME_ML 80.0F ///< Target rinseback volume to deliver back to the patient (in mL). -#define DEFAULT_RINSEBACK_VOLUME_ML 300.0F ///< Default rinseback volume (in mL). +#define DEFAULT_RINSEBACK_VOLUME_ML 350.0F ///< Default rinseback volume (in mL). #define MAX_TOTAL_ADDITIONAL_RINSEBACK_VOLUME_ML 300.0F ///< Maximum total additional rinseback volume allowed : all additionals (in mL). -#define MAX_RINSEBACK_VOLUME_ERROR_ML 60.0F ///< Maximum error in total additional rinseback volume (20% of total). -#define TARGET_ADDITIONAL_RINSEBACK_VOLUME_ML 10.0F ///< Target rinseback volume for an additional volume request (in mL). +#define TARGET_ADDITIONAL_RINSEBACK_VOLUME_ML 50.0F ///< Target rinseback volume for an additional volume request (in mL). #define RINSEBACK_FLOW_RATE_ADJ_ML_MIN 25 ///< Adjustment amount (in mL/min) to apply when user requests increase/decrease in flow rate. -#define MIN_RINSEBACK_FLOW_RATE_ML_MIN 50 ///< Minimum rinseback flow rate (in mL/min). -#define MAX_RINSEBACK_FLOW_RATE_ML_MIN 150 ///< Maximum rinseback flow rate (in mL/min). +#define DEFAULT_RINSEBACK_FLOW_RATE_ML_MIN 200 ///< Default rinseback flow rate (in mL/min). +#define MIN_RINSEBACK_FLOW_RATE_ML_MIN 100 ///< Minimum rinseback flow rate (in mL/min). +#define MAX_RINSEBACK_FLOW_RATE_ML_MIN 300 ///< Maximum rinseback flow rate (in mL/min). /// Interval at which rinseback progress is to be published to UI. #define RINSEBACK_DATA_PUBLISH_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) /// Maximum time allowed for rinseback operation until full volume is delivered. Timer is reset whenever BP is running. static const U32 MAX_RINSEBACK_TIME = ( 5 * SEC_PER_MIN * ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ); -/// Maximum time allowed after rinseback operation completed. Timer is reset whenever BP is running (additional). -static const U32 MAX_RINSEBACK_DONE_TIME = ( 15 * SEC_PER_MIN * ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ); -/// Warning time after rinseback operation completed. Timer is reset whenever BP is running (additional). -static const U32 RINSEBACK_DONE_WARNING_TIME = ( 13 * SEC_PER_MIN * ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ); /// Maximum time allowed for each additional rinseback volume delivery. -static const U32 MAX_RINSEBACK_ADDITIONAL_TIME = ( 20 * MS_PER_SECOND / TASK_GENERAL_INTERVAL ); +static const U32 MAX_RINSEBACK_ADDITIONAL_TIME = ( 25 * MS_PER_SECOND / TASK_GENERAL_INTERVAL ); /// Multiplier to convert flow (mL/min) into volume (mL) for period of general task interval. static const F32 RINSEBACK_FLOW_INTEGRATOR = 1.0F / (F32)( SEC_PER_MIN * ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ); @@ -67,7 +63,6 @@ static F32 rinsebackTargetVolume_mL; ///< Calculated target rinseback volume (based on selected dialyzer and fixed tubing volume). static OVERRIDE_F32_T cumulativeRinsebackVolume_mL = { 0.0, 0.0, 0.0, 0 }; ///< Total cumulative rinseback volume (in mL) from measured blood flow rate. -static F32 expectedRinsebackVolume_mL = 0.0; ///< Total cumulative rinseback volume (in mL) expected based on target blood flow rate. static F32 targetRinsebackVolumePlusAdditional_mL; ///< Target rinseback volume w/ additional volume(s) added (in mL). static F32 additionalRinsebackVolume_mL; ///< Total volume (in mL) delivered so far for additional volume request. static F32 totalAdditionalRinsebackVolume_mL; ///< Total accumulated volume (in mL) delivered so far for all additional volumes combined. @@ -101,6 +96,7 @@ static RINSEBACK_STATE_T handleRinsebackPausedState( void ); static RINSEBACK_STATE_T handleRinsebackStoppedState( void ); static RINSEBACK_STATE_T handleRinsebackRunAdditionalState( void ); +static RINSEBACK_STATE_T handleRinsebackReconnectPatientState( void ); static BOOL handleStartRinsebackUserAction( REQUEST_REJECT_REASON_CODE_T *rejReason ); static BOOL handleIncrRinsebackUserAction( REQUEST_REJECT_REASON_CODE_T *rejReason ); @@ -111,10 +107,10 @@ static BOOL handleAdditionalRinsebackUserAction( REQUEST_REJECT_REASON_CODE_T *rejReason ); static BOOL handleToRecircUserAction( REQUEST_REJECT_REASON_CODE_T *rejReason ); static BOOL handleBackToTreatmentUserAction( REQUEST_REJECT_REASON_CODE_T *rejReason ); -static BOOL handleEndTreatmentUserAction( REQUEST_REJECT_REASON_CODE_T *rejReason ); static void publishRinsebackData( void ); static U32 getPublishRinsebackInterval( void ); +static void handleDialysateRecircOnOff( void ); /*********************************************************************//** * @brief @@ -127,16 +123,14 @@ { rinsebackState = RINSEBACK_STOP_INIT_STATE; rinsebackRate_mL_min = getTreatmentParameterU32( TREATMENT_PARAM_RINSEBACK_FLOW_RATE ); - rinsebackTargetVolume_mL = TUBING_RINSEBACK_VOLUME_ML + (F32)getDialyzerBloodVolume(); + rinsebackTargetVolume_mL = DEFAULT_RINSEBACK_VOLUME_ML; targetRinsebackVolumePlusAdditional_mL = rinsebackTargetVolume_mL; rinsebackTimerCtr = 0; cumulativeRinsebackVolume_mL.data = 0.0; - expectedRinsebackVolume_mL = 0.0; additionalRinsebackVolume_mL = 0.0; totalAdditionalRinsebackVolume_mL = 0.0; rinsebackAdditionalTimerCtr = 0; rinsebackPublishTimerCtr = 0; - rinsebackTargetVolume_mL = DEFAULT_RINSEBACK_VOLUME_ML; resetRinsebackFlags(); } @@ -172,6 +166,7 @@ void transitionToRinseback( void ) { initRinseback(); + setCurrentSubState( (U32)rinsebackState ); doorClosedRequired( TRUE, TRUE ); @@ -193,7 +188,7 @@ 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, 0.0F ); + setDialInPumpTargetFlowRate( DIALYSATE_FLOW_RATE_FOR_RECIRC, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); cmdStartDGTrimmerHeater(); } @@ -216,6 +211,9 @@ setBloodPumpTargetFlowRate( rate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); // Start air trap leveling control startAirTrapControl(); + // 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(); } /*********************************************************************//** @@ -275,11 +273,13 @@ * @brief * The execRinseback function executes the Rinseback sub-mode state machine. * @details Inputs: rinsebackState - * @details Outputs: rinsebackState, rinsebackTimerCtr, flags + * @details Outputs: rinsebackState, rinsebackTimerCtr, endTreatmentRequested, flags * @return none *************************************************************************/ void execRinseback( void ) { + RINSEBACK_STATE_T priorSubState = rinsebackState; + rinsebackTimerCtr++; switch ( rinsebackState ) @@ -304,11 +304,23 @@ rinsebackState = handleRinsebackRunAdditionalState(); break; + case RINSEBACK_RECONNECT_PATIENT_STATE: + rinsebackState = handleRinsebackReconnectPatientState(); + break; + default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_RINSEBACK_INVALID_STATE, rinsebackState ); break; } + // Start/stop dialysate recirculation during rinseback mode based on active alarms that would block it + handleDialysateRecircOnOff(); + + if ( priorSubState != rinsebackState ) + { + setCurrentSubState( (U32)rinsebackState ); + SEND_EVENT_WITH_2_U32_DATA( HD_EVENT_SUB_STATE_CHANGE, priorSubState, rinsebackState ); + } // Rinseback flags should be handled by now - reset in case not handled by current state resetRinsebackFlags(); @@ -331,6 +343,9 @@ // Has user requested rinseback start? if ( TRUE == startRinsebackRequested ) { + setAlarmUserActionEnabled( ALARM_USER_ACTION_RESUME, TRUE ); + setAlarmUserActionEnabled( ALARM_USER_ACTION_RINSEBACK, FALSE ); + setAlarmUserActionEnabled( ALARM_USER_ACTION_END_TREATMENT, TRUE ); if ( isTreatmentCompleted() != TRUE ) { sendTreatmentLogEventData( MID_TREATMENT_RINSE_BACK_EVENT, 0.0, rinsebackRate_mL_min ); @@ -354,7 +369,7 @@ else if ( rinsebackTimerCtr > MAX_RINSEBACK_TIME ) { signalGoToTreatmentStopped(); - activateAlarmNoData( ALARM_ID_TREATMENT_RINSEBACK_TIMEOUT_ALARM ); + activateAlarmNoData( ALARM_ID_HD_TREATMENT_RINSEBACK_TIMEOUT_ALARM ); } return result; @@ -377,18 +392,23 @@ // Update rinseback volume delivered so far cumulativeRinsebackVolume_mL.data += ( getMeasuredBloodFlowRate() * RINSEBACK_FLOW_INTEGRATOR ); - expectedRinsebackVolume_mL += ( (F32)getTargetBloodFlowRate() * RINSEBACK_FLOW_INTEGRATOR ); // Has user requested to end rinseback? if ( TRUE == endRinsebackRequested ) { + setAlarmUserActionEnabled( ALARM_USER_ACTION_RESUME, FALSE ); + setAlarmUserActionEnabled( ALARM_USER_ACTION_RINSEBACK, FALSE ); + setAlarmUserActionEnabled( ALARM_USER_ACTION_END_TREATMENT, FALSE ); setupForRinsebackStopOrPause(); targetRinsebackVolumePlusAdditional_mL = getRinsebackVolume(); result = RINSEBACK_STOP_STATE; } // Has rinseback completed? else if ( getRinsebackVolume() >= rinsebackTargetVolume_mL ) { + setAlarmUserActionEnabled( ALARM_USER_ACTION_RESUME, FALSE ); + setAlarmUserActionEnabled( ALARM_USER_ACTION_RINSEBACK, FALSE ); + setAlarmUserActionEnabled( ALARM_USER_ACTION_END_TREATMENT, FALSE ); setRinsebackIsCompleted( TRUE ); setupForRinsebackStopOrPause(); targetRinsebackVolumePlusAdditional_mL = getRinsebackVolume(); @@ -397,7 +417,7 @@ // Check for empty saline bag if ( TRUE == isSalineBagEmpty() ) { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_EMPTY_SALINE_BAG, getMeasuredArterialPressure() ); + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_EMPTY_SALINE_BAG, getMeasuredArterialPressure() ); setupForRinsebackStopOrPause(); result = RINSEBACK_PAUSED_STATE; } @@ -407,19 +427,6 @@ setupForRinsebackStopOrPause(); result = RINSEBACK_PAUSED_STATE; } - // Is rinseback taking too long? - else if ( fabs( expectedRinsebackVolume_mL - getRinsebackVolume() ) > MAX_RINSEBACK_VOLUME_ERROR_ML ) - { -#ifndef _RELEASE_ - if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_FLOW_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) -#endif - { - setRinsebackIsCompleted( TRUE ); - setupForRinsebackStopOrPause(); - activateAlarmNoData( ALARM_ID_RINSEBACK_VOLUME_CHECK_FAILURE ); - result = RINSEBACK_STOP_STATE; - } - } // Otherwise, continue rinseback else { // Has user requested rate change? @@ -464,16 +471,23 @@ if ( rinsebackTimerCtr > MAX_RINSEBACK_TIME ) { signalGoToTreatmentStopped(); - activateAlarmNoData( ALARM_ID_TREATMENT_RINSEBACK_TIMEOUT_ALARM ); + activateAlarmNoData( ALARM_ID_HD_TREATMENT_RINSEBACK_TIMEOUT_ALARM ); } else if ( TRUE == resumeRinsebackRequested ) { setupForRinsebackDelivery( rinsebackRate_mL_min ); result = RINSEBACK_RUN_STATE; } + else if ( TRUE == endTreatmentRequested ) + { + signalEndTreatment(); + } // Has user requested to end rinseback? else if ( TRUE == endRinsebackRequested ) { + setAlarmUserActionEnabled( ALARM_USER_ACTION_RESUME, FALSE ); + setAlarmUserActionEnabled( ALARM_USER_ACTION_RINSEBACK, FALSE ); + setAlarmUserActionEnabled( ALARM_USER_ACTION_END_TREATMENT, FALSE ); targetRinsebackVolumePlusAdditional_mL = getRinsebackVolume(); result = RINSEBACK_STOP_STATE; } @@ -485,31 +499,21 @@ * @brief * The handleRinsebackStoppedState function handles the stopped rinseback * state operations. - * @details Inputs: flags - * @details Outputs: flags handled + * @details Inputs: rinsebackTimerCtr, recircRequested, additionalRinsebackRequested, + * backToTreatmentRequested, endTreatmentRequested + * @details Outputs: additionalRinsebackRequested, rinsebackAdditionalTimerCtr, + * additionalRinsebackVolume_mL, targetRinsebackVolumePlusAdditional_mL * @return next rinseback state *************************************************************************/ static RINSEBACK_STATE_T handleRinsebackStoppedState( void ) { RINSEBACK_STATE_T result = RINSEBACK_STOP_STATE; - // Have we been in this stopped state for too long despite having delivered full blood volume back to patient? - if ( ( rinsebackTimerCtr > MAX_RINSEBACK_DONE_TIME ) && ( getRinsebackVolume() >= rinsebackTargetVolume_mL ) ) - { - signalGoToTreatmentStopped(); - activateAlarmNoData( ALARM_ID_TREATMENT_RINSEBACK_TIMEOUT_ALARM ); - clearAlarm( ALARM_ID_HD_TREATMENT_RINSEBACK_TIMEOUT_WARNING ); - } - // Have we been in this stopped state for too long despite having delivered full blood volume back to patient? - else if ( ( RINSEBACK_DONE_WARNING_TIME == rinsebackTimerCtr ) && ( getRinsebackVolume() >= rinsebackTargetVolume_mL ) ) - { - activateAlarmNoData( ALARM_ID_HD_TREATMENT_RINSEBACK_TIMEOUT_WARNING ); - } // Have we been in this stopped state for too long w/o having delivered full blood volume back to patient? - else if ( ( rinsebackTimerCtr > MAX_RINSEBACK_TIME ) && ( getRinsebackVolume() < rinsebackTargetVolume_mL ) ) + if ( ( rinsebackTimerCtr > MAX_RINSEBACK_TIME ) && ( getRinsebackVolume() < rinsebackTargetVolume_mL ) ) { signalGoToTreatmentStopped(); - activateAlarmNoData( ALARM_ID_TREATMENT_RINSEBACK_TIMEOUT_ALARM ); + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_TREATMENT_RINSEBACK_TIMEOUT_ALARM, rinsebackTimerCtr, MAX_RINSEBACK_TIME ); } else if ( TRUE == recircRequested ) { @@ -518,19 +522,20 @@ else if ( TRUE == additionalRinsebackRequested ) { additionalRinsebackRequested = FALSE; - // deliver additional rinseback volume only if max volume not reached and max time not reached + // deliver additional rinseback volume only if max time not reached or max volume has been reached (i.e. no more blood in line) if ( ( rinsebackTimerCtr < MAX_RINSEBACK_TIME ) || ( getRinsebackVolume() >= rinsebackTargetVolume_mL ) ) { rinsebackAdditionalTimerCtr = 0; additionalRinsebackVolume_mL = 0.0; targetRinsebackVolumePlusAdditional_mL += TARGET_ADDITIONAL_RINSEBACK_VOLUME_ML; - setupForRinsebackDelivery( MIN_RINSEBACK_FLOW_RATE_ML_MIN ); + rinsebackRate_mL_min = DEFAULT_RINSEBACK_FLOW_RATE_ML_MIN; + setupForRinsebackDelivery( rinsebackRate_mL_min ); result = RINSEBACK_RUN_ADDITIONAL_STATE; } } else if ( TRUE == backToTreatmentRequested ) { - signalGoToTreatmentStopped(); + result = RINSEBACK_RECONNECT_PATIENT_STATE; } else if ( TRUE == endTreatmentRequested ) { @@ -565,12 +570,13 @@ // Check for empty saline bag if ( TRUE == isSalineBagEmpty() ) { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_EMPTY_SALINE_BAG, getMeasuredArterialPressure() ); + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_EMPTY_SALINE_BAG, getMeasuredArterialPressure() ); targetRinsebackVolumePlusAdditional_mL = getRinsebackVolume(); result = RINSEBACK_STOP_STATE; } - // Has additional rinseback completed - else if ( additionalRinsebackVolume_mL >= TARGET_ADDITIONAL_RINSEBACK_VOLUME_ML ) + // Has additional rinseback completed or max additional volume reached + else if ( ( additionalRinsebackVolume_mL >= TARGET_ADDITIONAL_RINSEBACK_VOLUME_ML ) || + ( totalAdditionalRinsebackVolume_mL >= MAX_TOTAL_ADDITIONAL_RINSEBACK_VOLUME_ML ) ) { result = RINSEBACK_STOP_STATE; } @@ -603,6 +609,47 @@ /*********************************************************************//** * @brief + * The handleRinsebackReconnectPatientState function handles the rinseback + * reconnect patient state operations. + * @details Inputs: flags + * @details Outputs: flags handled + * @return next rinseback state + *************************************************************************/ +static RINSEBACK_STATE_T handleRinsebackReconnectPatientState( void ) +{ + RINSEBACK_STATE_T result = RINSEBACK_RECONNECT_PATIENT_STATE; + + if ( TRUE == resumeRinsebackRequested ) + { + result = RINSEBACK_STOP_STATE; + } + else if ( TRUE == backToTreatmentRequested ) + { + signalGoToTreatmentStopped(); + } + else if ( TRUE == endTreatmentRequested ) + { + signalEndTreatment(); + } + + return result; +} + +/*********************************************************************//** + * @brief + * The signalRinsebackAlarmResumeUserAction function signals the rinseback + * sub-mode to resume per user alarm action. + * @details Inputs: none + * @details Outputs: resumeRinsebackRequested + * @return none + *************************************************************************/ +void signalRinsebackAlarmResumeUserAction( void ) +{ + resumeRinsebackRequested = TRUE; +} + +/*********************************************************************//** + * @brief * The signalRinsebackUserAction function signals a rinseback user action * has been requested. The request is handled and responded to. * @details Inputs: none @@ -653,7 +700,9 @@ break; case REQUESTED_USER_ACTION_RINSEBACK_END_TREATMENT: - accepted = handleEndTreatmentUserAction( &rejReason ); + // Send message to UI to get user confirmation to end treatment - action initiated only upon receipt of user confirmation from UI + addConfirmationRequest( GENERIC_CONFIRM_ID_TREATMENT_END, GENERIC_CONFIRM_CMD_REQUEST_OPEN, 0 ); + accepted = TRUE; break; case REQUESTED_USER_ACTION_RINSEBACK_BACK_TO_TREATMENT: @@ -804,7 +853,7 @@ * user action request. It is assumed that the calling function will set * the reject reason parameter to None beforehand. * @details Inputs: rinsebackState - * @details Outputs: rinseback resumed if appropriate + * @details Outputs: resumeRinsebackRequested * @param rejReason Code indicating reason for rejection * @return TRUE if user action accepted, FALSE if not *************************************************************************/ @@ -814,6 +863,18 @@ if ( RINSEBACK_PAUSED_STATE == rinsebackState ) { + if ( getNoRetriggerFlag() != TRUE ) + { + result = TRUE; + resumeRinsebackRequested = TRUE; + } + else + { + *rejReason = REQUEST_REJECT_REASON_TREATMENT_CANNOT_BE_RESUMED; + } + } + else if ( RINSEBACK_RECONNECT_PATIENT_STATE == rinsebackState ) + { result = TRUE; resumeRinsebackRequested = TRUE; } @@ -868,7 +929,7 @@ if ( RINSEBACK_STOP_STATE == rinsebackState ) { - if ( ( totalAdditionalRinsebackVolume_mL + TARGET_ADDITIONAL_RINSEBACK_VOLUME_ML ) <= MAX_TOTAL_ADDITIONAL_RINSEBACK_VOLUME_ML ) + if ( totalAdditionalRinsebackVolume_mL < MAX_TOTAL_ADDITIONAL_RINSEBACK_VOLUME_ML ) { result = TRUE; additionalRinsebackRequested = TRUE; @@ -904,7 +965,7 @@ { *rejReason = REQUEST_REJECT_REASON_TREATMENT_IS_COMPLETED; } - else if ( RINSEBACK_STOP_STATE != rinsebackState ) + else if ( rinsebackState != RINSEBACK_STOP_STATE ) { *rejReason = REQUEST_REJECT_REASON_ACTION_DISABLED_IN_CURRENT_STATE; } @@ -939,41 +1000,20 @@ { *rejReason = REQUEST_REJECT_REASON_TREATMENT_IS_COMPLETED; } - else if ( ( RINSEBACK_STOP_INIT_STATE != rinsebackState ) && ( RINSEBACK_STOP_STATE != rinsebackState ) ) + else if ( TRUE == isTreatmentResumeBlocked() ) { - *rejReason = REQUEST_REJECT_REASON_ACTION_DISABLED_IN_CURRENT_STATE; + *rejReason = REQUEST_REJECT_REASON_TREATMENT_CANNOT_BE_RESUMED; } - else + else if ( ( RINSEBACK_STOP_INIT_STATE != rinsebackState ) && + ( RINSEBACK_STOP_STATE != rinsebackState ) && + ( RINSEBACK_RECONNECT_PATIENT_STATE != rinsebackState ) ) { - result = TRUE; - backToTreatmentRequested = TRUE; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The handleEndTreatmentUserAction function handles an end treatment - * user action request. It is assumed that the calling function will set - * the reject reason parameter to None beforehand. - * @details Inputs: rinsebackState - * @details Outputs: end treatment if appropriate - * @param rejReason Code indicating reason for rejection - * @return TRUE if user action accepted, FALSE if not - *************************************************************************/ -static BOOL handleEndTreatmentUserAction( REQUEST_REJECT_REASON_CODE_T *rejReason ) -{ - BOOL result = FALSE; - - if ( ( RINSEBACK_STOP_INIT_STATE != rinsebackState ) && ( RINSEBACK_STOP_STATE != rinsebackState ) ) - { *rejReason = REQUEST_REJECT_REASON_ACTION_DISABLED_IN_CURRENT_STATE; } else { result = TRUE; - endTreatmentRequested = TRUE; + backToTreatmentRequested = TRUE; } return result; @@ -993,12 +1033,14 @@ if ( ++rinsebackPublishTimerCtr >= getPublishRinsebackInterval() ) { RINSEBACK_DATA_PAYLOAD_T data; + TREATMENT_STOP_PAYLOAD_T sdata; U32 timeout = MAX_RINSEBACK_TIME / ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ); - U32 countdown = ( getRinsebackVolume() >= rinsebackTargetVolume_mL ? MAX_RINSEBACK_DONE_TIME : MAX_RINSEBACK_TIME ); + U32 countdown = ( getRinsebackVolume() >= rinsebackTargetVolume_mL ? 0 : MAX_RINSEBACK_TIME ); + U32 stopTO = ( getRinsebackVolume() >= rinsebackTargetVolume_mL ? 0 : MAX_RINSEBACK_TIME ); countdown -= rinsebackTimerCtr; // Handle countdown past zero - if ( countdown > MAX_RINSEBACK_DONE_TIME ) + if ( countdown > MAX_RINSEBACK_TIME ) { countdown = 0; } @@ -1011,13 +1053,13 @@ if ( ( rinsebackState > RINSEBACK_PAUSED_STATE ) && ( getRinsebackVolume() >= rinsebackTargetVolume_mL ) ) { data.targetRinsebackVolumeMl = targetRinsebackVolumePlusAdditional_mL; - timeout = MAX_RINSEBACK_DONE_TIME / ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ); + timeout = 0; } data.deliveredRinsebackVolumeMl = getRinsebackVolume(); data.rinsebackFlowRateMlMin = rinsebackRate_mL_min; if ( RINSEBACK_RUN_ADDITIONAL_STATE == rinsebackState ) { - data.rinsebackFlowRateMlMin = MIN_RINSEBACK_FLOW_RATE_ML_MIN; + data.rinsebackFlowRateMlMin = DEFAULT_RINSEBACK_FLOW_RATE_ML_MIN; } data.timeout = timeout; data.countdown = countdown; @@ -1026,6 +1068,19 @@ data.isCompleted = TRUE; } broadcastData( MSG_ID_HD_RINSEBACK_PROGRESS, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( RINSEBACK_DATA_PAYLOAD_T ) ); + + // Send blood sitting count down to UI for alarm dialog + sdata.timeout = stopTO / ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ); + sdata.countdown = 0; + + if ( getRinsebackCompleted() != TRUE ) + { + if ( rinsebackTimerCtr > 0 ) + { + sdata.countdown = ( rinsebackTimerCtr > MAX_TIME_BLOOD_SITTING ? 0 : ( MAX_TIME_BLOOD_SITTING - rinsebackTimerCtr ) / ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ); + } + } + broadcastData( MSG_ID_HD_TREATMENT_STOP_TIMER_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&sdata, sizeof( TREATMENT_STOP_PAYLOAD_T ) ); } } @@ -1049,7 +1104,30 @@ return result; } +/*********************************************************************//** + * @brief + * The handleDialysateRecircOnOff function starts/stops dialysate recirculation + * during rinseback sub-mode based on active alarm properties. + * @details Inputs: none + * @details Outputs: dialysate recirculation started or stopped as appropriate + * @return none + *************************************************************************/ +static void handleDialysateRecircOnOff( void ) +{ + // Stop dialysate recirc if blocked by alarm + if ( ( TRUE == isDialysateRecircBlocked() ) && ( TRUE == isDialInPumpRunning() ) ) + { + signalDialInPumpHardStop(); + cmdStopDGTrimmerHeater(); + } + else if ( ( isDialysateRecircBlocked() != TRUE ) && ( isDialInPumpRunning() != TRUE ) ) + { + setDialInPumpTargetFlowRate( DIALYSATE_FLOW_RATE_FOR_RECIRC, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); + cmdStartDGTrimmerHeater(); + } +} + /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/