Index: firmware/App/Modes/Rinseback.c =================================================================== diff -u -r3c9724b7e07c1a82d0e7fd653a99d7cb96d06e5a -rcd5be724d5a3ba7457e761191d82f278654d7f5c --- firmware/App/Modes/Rinseback.c (.../Rinseback.c) (revision 3c9724b7e07c1a82d0e7fd653a99d7cb96d06e5a) +++ firmware/App/Modes/Rinseback.c (.../Rinseback.c) (revision cd5be724d5a3ba7457e761191d82f278654d7f5c) @@ -1,14 +1,14 @@ /************************************************************************** * -* Copyright (c) 2021-2023 Diality Inc. - All Rights Reserved. +* 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 Rinseback.c * * @author (last) Sean Nash -* @date (last) 18-Apr-2023 +* @date (last) 08-Sep-2023 * * @author (original) Sean Nash * @date (original) 20-Jan-2021 @@ -38,19 +38,20 @@ // ********** private definitions ********** -#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 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 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,6 +68,7 @@ static F32 totalAdditionalRinsebackVolume_mL; ///< Total accumulated volume (in mL) delivered so far for all additional volumes combined. static U32 rinsebackAdditionalTimerCtr; ///< Timer counter for duration of an additional rinseback delivery. static U32 rinsebackPublishTimerCtr; ///< Timer counter for determining interval for rinseback status to be published. + /// Interval (in task intervals) at which to publish rinseback data to CAN bus. static OVERRIDE_U32_T rinsebackPublishInterval = { RINSEBACK_DATA_PUBLISH_INTERVAL, RINSEBACK_DATA_PUBLISH_INTERVAL, RINSEBACK_DATA_PUBLISH_INTERVAL, 0 }; @@ -95,6 +97,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 ); @@ -121,15 +124,14 @@ { rinsebackState = RINSEBACK_STOP_INIT_STATE; rinsebackRate_mL_min = getTreatmentParameterU32( TREATMENT_PARAM_RINSEBACK_FLOW_RATE ); - rinsebackTargetVolume_mL = TUBING_BLOOD_PRIME_VOLUME_ML + (F32)getDialyzerBloodVolume(); + rinsebackTargetVolume_mL = DEFAULT_RINSEBACK_VOLUME_ML; targetRinsebackVolumePlusAdditional_mL = rinsebackTargetVolume_mL; rinsebackTimerCtr = 0; cumulativeRinsebackVolume_mL.data = 0.0; additionalRinsebackVolume_mL = 0.0; totalAdditionalRinsebackVolume_mL = 0.0; rinsebackAdditionalTimerCtr = 0; rinsebackPublishTimerCtr = 0; - rinsebackTargetVolume_mL = DEFAULT_RINSEBACK_VOLUME_ML; resetRinsebackFlags(); } @@ -165,6 +167,7 @@ void transitionToRinseback( void ) { initRinseback(); + setCurrentSubState( (U32)rinsebackState ); doorClosedRequired( TRUE, TRUE ); @@ -280,12 +283,6 @@ rinsebackTimerCtr++; - // Check for user confirmation of end treatment - if ( CONFIRMATION_REQUEST_STATUS_ACCEPTED == getConfirmationRequestStatus( GENERIC_CONFIRM_ID_TREATMENT_END ) ) - { - endTreatmentRequested = TRUE; - } - switch ( rinsebackState ) { case RINSEBACK_STOP_INIT_STATE: @@ -308,6 +305,10 @@ 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; @@ -318,6 +319,7 @@ 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 @@ -342,6 +344,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 ); @@ -392,13 +397,19 @@ // 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(); @@ -449,8 +460,9 @@ * @brief * The handleRinsebackPausedState function handles the rinseback paused * state operations. - * @details Inputs: flags - * @details Outputs: flags handled + * @details Inputs: rinsebackTimerCtr, resumeRinsebackRequested, + * endTreatmentRequested, endRinsebackRequested, rinsebackRate_mL_min + * @details Outputs: targetRinsebackVolumePlusAdditional_mL * @return next rinseback state *************************************************************************/ static RINSEBACK_STATE_T handleRinsebackPausedState( void ) @@ -468,9 +480,16 @@ 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; } @@ -482,8 +501,10 @@ * @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 ) @@ -509,13 +530,14 @@ 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 ) { @@ -554,8 +576,9 @@ 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; } @@ -588,6 +611,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 @@ -791,7 +855,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 *************************************************************************/ @@ -804,6 +868,11 @@ result = TRUE; resumeRinsebackRequested = TRUE; } + else if ( RINSEBACK_RECONNECT_PATIENT_STATE == rinsebackState ) + { + result = TRUE; + resumeRinsebackRequested = TRUE; + } else { *rejReason = REQUEST_REJECT_REASON_ACTION_DISABLED_IN_CURRENT_STATE; @@ -855,7 +924,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; @@ -930,7 +999,9 @@ { *rejReason = REQUEST_REJECT_REASON_TREATMENT_CANNOT_BE_RESUMED; } - else if ( ( RINSEBACK_STOP_INIT_STATE != rinsebackState ) && ( RINSEBACK_STOP_STATE != rinsebackState ) ) + else if ( ( RINSEBACK_STOP_INIT_STATE != rinsebackState ) && + ( RINSEBACK_STOP_STATE != rinsebackState ) && + ( RINSEBACK_RECONNECT_PATIENT_STATE != rinsebackState ) ) { *rejReason = REQUEST_REJECT_REASON_ACTION_DISABLED_IN_CURRENT_STATE; } @@ -974,19 +1045,26 @@ data.targetRinsebackVolumeMl = rinsebackTargetVolume_mL; rinsebackPublishTimerCtr = 0; // If we have completed rinseback, timeout is no longer in force - indicate by zeroing timeout. Also include any additionals to target. + data.timeout = 0; + data.countdown = 0; if ( ( rinsebackState > RINSEBACK_PAUSED_STATE ) && ( getRinsebackVolume() >= rinsebackTargetVolume_mL ) ) { data.targetRinsebackVolumeMl = targetRinsebackVolumePlusAdditional_mL; - 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; + if ( getRinsebackCompleted() != TRUE ) + { + if ( rinsebackTimerCtr > 0 ) // Timer set to zero when BP is running + { + data.timeout = timeout; + data.countdown = countdown; + } + } if ( data.deliveredRinsebackVolumeMl >= rinsebackTargetVolume_mL ) { data.isCompleted = TRUE;