Index: firmware/App/Modes/ModeTreatment.c =================================================================== diff -u -rc0a3d31ab3850e0d355eea3076dd9f7268b30f91 -raf0702a1166af3dcae57506d922f81038d65e0af --- firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision c0a3d31ab3850e0d355eea3076dd9f7268b30f91) +++ firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision af0702a1166af3dcae57506d922f81038d65e0af) @@ -8,7 +8,7 @@ * @file ModeTreatment.c * * @author (last) Sean Nash -* @date (last) 28-Mar-2023 +* @date (last) 16-Jun-2023 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 @@ -104,6 +104,7 @@ static BOOL bloodPrimeToDialysisRequest; ///< Flag indicates blood prime has completed and time to start dialysis. static BOOL rinsebackToRecircRequest; ///< Flag indicates user has requested to proceed to re-circulate sub-mode. static BOOL treatmentEndToRinsebackRequest; ///< Flag indicates user has requested final rinseback. +static BOOL resumeBlockedByAlarm; ///< Flag indicates an alarm has blocked resume of this treatment. static U32 pendingParamChangesTimer; ///< User required to confirm UF volume change within 1 minute. static F32 pendingUFVolumeChange; ///< An ultrafiltration volume change (mL) is pending user confirmation. @@ -127,7 +128,6 @@ static U32 treatmentStartTimeStamp; ///< Treatment start timestampt for logging purpose. static U32 treatmentEndTimeStamp; ///< Treatment end timestampt for logging purpose. -static BOOL hasTreatmentStartTimeBeenWrittenToNV; ///< Boolean flag to indicate whether treatment start time has been started or not. // ********** private function prototypes ********** @@ -158,6 +158,7 @@ bloodIsPrimed = FALSE; treatmentCompleted = FALSE; rinsebackDone = FALSE; + resumeBlockedByAlarm = FALSE; treatmentTimeMS = 0; lastTreatmentTimeStamp = 0; @@ -193,7 +194,6 @@ treatmentStartTimeStamp = getRTCTimestamp(); treatmentEndTimeStamp = 0; - hasTreatmentStartTimeBeenWrittenToNV = FALSE; } /*********************************************************************//** @@ -205,17 +205,27 @@ *************************************************************************/ U32 transitionToTreatmentMode( void ) { - // Initialize treatment mode each time we transition to it - initTreatmentMode(); - initReservoirs(); - // Initialize treatment sub-modes each time we transition to treatment mode - initBloodPrime(); - initDialysis(); - initTreatmentStop(); - initRinseback(); - initTreatmentRecirc(); - initTreatmentEnd(); + if ( ( getTestConfigStatus( TEST_CONFIG_RECOVER_TREATMENT ) != TRUE ) || ( getPreviousOperationMode() != DG_MODE_FAUL ) ) + { + // Initialize treatment mode each time we transition to it + initTreatmentMode(); + initReservoirs(); + // Initialize treatment sub-modes each time we transition to treatment mode + initBloodPrime(); + initDialysis(); + initTreatmentStop(); + initRinseback(); + initTreatmentRecirc(); + initTreatmentEnd(); + } + // Started the treatment set the start time in epoch + setTxLastStartTimeEpoch( getRTCTimestamp() ); + + setCurrentSubState( NO_SUB_STATE ); + // Enable venous bubble detection in treatment mode + setVenousBubbleDetectionEnabled( TRUE ); + return currentTreatmentState; } @@ -246,6 +256,19 @@ /*********************************************************************//** * @brief + * The isTreatmentResumeBlocked function determines whether the treatment has + * seen an alarm that prevents resumption. + * @details Inputs: resumeBlockedByAlarm + * @details Outputs: none + * @return resumeBlockedByAlarm + *************************************************************************/ +BOOL isTreatmentResumeBlocked( void ) +{ + return resumeBlockedByAlarm; +} + +/*********************************************************************//** + * @brief * The getTreatmentTimeRemainingSecs function determines the number of seconds * remaining in the treatment. * @details Inputs: presTreatmentTimeSecs, treatmentTimeMS @@ -592,22 +615,21 @@ // Trigger user stop alarm at any time in treatment mode when user presses stop button if ( TRUE == stop ) { - activateAlarmNoData( ALARM_ID_TREATMENT_STOPPED_BY_USER ); + activateAlarmNoData( ALARM_ID_HD_TREATMENT_STOPPED_BY_USER ); } + // Check if resume treatment blocked by alarm + if ( TRUE == doesAlarmIndicateNoResume() ) + { + resumeBlockedByAlarm = TRUE; + } + // Check dialysate temperature during treatment mode (except end state where treatment is over, dialyzer is bypassed and temp is no longer an issue) if ( currentTreatmentState != TREATMENT_END_STATE ) { checkDialysateTemperature(); } - // Record treatment start time if not done yet - if ( FALSE == hasTreatmentStartTimeBeenWrittenToNV ) - { - // Started the treatment set the start time in epoch - hasTreatmentStartTimeBeenWrittenToNV = setTxLastStartTimeEpoch( getRTCTimestamp() ); - } - // Treatment mode state machine switch ( currentTreatmentState ) { @@ -764,7 +786,7 @@ treatmentEndTimeStamp = getRTCTimestamp(); stopDialysis(); transitionToTreatmentEnd(); - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_END_OF_TREATMENT_WARNING, presTreatmentTimeSecs ); + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_END_OF_TREATMENT_WARNING, presTreatmentTimeSecs ); result = TREATMENT_END_STATE; } // Otherwise, execute state machine for treatment dialysis sub-mode @@ -812,6 +834,7 @@ transitionToBloodPrime(); result = TREATMENT_BLOOD_PRIME_STATE; } + signalUserRateChange(); // so pressure limits re-stabilize } // If user requests rinseback, go to rinseback else if ( TRUE == initiateRinsebackAlarmResponseRequest ) @@ -851,16 +874,33 @@ * @brief * The handleTreatmentRinsebackState function executes the rinseback state of the * Treatment Mode state machine. - * @details Inputs: none - * @details Outputs: treatment rinseback sub-mode executed. + * @details Inputs: endTreatmentAlarmResponseRequest, resumeTreatmentAlarmResponseRequest, + * rinsebackToRecircRequest, rinsebackToStoppedRequest, endTreatmentRequest + * @details Outputs: treatment rinseback sub-mode executed, sendLastTreatmentPeriodicData * @return next treatment mode state *************************************************************************/ static TREATMENT_STATE_T handleTreatmentRinsebackState( void ) { TREATMENT_STATE_T result = TREATMENT_RINSEBACK_STATE; - // Execute treatment rinseback sub-mode - execRinseback(); + // If user requests treatment end, end treatment + if ( TRUE == endTreatmentAlarmResponseRequest ) + { + sendLastTreatmentPeriodicData = TRUE; + requestNewOperationMode( MODE_POST ); + } + // Otherwise execute state machine for treatment rinseback sub-mode + else + { + // If user requests resumption of treatment, resume rinseback + if ( TRUE == resumeTreatmentAlarmResponseRequest ) + { + resumeTreatmentAlarmResponseRequest = FALSE; + signalRinsebackAlarmResumeUserAction(); + } + // Execute treatment rinseback sub-mode + execRinseback(); + } // Handle signals from rinseback sub-mode if ( TRUE == rinsebackToRecircRequest ) @@ -1243,6 +1283,11 @@ result = TRUE; sendTreatmentLogEventData( BLOOD_FLOW_RATE_CHANGE_EVENT, getTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW ), bloodRate ); sendTreatmentLogEventData( DIALYSATE_FLOW_RATE_CHANGE_EVENT, getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), dialRate ); + if ( ( bloodRate != (U32)getTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW ) ) || + ( dialRate != (U32)getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ) ) ) + { + signalUserRateChange(); + } // Set to new rates setTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW, bloodRate ); setTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW, dialRate ); @@ -1291,97 +1336,64 @@ BOOL verifyPressureLimitsChange( PRESSURE_LIMIT_CHANGE_REQUEST_T *data ) { BOOL result = TRUE; - CRITICAL_DATAS_T proposedNewArtLowLimit, proposedNewArtHighLimit; - CRITICAL_DATAS_T proposedNewVenLowLimit, proposedNewVenHighLimit; - PRESSURE_LIMIT_CHANGE_RESPONSE_T respRecord = { FALSE, 0, 0, 0, 0, 0 }; + CRITICAL_DATAS_T proposedNewArtLimitWindow; + CRITICAL_DATAS_T proposedNewVenLimitWindow; + CRITICAL_DATAS_T proposedNewVenLimitAsymmetric; + PRESSURE_LIMIT_CHANGE_RESPONSE_T respRecord = { FALSE, 0, 0, 0 }; - proposedNewArtLowLimit.sInt = data->artLowLimit; - proposedNewArtHighLimit.sInt = data->artHighLimit; - proposedNewVenLowLimit.sInt = data->venLowLimit; - proposedNewVenHighLimit.sInt = data->venHighLimit; + proposedNewArtLimitWindow.sInt = data->artPresLimitWindowmmHg; + proposedNewVenLimitWindow.sInt = data->venPresLimitWindowmmHg; + proposedNewVenLimitAsymmetric.sInt = data->venPresLimitAsymmetricmmHg; // Check ranges for changed limits - if ( FALSE == isTreatmentParamInRange( TREATMENT_PARAM_ART_PRESSURE_LOW_LIMIT, proposedNewArtLowLimit ) ) + if ( FALSE == isTreatmentParamInRange( TREATMENT_PARAM_ART_PRES_LIMIT_WINDOW, proposedNewArtLimitWindow ) ) { respRecord.rejReasonCode = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; result = FALSE; } - if ( FALSE == isTreatmentParamInRange( TREATMENT_PARAM_ART_PRESSURE_HIGH_LIMIT, proposedNewArtHighLimit ) ) + if ( FALSE == isTreatmentParamInRange( TREATMENT_PARAM_VEN_PRES_LIMIT_WINDOW, proposedNewVenLimitWindow ) ) { respRecord.rejReasonCode = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; result = FALSE; } - if ( FALSE == isTreatmentParamInRange( TREATMENT_PARAM_VEN_PRESSURE_LOW_LIMIT, proposedNewVenLowLimit ) ) + if ( FALSE == isTreatmentParamInRange( TREATMENT_PARAM_VEN_PRES_LIMIT_ASYMMETRIC, proposedNewVenLimitAsymmetric ) ) { respRecord.rejReasonCode = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; result = FALSE; } - if ( FALSE == isTreatmentParamInRange( TREATMENT_PARAM_VEN_PRESSURE_HIGH_LIMIT, proposedNewVenHighLimit ) ) - { - respRecord.rejReasonCode = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; - result = FALSE; - } - // If ranges ok, check separation between low/high limits - if ( TRUE == result ) - { - S32 arterialPresLimitDelta = data->artHighLimit - data->artLowLimit; - S32 venousPresLimitDelta = data->venHighLimit - data->venLowLimit; - - // Check arterial alarm limits dependency - if ( arterialPresLimitDelta < MIN_PRESSURE_ALARM_LIMIT_DELTA_MMHG ) - { - respRecord.rejReasonCode = REQUEST_REJECT_REASON_ARTERIAL_PRESSURE_LOW_VS_HIGH; - result = FALSE; - } - - // Check venous alarm limits dependency - if ( venousPresLimitDelta < MIN_PRESSURE_ALARM_LIMIT_DELTA_MMHG ) - { - respRecord.rejReasonCode = REQUEST_REJECT_REASON_VENOUS_PRESSURE_LOW_VS_HIGH; - result = FALSE; - } - } - // Set overall result - are changes accepted? respRecord.accepted = result; // If changes accepted, set new pressure limits if ( TRUE == result ) { - S32 const artLowLimit = getTreatmentParameterS32( TREATMENT_PARAM_ART_PRESSURE_LOW_LIMIT ); - S32 const artHighLimit = getTreatmentParameterS32( TREATMENT_PARAM_ART_PRESSURE_HIGH_LIMIT ); - S32 const venLowLimit = getTreatmentParameterS32( TREATMENT_PARAM_VEN_PRESSURE_LOW_LIMIT ); - S32 const venHighLimit = getTreatmentParameterS32( TREATMENT_PARAM_VEN_PRESSURE_HIGH_LIMIT ); + S32 artLimitWindow = getTreatmentParameterS32( TREATMENT_PARAM_ART_PRES_LIMIT_WINDOW ); + S32 venLimitWindow = getTreatmentParameterS32( TREATMENT_PARAM_VEN_PRES_LIMIT_WINDOW ); + S32 venLimitAsymmetric = getTreatmentParameterS32( TREATMENT_PARAM_VEN_PRES_LIMIT_ASYMMETRIC ); - setTreatmentParameterS32( TREATMENT_PARAM_ART_PRESSURE_LOW_LIMIT, data->artLowLimit ); - setTreatmentParameterS32( TREATMENT_PARAM_ART_PRESSURE_HIGH_LIMIT, data->artHighLimit ); - setTreatmentParameterS32( TREATMENT_PARAM_VEN_PRESSURE_LOW_LIMIT, data->venLowLimit ); - setTreatmentParameterS32( TREATMENT_PARAM_VEN_PRESSURE_HIGH_LIMIT, data->venHighLimit ); + setTreatmentParameterS32( TREATMENT_PARAM_ART_PRES_LIMIT_WINDOW, data->artPresLimitWindowmmHg ); + setTreatmentParameterS32( TREATMENT_PARAM_VEN_PRES_LIMIT_WINDOW, data->venPresLimitWindowmmHg ); + setTreatmentParameterS32( TREATMENT_PARAM_VEN_PRES_LIMIT_ASYMMETRIC, data->venPresLimitAsymmetricmmHg ); - if ( abs( artLowLimit - data->artLowLimit ) > 0 ) + if ( abs( artLimitWindow - data->artPresLimitWindowmmHg ) > 0 ) { - sendTreatmentLogEventData( ARTERIAL_PRESSURE_LOWER_LIMIT_CHANGE_EVENT, (F32)artLowLimit, (F32)data->artLowLimit ); + sendTreatmentLogEventData( ARTERIAL_PRESSURE_LIMIT_WINDOW_CHANGE_EVENT, (F32)artLimitWindow, (F32)data->artPresLimitWindowmmHg ); } - if ( abs( artHighLimit - data->artHighLimit ) > 0 ) + if ( abs( venLimitWindow - data->venPresLimitWindowmmHg ) > 0 ) { - sendTreatmentLogEventData( ARTERIAL_PRESSURE_UPPER_LIMIT_CHANGE_EVENT, (F32)artHighLimit, (F32)data->artHighLimit ); + sendTreatmentLogEventData( VENOUS_PRESSURE_LIMIT_WINDOW_CHANGE_EVENT, (F32)venLimitWindow, (F32)data->venPresLimitWindowmmHg ); } - if ( abs( venLowLimit - data->venLowLimit ) > 0 ) + if ( abs( venLimitAsymmetric - data->venPresLimitAsymmetricmmHg ) > 0 ) { - sendTreatmentLogEventData( VENOUS_PRESSURE_LOWER_LIMIT_CHANGE_EVENT, (F32)venLowLimit, (F32)data->venLowLimit ); + sendTreatmentLogEventData( VENOUS_PRESSURE_LIMIT_ASYM_CHANGE_EVENT, (F32)venLimitAsymmetric, (F32)data->venPresLimitAsymmetricmmHg ); } - if ( abs( venHighLimit - data->venHighLimit ) > 0 ) - { - sendTreatmentLogEventData( VENOUS_PRESSURE_UPPER_LIMIT_CHANGE_EVENT, (F32)venHighLimit, (F32)data->venHighLimit ); - } } // Read back limits for transmit to UI. - respRecord.artLowLimit = getTreatmentParameterS32( TREATMENT_PARAM_ART_PRESSURE_LOW_LIMIT ); - respRecord.artHighLimit = getTreatmentParameterS32( TREATMENT_PARAM_ART_PRESSURE_HIGH_LIMIT ); - respRecord.venLowLimit = getTreatmentParameterS32( TREATMENT_PARAM_VEN_PRESSURE_LOW_LIMIT ); - respRecord.venHighLimit = getTreatmentParameterS32( TREATMENT_PARAM_VEN_PRESSURE_HIGH_LIMIT ); + respRecord.artPresLimitWindowmmHg = getTreatmentParameterS32( TREATMENT_PARAM_ART_PRES_LIMIT_WINDOW ); + respRecord.venPresLimitWindowmmHg = getTreatmentParameterS32( TREATMENT_PARAM_VEN_PRES_LIMIT_WINDOW ); + respRecord.venPresLimitAsymmetricmmHg = getTreatmentParameterS32( TREATMENT_PARAM_VEN_PRES_LIMIT_ASYMMETRIC ); // Send response sendPressureLimitsChangeResponse( &respRecord ); @@ -1392,8 +1404,9 @@ * @brief * The broadcastTreatmentTimeAndState function broadcasts treatment time and * state data during treatment. - * @details Inputs: treatment time and state data - * @details Outputs: treatment time and state messages sent on interval + * @details Inputs: treatmentTimeBroadcastTimerCtr, elapsedTreatmentTimeInSecs, + * presTreatmentTimeSecs, treatmentStateBroadcastTimerCtr + * @details Outputs: treatmentTimeBroadcastTimerCtr, treatmentStateBroadcastTimerCtr * @return none *************************************************************************/ void broadcastTreatmentTimeAndState( void ) @@ -1409,9 +1422,18 @@ if ( isTreatmentCompleted() != TRUE ) { - data.treatmentTimePrescribedinSec = presTreatmentTimeSecs; data.treatmentTimeElapsedinSec = elapsedTreatmentTimeInSecs; - data.treatmentTimeRemaininginSec = presTreatmentTimeSecs - elapsedTreatmentTimeInSecs; + // if alarm preventing treatment resumption, treatment is essentially over and we want to indicate that with published treatment time data + if ( isTreatmentResumeBlocked() != TRUE ) + { + data.treatmentTimePrescribedinSec = presTreatmentTimeSecs; + data.treatmentTimeRemaininginSec = presTreatmentTimeSecs - elapsedTreatmentTimeInSecs; + } + else + { + data.treatmentTimePrescribedinSec = 0; + data.treatmentTimeRemaininginSec = 0; + } } broadcastData( MSG_ID_TREATMENT_TIME_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( TREATMENT_TIME_DATA_T ) ); treatmentTimeBroadcastTimerCtr = 0; @@ -1551,13 +1573,10 @@ { U32 treatmentTime = MIN_TREATMENT_TIME_MINUTES; -#ifndef _RELEASE_ - // Check if the 1 minute treatment software configuration has not been enabled - if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_ENABLE_1_MIN_TREATMENT ) ) + if ( TRUE == getTestConfigStatus( TEST_CONFIG_ENABLE_ONE_MINUTE_TREATMENT ) ) { treatmentTime = 1; } -#endif return treatmentTime; } @@ -1569,7 +1588,7 @@ * @details Outputs: non-alarm signal flags set to FALSE * @return none *************************************************************************/ -void resetSignalFlags( void ) +static void resetSignalFlags( void ) { rinsebackToStoppedRequest = FALSE; endTreatmentRequest = FALSE; @@ -1585,7 +1604,7 @@ * @details Outputs: alarm signal flags set to FALSE * @return none *************************************************************************/ -void resetAlarmSignalFlags( void ) +static void resetAlarmSignalFlags( void ) { resumeTreatmentAlarmResponseRequest = FALSE; initiateRinsebackAlarmResponseRequest = FALSE;