Index: firmware/App/Modes/ModeTreatment.c =================================================================== diff -u -r9944e4f766d9eb4cdf7a5ca7587e3ceca556e106 -rcd5be724d5a3ba7457e761191d82f278654d7f5c --- firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 9944e4f766d9eb4cdf7a5ca7587e3ceca556e106) +++ firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision cd5be724d5a3ba7457e761191d82f278654d7f5c) @@ -1,14 +1,14 @@ /************************************************************************** * -* Copyright (c) 2019-2022 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-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 ModeTreatment.c * -* @author (last) Darren Cox -* @date (last) 11-May-2022 +* @author (last) Vinayakam Mani +* @date (last) 12-Oct-2023 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 @@ -89,6 +89,7 @@ static U32 treatmentTimeBroadcastTimerCtr; ///< Treatment time data broadcast timer counter used to schedule when to transmit data. static U32 treatmentStateBroadcastTimerCtr; ///< Treatment state data broadcast timer counter used to schedule when to transmit data. static U32 treatmentParamsRangesBroadcastTimerCtr; ///< Treatment parameter ranges broadcast timer counter used to schedule when to transmit updated ranges. + /// Interval (in task intervals) at which to publish alarm status to CAN bus. static OVERRIDE_U32_T treatmentTimePublishInterval = { TREATMENT_TIME_DATA_PUB_INTERVAL, TREATMENT_TIME_DATA_PUB_INTERVAL, TREATMENT_TIME_DATA_PUB_INTERVAL, 0 }; /// Interval (in task intervals) at which to publish alarm status to CAN bus. @@ -104,6 +105,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. @@ -130,18 +132,18 @@ // ********** private function prototypes ********** -static void resetSignalFlags( void ); -static void resetAlarmSignalFlags( void ); static void broadcastTreatmentSettingsRanges( void ); static void broadcastTreatmentPeriodicData(); -static U32 getTreatmentTimeInMinutes( void ); +static U32 getMinTreatmentTimeInMinutes( void ); static TREATMENT_STATE_T handleTreatmentStartState( void ); static TREATMENT_STATE_T handleTreatmentBloodPrimeState( void ); static TREATMENT_STATE_T handleTreatmentDialysisState( void ); static TREATMENT_STATE_T handleTreatmentStopState( void ); static TREATMENT_STATE_T handleTreatmentRinsebackState( void ); static TREATMENT_STATE_T handleTreatmentRecircState( void ); static TREATMENT_STATE_T handleTreatmentEndState( void ); +static void resetSignalFlags( void ); +static void resetAlarmSignalFlags( void ); /*********************************************************************//** * @brief @@ -157,6 +159,7 @@ bloodIsPrimed = FALSE; treatmentCompleted = FALSE; rinsebackDone = FALSE; + resumeBlockedByAlarm = FALSE; treatmentTimeMS = 0; lastTreatmentTimeStamp = 0; @@ -192,62 +195,38 @@ treatmentStartTimeStamp = getRTCTimestamp(); treatmentEndTimeStamp = 0; - } /*********************************************************************//** * @brief - * The resetSignalFlags function resets all non-alarm signal flags. - * @details Inputs: none - * @details Outputs: non-alarm signal flags set to FALSE - * @return none - *************************************************************************/ -static void resetSignalFlags( void ) -{ - rinsebackToStoppedRequest = FALSE; - endTreatmentRequest = FALSE; - rinsebackToRecircRequest = FALSE; - bloodPrimeToDialysisRequest = FALSE; - treatmentEndToRinsebackRequest = FALSE; -} - -/*********************************************************************//** - * @brief - * The resetAlarmSignalFlags function resets all alarm signal flags. - * @details Inputs: none - * @details Outputs: alarm signal flags set to FALSE - * @return none - *************************************************************************/ -static void resetAlarmSignalFlags( void ) -{ - resumeTreatmentAlarmResponseRequest = FALSE; - initiateRinsebackAlarmResponseRequest = FALSE; - endTreatmentAlarmResponseRequest = FALSE; -} - -/*********************************************************************//** - * @brief * The transitionToTreatmentMode function prepares for transition to treatment mode. * @details Inputs: none * @details Outputs: * @return initial state *************************************************************************/ 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; } @@ -278,6 +257,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 @@ -621,11 +613,19 @@ { BOOL stop = isStopButtonPressed(); + // 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(); @@ -713,7 +713,7 @@ * @brief * The handleTreatmentBloodPrimeState function handles the blood prime state of * the Treatment Mode state machine. - * @details Inputs: none + * @details Inputs: presUFRate * @details Outputs: none * @return next treatment mode state *************************************************************************/ @@ -740,7 +740,10 @@ // Kick dialysis sub-mode off setDialysisParams( getTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW ), getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), presMaxUFVolumeML, presUFRate ); - sendTreatmentLogEventData( UF_START_RESUME_EVENT, 0.0, presUFRate ); + if ( presUFRate > 0.0 ) + { + sendTreatmentLogEventData( UF_START_RESUME_EVENT, 0.0, presUFRate ); + } transitionToDialysis(); result = TREATMENT_DIALYSIS_STATE; } @@ -763,9 +766,10 @@ TREATMENT_STATE_T result = TREATMENT_DIALYSIS_STATE; U32 newTime = getMSTimerCount(); U32 msSinceLast = calcTimeBetween( lastTreatmentTimeStamp, newTime ); + DIALYSIS_STATE_T dialysisState = getDialysisState(); // Update treatment time (unless delivering a saline bolus) - if ( getDialysisState() != DIALYSIS_SALINE_BOLUS_STATE ) + if ( dialysisState != DIALYSIS_SALINE_BOLUS_STATE ) { treatmentTimeMS += msSinceLast; } @@ -779,7 +783,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 @@ -790,7 +794,6 @@ // Handle alarm stoppage if ( TRUE == doesAlarmStatusIndicateStop() ) { - stopDialysis(); transitionToTreatmentStop(); result = TREATMENT_STOP_STATE; } @@ -816,6 +819,10 @@ if ( TRUE == resumeTreatmentAlarmResponseRequest ) { resumeTreatmentAlarmResponseRequest = FALSE; + // Hard stop the pumps so they will ramp up from zero together on resume + signalDialInPumpHardStop(); + signalDialOutPumpHardStop(); + if ( TRUE == getBloodIsPrimed() ) { lastTreatmentTimeStamp = getMSTimerCount(); @@ -827,6 +834,7 @@ transitionToBloodPrime(); result = TREATMENT_BLOOD_PRIME_STATE; } + signalInitiatePressureStabilization( USE_NORMAL_STABILIZATION_PERIOD ); } // If user requests rinseback, go to rinseback else if ( TRUE == initiateRinsebackAlarmResponseRequest ) @@ -866,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 ) @@ -900,20 +925,31 @@ * @brief * The handleTreatmentRecircState function executes the re-circulate state of the * Treatment Mode state machine. - * @details Inputs: none - * @details Outputs: treatment re-circulate sub-mode executed. + * @details Inputs: endTreatmentAlarmResponseRequest, rinsebackToStoppedRequest, + * endTreatmentRequest + * @details Outputs: sendLastTreatmentPeriodicData * @return next treatment mode state *************************************************************************/ static TREATMENT_STATE_T handleTreatmentRecircState( void ) { TREATMENT_STATE_T result = TREATMENT_RECIRC_STATE; - // Execute treatment re-circ sub-mode - execTreatmentRecirc(); + // If user requests treatment end, end treatment + if ( TRUE == endTreatmentAlarmResponseRequest ) + { + sendLastTreatmentPeriodicData = TRUE; + requestNewOperationMode( MODE_POST ); + } + else + { + // Execute treatment re-circ sub-mode + execTreatmentRecirc(); + } // Handle signals from treatment re-circ sub-mode if ( TRUE == rinsebackToStoppedRequest ) { + stopDialysis(); transitionToTreatmentStop(); result = TREATMENT_STOP_STATE; } @@ -947,11 +983,7 @@ { signalTreatmentEndAlarmEndTxUserAction(); } - // Handle alarm response from user to resume slow blood flow while waiting for rinseback request - else if ( TRUE == resumeTreatmentAlarmResponseRequest ) - { - signalTreatmentEndAlarmResumeUserAction(); - } + // End treatment state does not allow resume // Execute treatment end sub-mode execTreatmentEnd(); @@ -988,7 +1020,7 @@ // Check if we are in an appropriate treatment state for settings adjustment if ( ( MODE_TREA == currMode ) && ( currentTreatmentState > TREATMENT_START_STATE ) && ( currentTreatmentState < TREATMENT_END_STATE ) && - ( CALC_ELAPSED_TREAT_TIME_IN_MIN() < treatmentTime ) && ( treatmentTime >= getTreatmentTimeInMinutes() ) ) + ( CALC_ELAPSED_TREAT_TIME_IN_MIN() < treatmentTime ) && ( treatmentTime >= getMinTreatmentTimeInMinutes() ) ) { F32 uFVolume; U32 dialVolume = getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ) * treatmentTime; // In mL @@ -1003,7 +1035,10 @@ sendTreatmentLogEventData( TREATMENT_DURATION_CHANGE_EVENT, ( presTreatmentTimeSecs / SEC_PER_MIN ), treatmentTime ); presMaxUFVolumeML = uFVolume; presTreatmentTimeSecs = treatmentTime * SEC_PER_MIN; + setTreatmentParameterF32( TREATMENT_PARAM_UF_VOLUME, ( presMaxUFVolumeML / (F32)ML_PER_LITER ) ); + setTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION, ( presTreatmentTimeSecs / SEC_PER_MIN ) ); setDialysisParams( getTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW ), getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), presMaxUFVolumeML, presUFRate ); + signalInitiatePressureStabilization( USE_NORMAL_STABILIZATION_PERIOD ); } else { @@ -1032,7 +1067,7 @@ { rejectReason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; } - else if ( treatmentTime < getTreatmentTimeInMinutes() ) + else if ( treatmentTime < getMinTreatmentTimeInMinutes() ) { rejectReason = REQUEST_REJECT_REASON_TREATMENT_TIME_LESS_THAN_MINIMUM; } @@ -1059,7 +1094,7 @@ * @details Inputs: current operating mode, treatment states and parameters * @details Outputs: response message sent * @param uFVolume New ultrafiltration volume requested by the user - * @return TRUE if new UF voluem is valid, FALSE if not. + * @return TRUE if new UF volume is valid, FALSE if not. *************************************************************************/ BOOL verifyUFSettingsChange( F32 uFVolume ) { @@ -1068,6 +1103,10 @@ S32 timeDiff = 0; F32 rateDiff = 0.0; HD_OP_MODE_T currMode = getCurrentOperationMode(); + S32 txSecRem = CALC_TREAT_TIME_REMAINING_IN_SECS(); + S32 txMinEla = CALC_ELAPSED_TREAT_TIME_IN_SECS() / SEC_PER_MIN; + F32 txMinRem = (F32)txSecRem / (F32)SEC_PER_MIN; + F32 colUFVol = getUltrafiltrationReferenceVolume(); // How much UF volume have we taken so far? // Reset pending UF/time settings changes to current values in case request is rejected pendingUFVolumeChange = presMaxUFVolumeML; @@ -1077,14 +1116,15 @@ // Check if we are in an appropriate treatment state for settings adjustment if ( ( MODE_TREA == currMode ) && ( currentTreatmentState > TREATMENT_START_STATE ) && ( currentTreatmentState < TREATMENT_END_STATE ) && - ( uFVolume <= MAX_UF_VOLUME_ML ) && + ( uFVolume <= MAX_UF_VOLUME_ML ) && ( uFVolume > colUFVol ) && ( CALC_TREAT_TIME_REMAINING_IN_SECS() >= PREVENT_UF_VOL_CHANGE_IF_NEARLY_DONE_SEC ) ) { DIALYSIS_STATE_T currDialysisState = getDialysisState(); UF_STATE_T currUFState = getUltrafiltrationState(); - F32 uFRate = uFVolume / ((F32)presTreatmentTimeSecs / (F32)SEC_PER_MIN); // What UF rate would be if user selected to adjust it - U32 trtTime = (S32)( uFVolume / presUFRate ) + 1; // What the treatment duration would be if user selected to adjust it - U32 dialVolume = getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ) * trtTime; // What dialysate volume would be if user selected to adjust time + F32 remUFVol = uFVolume - colUFVol; // What would remaining UF volume be after subtracting UF volume already taken + F32 uFRate = remUFVol / txMinRem; // What UF rate would be if user selected to adjust it + U32 trtTime = ( fabs( presUFRate ) < NEARLY_ZERO ? txMinEla + 1 : (S32)( remUFVol / presUFRate ) + txMinEla + 1 ); // What the treatment duration would be if user selected to adjust it + U32 dialVolume = getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ) * trtTime; // What dialysate volume would be if user selected to adjust time // UF should already be paused but let's make sure. if ( ( TREATMENT_DIALYSIS_STATE == currentTreatmentState ) && @@ -1109,19 +1149,8 @@ { pendingUFRateChange = 0.0; } - // Verify treatment duration change would be valid (leave zero if not valid - UI will disable option) - if ( ( trtTime <= MAX_TREATMENT_TIME_MINUTES ) && ( trtTime >= getTreatmentTimeInMinutes() ) && - ( dialVolume <= MAX_DIALYSATE_VOLUME_ML ) ) - { - result = TRUE; - pendingUFVolumeChange = uFVolume; - pendingTreatmentTimeChange = trtTime; - timeDiff = trtTime - ( (U32)( (F32)presTreatmentTimeSecs / (F32)SEC_PER_MIN ) + 1 ); - } - else - { - pendingTreatmentTimeChange = 0; - } + // Treatment duration change is now never valid - leave zero - UI will disable option) + pendingTreatmentTimeChange = 0; // If neither option works, reject for UF rate if ( FALSE == result ) { @@ -1139,7 +1168,9 @@ { rejectReason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; } - else if ( uFVolume > MAX_UF_VOLUME_ML ) + // UF volume cannot be set lower than the UF volume that has already been collected + else if ( ( uFVolume > MAX_UF_VOLUME_ML ) || + ( uFVolume <= colUFVol ) ) { rejectReason = REQUEST_REJECT_REASON_UF_VOLUME_OUT_OF_RANGE; } @@ -1158,8 +1189,10 @@ * @brief * The verifyUFSettingsConfirmation function verifies the user confirmed * ultrafiltration settings change(s) and, if valid, accepts the new settings. - * @details Inputs: current operating mode, treatment states and parameters - * @details Outputs: response message sent + * @details Inputs: current operating mode, treatment states and parameters, + * pendingUFVolumeChange, pendingUFRateChange + * @details Outputs: response message sent, presMaxUFVolumeML, + * presTreatmentTimeSecs, presUFRate * @param uFVolume New ultrafiltration volume confirmed by the user * @param adjustment The adjustment selected by the user * @return TRUE if new UF settings accepted, FALSE if not. @@ -1179,16 +1212,14 @@ sendTreatmentLogEventData( UF_VOLUME_CHANGE_EVENT, presMaxUFVolumeML, pendingUFVolumeChange ); result = TRUE; presMaxUFVolumeML = pendingUFVolumeChange; + setTreatmentParameterF32( TREATMENT_PARAM_UF_VOLUME, ( presMaxUFVolumeML / (F32)ML_PER_LITER ) ); - // Which setting does user want to adjust to accommodate the UF volume change? (treatment time or UF rate) - if ( UF_ADJ_TREATMENT_TIME == adjustment ) + // User should only allow UF rate adjustment to achieve UF volume change + if ( UF_ADJ_UF_RATE == adjustment ) { - presTreatmentTimeSecs = pendingTreatmentTimeChange * SEC_PER_MIN; - } - else // Must be adjusting UF rate then - { sendTreatmentLogEventData( UF_RATE_CHANGE_EVENT, presUFRate, pendingUFRateChange ); presUFRate = pendingUFRateChange; + signalInitiatePressureStabilization( USE_NORMAL_STABILIZATION_PERIOD ); } setDialysisParams( getTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW ), getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), presMaxUFVolumeML, presUFRate ); @@ -1252,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 ) ) ) + { + signalInitiatePressureStabilization( USE_NORMAL_STABILIZATION_PERIOD ); + } // Set to new rates setTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW, bloodRate ); setTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW, dialRate ); @@ -1300,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 ); @@ -1401,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 ) @@ -1418,11 +1422,20 @@ 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, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( TREATMENT_TIME_DATA_T ) ); + broadcastData( MSG_ID_TREATMENT_TIME_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( TREATMENT_TIME_DATA_T ) ); treatmentTimeBroadcastTimerCtr = 0; } // Broadcast treatment state data at interval @@ -1441,7 +1454,7 @@ payload.heparinState = getHeparinState(); payload.dialysisState = getDialysisState(); - broadcastData( MSG_ID_TREATMENT_STATE, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&payload, sizeof( TREATMENT_STATE_DATA_T ) ); + broadcastData( MSG_ID_TREATMENT_STATE_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&payload, sizeof( TREATMENT_STATE_DATA_T ) ); treatmentStateBroadcastTimerCtr = 0; } } @@ -1463,7 +1476,7 @@ // Compute minimum treatment duration U32 presTime = ( presTreatmentTimeSecs / SEC_PER_MIN ); U32 elapseTime = CALC_ELAPSED_TREAT_TIME_IN_MIN(); - U32 minTime = MAX( (elapseTime + 2), getTreatmentTimeInMinutes() ); // Treatment duration cannot be < 1 hour. add two minutes to cover rounding and ensure it is valid for next minute + U32 minTime = MAX( (elapseTime + 2), getMinTreatmentTimeInMinutes() ); // Treatment duration cannot be < 1 hour. add two minutes to cover rounding and ensure it is valid for next minute // Compute maximum treatment duration (from both UF and dialysate volume perspectives) U32 maxTimeRem = ( MAX_UF_VOLUME_ML - (U32)getUltrafiltrationReferenceVolume() ) / ( presUFRate > 0.0 ? (U32)presUFRate : 1 ); U32 maxTime1 = minTime + maxTimeRem; @@ -1524,50 +1537,80 @@ if ( ( timeElapsedSinceLastPublish_ms >= TREATMENT_PERIODIC_DATA_PUB_INTERVAL ) || ( TRUE == sendLastTreatmentPeriodicData ) ) { TREATMENT_LOG_DATA_PERIODIC_T periodTreatmentData; + F32 const uFVolumeCollected = getUltrafiltrationVolumeCollected(); U32 const numberOfDataPoint = timeElapsedSinceLastPublish_ms / TREATMENT_PERIODIC_DATA_LOG_INTERVAL; - periodTreatmentData.avgUFRate = ( getUltrafiltrationVolumeCollected() - lastUltraFiltrationVolume_mL ) / ( numberOfDataPoint / SEC_PER_MIN ); - periodTreatmentData.avgBloodFlowRate = bloodFlowRateSum_mL_min / numberOfDataPoint; - periodTreatmentData.avgDialysateFlowRate = dialysateFlowRateSum_mL_min / numberOfDataPoint; - periodTreatmentData.avgArterialPressure = arterialPressureSum_mmHg / numberOfDataPoint; - periodTreatmentData.avgVenousPressure = venousPressureSum_mmHg / numberOfDataPoint; - + if ( numberOfDataPoint > 0 ) + { // don't send data if no data since last publish + periodTreatmentData.avgUFRate = ( uFVolumeCollected - lastUltraFiltrationVolume_mL ) / ( numberOfDataPoint / SEC_PER_MIN ); + periodTreatmentData.avgBloodFlowRate = bloodFlowRateSum_mL_min / numberOfDataPoint; + periodTreatmentData.avgDialysateFlowRate = dialysateFlowRateSum_mL_min / numberOfDataPoint; + periodTreatmentData.avgArterialPressure = arterialPressureSum_mmHg / numberOfDataPoint; + periodTreatmentData.avgVenousPressure = venousPressureSum_mmHg / numberOfDataPoint; + sendTreatmentPeriodicDataToUI( &periodTreatmentData ); + } + // reset for next round to publish sendLastTreatmentPeriodicData = FALSE; lastTreatmentPeriodicDataPublishTimeStamp = treatmentTimeMS; - lastUltraFiltrationVolume_mL = getUltrafiltrationVolumeCollected(); + lastUltraFiltrationVolume_mL = uFVolumeCollected; bloodFlowRateSum_mL_min = 0.0; dialysateFlowRateSum_mL_min = 0.0; arterialPressureSum_mmHg = 0.0; venousPressureSum_mmHg = 0.0; - sendTreatmentPeriodicDataToUI( &periodTreatmentData ); } } /*********************************************************************//** * @brief - * The getTreatmentTimeInMinutes function returns the treatment time in minutes. - * @details Inputs: none + * The getMinTreatmentTimeInMinutes function returns the minimum treatment + * time (in minutes) that the user could set treatment duration to. + * @details Inputs: MIN_TREATMENT_TIME_MINUTES * @details Outputs: none - * @return treatment time in minutes + * @return minimum treatment time in minutes *************************************************************************/ -static U32 getTreatmentTimeInMinutes( void ) +static U32 getMinTreatmentTimeInMinutes( void ) { - // Assuming a 1 minute treatment - // NOTE: no # define for the 1 minute treatment time since this is only used for testing - U32 treatmentTime = 1; + U32 treatmentTime = MIN_TREATMENT_TIME_MINUTES; -#ifndef _RELEASE_ - // Check if the 1 minute treatment software configuration has not been enabled - if ( getSoftwareConfigStatus( SW_CONFIG_ENABLE_1_MIN_TREATMENT ) != SW_CONFIG_ENABLE_VALUE ) -#endif + if ( TRUE == getTestConfigStatus( TEST_CONFIG_ENABLE_ONE_MINUTE_TREATMENT ) ) { - treatmentTime = MIN_TREATMENT_TIME_MINUTES; + treatmentTime = 1; } return treatmentTime; } +/*********************************************************************//** + * @brief + * The resetSignalFlags function resets all non-alarm signal flags. + * @details Inputs: none + * @details Outputs: non-alarm signal flags set to FALSE + * @return none + *************************************************************************/ +static void resetSignalFlags( void ) +{ + rinsebackToStoppedRequest = FALSE; + endTreatmentRequest = FALSE; + rinsebackToRecircRequest = FALSE; + bloodPrimeToDialysisRequest = FALSE; + treatmentEndToRinsebackRequest = FALSE; +} +/*********************************************************************//** + * @brief + * The resetAlarmSignalFlags function resets all alarm signal flags. + * @details Inputs: none + * @details Outputs: alarm signal flags set to FALSE + * @return none + *************************************************************************/ +static void resetAlarmSignalFlags( void ) +{ + resumeTreatmentAlarmResponseRequest = FALSE; + initiateRinsebackAlarmResponseRequest = FALSE; + endTreatmentAlarmResponseRequest = FALSE; +} + + /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/