Index: firmware/App/Modes/ModeTreatment.c =================================================================== diff -u -raef738aab88159be8664b91d72b1682a0d0db541 -r8acad167bcf7ad07043192007e59d253a5216e3a --- firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision aef738aab88159be8664b91d72b1682a0d0db541) +++ firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 8acad167bcf7ad07043192007e59d253a5216e3a) @@ -27,6 +27,7 @@ #include "ModeTreatmentParams.h" #include "OperationModes.h" #include "Rinseback.h" +#include "RTC.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "Timers.h" @@ -44,9 +45,11 @@ // ********** private definitions ********** #define MAX_TREATMENT_TIME_MINUTES ( 8 * MIN_PER_HOUR ) ///< Maximum treatment time (in minutes). +#ifndef ALLOW_1_MIN_TREATMENT_DURATION #define MIN_TREATMENT_TIME_MINUTES ( 1 * MIN_PER_HOUR ) ///< Minimum treatment time (in minutes). -#define MAX_UF_RATE_ML_MIN ( (F32)2500 / (F32)MIN_PER_HOUR ) ///< Maximum ultrafiltration rate (in mL/min). -#define MAX_UF_VOLUME_ML ( 8 * ML_PER_LITER ) ///< Maximum ultrafiltration volume (in mL). +#else +#define MIN_TREATMENT_TIME_MINUTES ( 1 ) ///< Minimum treatment time (in minutes). +#endif #define MAX_DIALYSATE_VOLUME_ML ( 150 * ML_PER_LITER ) ///< Maximum dialysate volume (in mL). #define USER_CONFIRM_CHANGE_TIMEOUT_MS ( 60 * MS_PER_SECOND ) ///< Require user to confirm UF volume change within this time. @@ -58,6 +61,10 @@ static const U32 TREATMENT_STATE_DATA_PUB_INTERVAL = ( 250 / TASK_GENERAL_INTERVAL ); /// Interval (ms/task time) at which updated, valid treatment setting ranges are published on the CAN bus. static const U32 TREATMENT_SETTINGS_RANGES_PUB_INTERVAL = ( ( 60 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ); +/// Interval (ms) at which the treatment periodic data is published on the CAN bus. +static const U32 TREATMENT_PERIODIC_DATA_PUB_INTERVAL = ( 30 * SEC_PER_MIN * MS_PER_SECOND ); +/// Interval (ms) at which the treatment periodic data is logged. +static const U32 TREATMENT_PERIODIC_DATA_LOG_INTERVAL = ( MS_PER_SECOND ); #define CALC_ELAPSED_TREAT_TIME_IN_SECS() ( treatmentTimeMS / MS_PER_SECOND ) ///< Macro to calculate the elapsed treatment time in seconds. /// Macro to calculate the elapsed treatment time in minutes. @@ -99,11 +106,30 @@ static F32 pendingUFRateChange; ///< An ultrafiltration rate change (mL/min) is pending user confirmation. static U32 pendingTreatmentTimeChange; ///< A treatment time change (min) is pending user confirmation. +static U32 lastTreatmentPeriodicDataPublishTimeStamp; ///< Last treatment 30 minutes periodic data publish time stamp. +static U32 lastTreatmentPeriodicDataCollectTimeStamp; ///< Last treatment periodic data collect time stamp. +static F32 lastUltraFiltrationVolume_mL; ///< Last 30 minutes ultra filtration volume in mL. +static F32 bloodFlowRateSum_mL_min; ///< Blood flow rate sum logged every second. +static F32 dialysateFlowRateSum_mL_min; ///< Dialysate flow rate sum logged every second. +static F32 arterialPressureSum_mmHg; ///< Arterial pressure sum logged every second. +static F32 venousPressureSum_mmHg; ///< Venous pressure sum logged every second. + +static F32 treatmentBloodFlowRateTotal_mL_min; ///< Blood flow rate total per treatment logged every second. +static F32 treatmentDialysateFlowRateTotal_mL_min; ///< Dialysate flow rate total per treatment logged every second. +static F32 treatmentDialysateTempTotal_degree_C; ///< Dialysate temperature total per treatment logged every second. +static F32 treatmentArterialPressureTotal_mmHg; ///< Arterial pressure total per treatment logged every second. +static F32 treatmentVenousPressureTotal_mmHg; ///< Venous pressure total per treatment logged every second. +static BOOL sendLastTreatmentPeriodicData; ///< Flag determines if HD needs to send the last treatment periodic data. + +static U32 treatmentStartTimeStamp; ///< Treatment start timestampt for logging purpose. +static U32 treatmentEndTimeStamp; ///< Treatment end timestampt for logging purpose. + // ********** private function prototypes ********** static void resetSignalFlags( void ); static void resetAlarmSignalFlags( void ); static void broadcastTreatmentSettingsRanges( void ); +static void broadcastTreatmentPeriodicData(); static TREATMENT_STATE_T handleTreatmentStartState( void ); static TREATMENT_STATE_T handleTreatmentBloodPrimeState( void ); static TREATMENT_STATE_T handleTreatmentDialysisState( void ); @@ -125,7 +151,7 @@ bloodIsPrimed = FALSE; treatmentCompleted = FALSE; - rinsebackDone = TRUE; + rinsebackDone = FALSE; treatmentTimeMS = 0; lastTreatmentTimeStamp = 0; @@ -146,6 +172,23 @@ pendingUFVolumeChange = 0.0; pendingUFRateChange = 0.0; pendingTreatmentTimeChange = 0; + + lastTreatmentPeriodicDataPublishTimeStamp = 0; + lastTreatmentPeriodicDataCollectTimeStamp = 0; + lastUltraFiltrationVolume_mL = 0.0; + bloodFlowRateSum_mL_min = 0.0; + dialysateFlowRateSum_mL_min = 0.0; + arterialPressureSum_mmHg = 0.0; + venousPressureSum_mmHg = 0.0; + treatmentBloodFlowRateTotal_mL_min = 0.0; + treatmentDialysateFlowRateTotal_mL_min = 0.0; + treatmentDialysateTempTotal_degree_C = 0.0; + treatmentArterialPressureTotal_mmHg = 0.0; + treatmentVenousPressureTotal_mmHg = 0.0; + sendLastTreatmentPeriodicData = FALSE; + + treatmentStartTimeStamp = getRTCTimestamp(); + treatmentEndTimeStamp = 0; } /*********************************************************************//** @@ -241,6 +284,19 @@ /*********************************************************************//** * @brief + * The getActualTreatmentTimeSecs function determines the actual treatment + * duration in seconds. + * @details Inputs: treatmentTimeMS + * @details Outputs: none + * @return The actual treatment duration in seconds. + *************************************************************************/ +U32 getActualTreatmentTimeSecs( void ) +{ + return ( treatmentTimeMS / MS_PER_SECOND ); +} + +/*********************************************************************//** + * @brief * The getRinsebackCompleted function determines whether a rinseback has been * completed (indicating blood-side circuit should be primarily saline). * @details Inputs: rinsebackDone @@ -299,6 +355,137 @@ /*********************************************************************//** * @brief + * The getTreatmentAvgBloodFlowRate function returns the average blood flow + * rate collected through out the treatment. + * @details Inputs: treatmentTimeMS, treatmentBloodFlowRateTotal_mL_min + * @details Outputs: none + * @return the average blood flow rate + *************************************************************************/ +F32 getTreatmentAvgBloodFlowRate( void ) +{ + U32 const numberOfDataPoint = ( treatmentTimeMS / TREATMENT_PERIODIC_DATA_LOG_INTERVAL ); + F32 result = 0.0; + + if ( numberOfDataPoint > 0 ) + { + result = ( treatmentBloodFlowRateTotal_mL_min / numberOfDataPoint ); + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getTreatmentAvgDialysateFlowRate function returns the average dialysate + * flow rate collected through out the treatment. + * @details Inputs: treatmentTimeMS, treatmentDialysateFlowRateTotal_mL_min + * @details Outputs: none + * @return the average dialysate flow rate + *************************************************************************/ +F32 getTreatmentAvgDialysateFlowRate( void ) +{ + U32 const numberOfDataPoint = ( treatmentTimeMS / TREATMENT_PERIODIC_DATA_LOG_INTERVAL ); + F32 result = 0.0; + + if ( numberOfDataPoint > 0 ) + { + result = ( treatmentDialysateFlowRateTotal_mL_min / numberOfDataPoint ); + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getTreatmentAvgDialysateTemp function returns the average dialysate + * temperature collected through out the treatment. + * @details Inputs: treatmentTimeMS, treatmentDialysateTempTotal_degree_C + * @details Outputs: none + * @return the average dialysate temperature + *************************************************************************/ +F32 getTreatmentAvgDialysateTemp( void ) +{ + U32 const numberOfDataPoint = ( treatmentTimeMS / TREATMENT_PERIODIC_DATA_LOG_INTERVAL ); + F32 result = 0.0; + + if ( numberOfDataPoint > 0 ) + { + result = ( treatmentDialysateTempTotal_degree_C / numberOfDataPoint ); + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getTreatmentAvgArterialPressure function returns the average arterial + * pressure collected through out the treatment. + * @details Inputs: treatmentTimeMS, treatmentArterialPressureTotal_mmHg + * @details Outputs: none + * @return the average arterial pressure + *************************************************************************/ +F32 getTreatmentAvgArterialPressure( void ) +{ + U32 const numberOfDataPoint = ( treatmentTimeMS / TREATMENT_PERIODIC_DATA_LOG_INTERVAL ); + F32 result = 0.0; + + if ( numberOfDataPoint > 0 ) + { + result = ( treatmentArterialPressureTotal_mmHg / numberOfDataPoint ); + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getTreatmentAvgVenousPressure function returns the average venous + * pressure collected through out the treatment. + * @details Inputs: treatmentTimeMS, treatmentVenousPressureTotal_mmHg + * @details Outputs: none + * @return the average venous pressure + *************************************************************************/ +F32 getTreatmentAvgVenousPressure( void ) +{ + U32 const numberOfDataPoint = ( treatmentTimeMS / TREATMENT_PERIODIC_DATA_LOG_INTERVAL ); + F32 result = 0.0; + + if ( numberOfDataPoint > 0 ) + { + result = ( treatmentVenousPressureTotal_mmHg / numberOfDataPoint ); + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getTreatmentStartTimeStamp function returns the treatment start + * time stamp. + * @details Inputs: treatmentStartTimeStamp + * @details Outputs: none + * @return the treatment start time stamp + *************************************************************************/ +U32 getTreatmentStartTimeStamp( void ) +{ + return treatmentStartTimeStamp; +} + +/*********************************************************************//** + * @brief + * The getTreatmentEndTimeStamp function returns the treatment end + * time stamp. + * @details Inputs: treatmentEndTimeStamp + * @details Outputs: none + * @return the treatment end time stamp + *************************************************************************/ +U32 getTreatmentEndTimeStamp( void ) +{ + return treatmentEndTimeStamp; +} + +/*********************************************************************//** + * @brief * The signalAlarmActionToTreatmentMode function executes the given alarm action * as appropriate while in Treatment Mode. * @details Inputs: none @@ -463,6 +650,7 @@ // Broadcast treatment data broadcastTreatmentTimeAndState(); broadcastTreatmentSettingsRanges(); + broadcastTreatmentPeriodicData(); // Manage air trap control execAirTrapMonitorTreatment(); @@ -562,6 +750,8 @@ if ( CALC_ELAPSED_TREAT_TIME_IN_SECS() >= presTreatmentTimeSecs ) { treatmentCompleted = TRUE; + sendLastTreatmentPeriodicData = TRUE; + treatmentEndTimeStamp = getRTCTimestamp(); stopDialysis(); transitionToTreatmentEnd(); SET_ALARM_WITH_1_U32_DATA( ALARM_ID_END_OF_TREATMENT_WARNING, presTreatmentTimeSecs ); @@ -622,11 +812,13 @@ // If user requests treatment end, end treatment else if ( TRUE == endTreatmentAlarmResponseRequest ) { + sendLastTreatmentPeriodicData = TRUE; requestNewOperationMode( MODE_POST ); } // Otherwise execute state machine for treatment stop sub-mode else { + execTreatmentReservoirMgmt(); execTreatmentStop(); } @@ -766,6 +958,7 @@ ( uFVolume <= MAX_UF_VOLUME_ML ) ) { result = TRUE; + sendTreatmentLogEventData( TREATMENT_DURATION_CHANGE_EVENT, ( presTreatmentTimeSecs / SEC_PER_MIN ), treatmentTime ); presMaxUFVolumeML = uFVolume; presTreatmentTimeSecs = treatmentTime * SEC_PER_MIN; setDialysisParams( presBloodFlowRate, presDialysateFlowRate, presMaxUFVolumeML, presUFRate ); @@ -940,6 +1133,7 @@ DIALYSIS_STATE_T currDialysisState = getDialysisState(); UF_STATE_T currUFState = getUltrafiltrationState(); + sendTreatmentLogEventData( UF_VOLUME_CHANGE_EVENT, presMaxUFVolumeML, pendingUFVolumeChange ); result = TRUE; presMaxUFVolumeML = pendingUFVolumeChange; @@ -1010,6 +1204,8 @@ ( dialVolume <= MAX_DIALYSATE_VOLUME_ML ) ) { result = TRUE; + sendTreatmentLogEventData( BLOOD_FLOW_RATE_CHANGE_EVENT, presBloodFlowRate, bloodRate ); + sendTreatmentLogEventData( DIALYSATE_FLOW_RATE_CHANGE_EVENT, presDialysateFlowRate, dialRate ); // Set to new rates presBloodFlowRate = bloodRate; presDialysateFlowRate = dialRate; @@ -1117,6 +1313,11 @@ 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 ); + + sendTreatmentLogEventData( ARTERIAL_PRESSURE_LOWER_LIMIT_CHANGE_EVENT, getTreatmentParameterS32( TREATMENT_PARAM_ART_PRESSURE_LOW_LIMIT ), data->artLowLimit ); + sendTreatmentLogEventData( ARTERIAL_PRESSURE_UPPER_LIMIT_CHANGE_EVENT, getTreatmentParameterS32( TREATMENT_PARAM_ART_PRESSURE_HIGH_LIMIT ), data->artHighLimit ); + sendTreatmentLogEventData( VENOUS_PRESSURE_LOWER_LIMIT_CHANGE_EVENT, getTreatmentParameterS32( TREATMENT_PARAM_VEN_PRESSURE_LOW_LIMIT ), data->venLowLimit ); + sendTreatmentLogEventData( VENOUS_PRESSURE_UPPER_LIMIT_CHANGE_EVENT, getTreatmentParameterS32( TREATMENT_PARAM_VEN_PRESSURE_HIGH_LIMIT ), data->venHighLimit ); } // Read back limits for transmit to UI. @@ -1223,7 +1424,60 @@ } } +/*********************************************************************//** + * @brief + * The broadcastTreatmentPeriodicData function computes and broadcasts + * periodic treatment data during treatment. + * @details Inputs: treatmentPeriodDataBroadcastTimerCtr + * @details Outputs: collected and sent average treatment data over 30 minutes + * @return none + *************************************************************************/ +static void broadcastTreatmentPeriodicData( void ) +{ + U32 const timeElapsedSinceLastCollect_ms = calcTimeBetween( lastTreatmentPeriodicDataCollectTimeStamp, treatmentTimeMS ); + U32 const timeElapsedSinceLastPublish_ms = calcTimeBetween( lastTreatmentPeriodicDataPublishTimeStamp, treatmentTimeMS ); + if ( timeElapsedSinceLastCollect_ms >= TREATMENT_PERIODIC_DATA_LOG_INTERVAL ) + { + F32 const arterialPres = getMeasuredArterialPressure(); + F32 const venousPres = getMeasuredArterialPressure(); + + lastTreatmentPeriodicDataCollectTimeStamp = treatmentTimeMS; + bloodFlowRateSum_mL_min += getMeasuredBloodFlowRate(); + dialysateFlowRateSum_mL_min += getMeasuredDialInFlowRate(); + arterialPressureSum_mmHg += arterialPres; + venousPressureSum_mmHg += venousPres; + + treatmentBloodFlowRateTotal_mL_min += getMeasuredBloodFlowRate(); + treatmentDialysateFlowRateTotal_mL_min += getMeasuredDialInFlowRate(); + treatmentDialysateTempTotal_degree_C += getDialysateTemperature(); + treatmentArterialPressureTotal_mmHg += arterialPres; + treatmentVenousPressureTotal_mmHg += venousPres; + } + + if ( ( timeElapsedSinceLastPublish_ms >= TREATMENT_PERIODIC_DATA_PUB_INTERVAL ) || ( TRUE == sendLastTreatmentPeriodicData ) ) + { + TREATMENT_LOG_DATA_PERIODIC_T periodTreatmentData; + 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; + + sendLastTreatmentPeriodicData = FALSE; + lastTreatmentPeriodicDataPublishTimeStamp = treatmentTimeMS; + lastUltraFiltrationVolume_mL = getUltrafiltrationVolumeCollected(); + bloodFlowRateSum_mL_min = 0.0; + dialysateFlowRateSum_mL_min = 0.0; + arterialPressureSum_mmHg = 0.0; + venousPressureSum_mmHg = 0.0; + sendTreatmentPeriodicDataToUI( &periodTreatmentData ); + } +} + + /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/