Index: firmware/App/Modes/ModeTreatment.c =================================================================== diff -u -ra37189e75de205982befcc91176f33c0523b03a8 -rcd5be724d5a3ba7457e761191d82f278654d7f5c --- firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision a37189e75de205982befcc91176f33c0523b03a8) +++ firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision cd5be724d5a3ba7457e761191d82f278654d7f5c) @@ -1,14 +1,14 @@ /************************************************************************** * -* Copyright (c) 2019-2023 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) Dara Navaei -* @date (last) 03-Jun-2023 +* @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. @@ -128,7 +129,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 ********** @@ -195,7 +195,6 @@ treatmentStartTimeStamp = getRTCTimestamp(); treatmentEndTimeStamp = 0; - hasTreatmentStartTimeBeenWrittenToNV = FALSE; } /*********************************************************************//** @@ -221,6 +220,9 @@ 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 ); @@ -629,13 +631,6 @@ 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 ) { @@ -718,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 *************************************************************************/ @@ -745,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; } @@ -773,14 +771,7 @@ // Update treatment time (unless delivering a saline bolus) if ( dialysisState != DIALYSIS_SALINE_BOLUS_STATE ) { -#ifdef DIALYZER_REPRIME_ENABLED - if ( dialysisState != DIALYSIS_DIALYZER_REPRIME_STATE ) - { -#endif treatmentTimeMS += msSinceLast; -#ifdef DIALYZER_REPRIME_ENABLED - } -#endif } lastTreatmentTimeStamp = newTime; @@ -803,7 +794,6 @@ // Handle alarm stoppage if ( TRUE == doesAlarmStatusIndicateStop() ) { - stopDialysis(); transitionToTreatmentStop(); result = TREATMENT_STOP_STATE; } @@ -829,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(); @@ -840,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 ) @@ -879,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 ) @@ -913,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; } @@ -960,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(); @@ -1019,6 +1038,7 @@ 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 { @@ -1074,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 ) { @@ -1083,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; @@ -1092,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 ) && @@ -1113,7 +1138,7 @@ pendingParamChangesTimer = getMSTimerCount(); // Verify UF rate change would be valid (leave zero if not valid - UI will disable option) - if ( ( uFRate <= (F32)MAX_UF_RATE_ML_MIN ) && ( uFRate >= MIN_UF_RATE_ML_MIN ) ) + if ( uFRate <= (F32)MAX_UF_RATE_ML_MIN ) { result = TRUE; pendingUFVolumeChange = uFVolume; @@ -1124,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 >= getMinTreatmentTimeInMinutes() ) && - ( 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 ) { @@ -1154,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; } @@ -1198,16 +1214,12 @@ 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; - setTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION, ( presTreatmentTimeSecs / 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 ); @@ -1274,7 +1286,7 @@ if ( ( bloodRate != (U32)getTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW ) ) || ( dialRate != (U32)getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ) ) ) { - signalUserRateChange(); + signalInitiatePressureStabilization( USE_NORMAL_STABILIZATION_PERIOD ); } // Set to new rates setTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW, bloodRate ); @@ -1441,11 +1453,6 @@ payload.txEndState = getCurrentTreatmentEndState(); payload.heparinState = getHeparinState(); payload.dialysisState = getDialysisState(); -#ifdef DIALYZER_REPRIME_ENABLED - payload.dlzReprimeState = getDialyzerRePrimeState(); -#else - payload.dlzReprimeState = 0; -#endif broadcastData( MSG_ID_TREATMENT_STATE_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&payload, sizeof( TREATMENT_STATE_DATA_T ) ); treatmentStateBroadcastTimerCtr = 0; @@ -1530,22 +1537,26 @@ 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 ); } }