Index: firmware/App/Modes/ModeTreatment.c =================================================================== diff -u --- firmware/App/Modes/ModeTreatment.c (revision 0) +++ firmware/App/Modes/ModeTreatment.c (revision cd19fd5095128315982b9ef810bd45e68eff8deb) @@ -0,0 +1,1047 @@ +/************************************************************************** +* +* Copyright (c) 2025-2025 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) Sean +* @date (last) 25-Mar-2025 +* +* @author (original) Sean +* @date (original) 25-Mar-2025 +* +***************************************************************************/ + +#include "TDCommon.h" +#include "AirTrap.h" +//#include "BloodFlow.h" +#include "Buttons.h" +#include "DDInterface.h" +#include "ModeService.h" +#include "ModeTreatment.h" +#include "ModeTxParams.h" +//#include "NVDataMgmt.h" +#include "OperationModes.h" +#include "StateTxDialysis.h" +#include "StateTxPaused.h" +//#include "Switches.h" +#include "TaskGeneral.h" +#include "Timers.h" +#include "Valves.h" + +/** + * @addtogroup TDTreatmentMode + * @{ + */ + +// ********** private definitions ********** + +#define MAX_TREATMENT_TIME_MINUTES ( 8 * MIN_PER_HOUR ) ///< Maximum treatment time (in minutes). +#define MIN_TREATMENT_TIME_MINUTES ( 1 * MIN_PER_HOUR ) ///< Minimum treatment time (in minutes). + +/// Interval (ms/task time) at which the treatment time data is published on the CAN bus. +#define TREATMENT_TIME_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) +/// Interval (ms/task time) at which the treatment state data is published on the CAN bus. +#define 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. +#define TREATMENT_SETTINGS_RANGES_PUB_INTERVAL ( ( 60 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) +/// Saline ultrafiltration data broadcast interval (ms/task time) count. +#define ULTRAFILTRATION_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) +/// Saline bolus data broadcast interval (ms/task time) count. // TODO - move to StateTxSalineBolus.c when implemented +#define SALINE_BOLUS_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) + +/// Macro to calculate the elapsed treatment time in seconds. +#define CALC_ELAPSED_TREAT_TIME_IN_SECS() ( treatmentTimeMS / MS_PER_SECOND ) +/// Macro to calculate the elapsed treatment time in minutes. +#define CALC_ELAPSED_TREAT_TIME_IN_MIN() ( ( treatmentTimeMS / MS_PER_SECOND ) / SEC_PER_MIN ) +/// Macro to calculate the remaining treatment time in seconds. +#define CALC_TREAT_TIME_REMAINING_IN_SECS() ( (S32)presTreatmentTimeSecs - (S32)( treatmentTimeMS / MS_PER_SECOND ) ) + +// ********** private data ********** + +static TREATMENT_STATE_T currentTreatmentState; ///< Current state (sub-mode) of treatment mode. + +static BOOL bloodIsPrimed; ///< Flag indicates whether blood-side circuit has been primed with blood. Set FALSE at init and start of rinseback. Set TRUE at end of blood prime. +static BOOL rinsebackDone; ///< Flag indicates whether a rinseback has been completed. Set FALSE at start of blood prime. Set TRUE at init and end of rinseback. +static BOOL treatmentCompleted; ///< Flag indicates whether the treatment has completed. + +static U32 presTreatmentTimeSecs; ///< Prescribed treatment time (in seconds). +static F32 presUFVolumeL; ///< Prescribed ultrafiltration volume (in L). +static F32 presUFRateLHr; ///< Prescribed ultrafiltration rate (in L/hr). + +static U32 treatmentTimeMS; ///< Elapsed treatment time (in ms). +static U32 lastTreatmentTimeStamp; ///< Last time elapsed treatment time was recorded (a timestamp in ms). +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. +static U32 ultrafiltrationBroadcastTimerCtr; ///< Ultrafiltration data broadcast timer counter used to schedule when to transmit data. +static U32 salineBolusBroadcastTimerCtr; ///< Saline bolus data broadcast timer counter used to schedule when to transmit data. + +/// 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. +static OVERRIDE_U32_T treatmentStatePublishInterval = { TREATMENT_STATE_DATA_PUB_INTERVAL, TREATMENT_STATE_DATA_PUB_INTERVAL, TREATMENT_STATE_DATA_PUB_INTERVAL, 0 }; +/// Interval (in task intervals) at which to publish alarm status to CAN bus. +static OVERRIDE_U32_T treatmentParamRangesPublishInterval = { TREATMENT_SETTINGS_RANGES_PUB_INTERVAL, TREATMENT_SETTINGS_RANGES_PUB_INTERVAL, TREATMENT_SETTINGS_RANGES_PUB_INTERVAL, 0 }; + +static BOOL resumeTreatmentAlarmResponseRequest; ///< Flag indicates user has requested treatment resume. +static BOOL initiateRinsebackAlarmResponseRequest; ///< Flag indicates user has requested rinseback. +static BOOL endTreatmentAlarmResponseRequest; ///< Flag indicates user has requested treatment end. +static BOOL endTreatmentRequest; ///< Flag indicates user has requested end of treatment from rinseback workflow. +static BOOL bloodPrimeToDialysisRequest; ///< Flag indicates blood prime has completed and time to start dialysis. +static BOOL resumeBlockedByAlarm; ///< Flag indicates an alarm has blocked resume of this treatment. + +static U32 treatmentStartTimeStamp; ///< Treatment start timestamp for logging purpose. +static U32 treatmentEndTimeStamp; ///< Treatment end timestamp for logging purpose. + +// ********** private function prototypes ********** + +static void broadcastTreatmentSettingsRanges( void ); +static void broadcastTreatmentPeriodicData(); +static void publishSalineBolusData( void ); // TODO - move to StateTxSalineBolus.c when implemented +static void publishUltrafiltrationData( 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 handleTreatmentIsoUFState( void ); +static TREATMENT_STATE_T handleTreatmentDialysatePausedState( void ); +static TREATMENT_STATE_T handleTreatmentSalineBolusState( void ); +static TREATMENT_STATE_T handleTreatmentPausedState( 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 + * The initTreatmentMode function initializes the Treatment Mode unit. + * @details \b Inputs: none + * @details \b Outputs: Treatment Mode unit initialized. + * @return none + *************************************************************************/ +void initTreatmentMode( void ) +{ + currentTreatmentState = TREATMENT_START_STATE; + + bloodIsPrimed = FALSE; + treatmentCompleted = FALSE; + rinsebackDone = FALSE; + resumeBlockedByAlarm = FALSE; + + treatmentTimeMS = 0; + lastTreatmentTimeStamp = 0; + treatmentTimeBroadcastTimerCtr = TREATMENT_TIME_DATA_PUB_INTERVAL; // So we send time data immediately when we begin treatment mode + treatmentStateBroadcastTimerCtr = TREATMENT_STATE_DATA_PUB_INTERVAL; // So we send state data immediately when we begin treatment mode + treatmentParamsRangesBroadcastTimerCtr = TREATMENT_SETTINGS_RANGES_PUB_INTERVAL; // So we send ranges immediately when we begin treatment mode + ultrafiltrationBroadcastTimerCtr = ULTRAFILTRATION_DATA_PUB_INTERVAL; // So we send ultrafiltration immediately when we begin treatment mode + salineBolusBroadcastTimerCtr = SALINE_BOLUS_DATA_PUB_INTERVAL; // So we send saline bolus data immediately when we begin treatment mode + + presTreatmentTimeSecs = 0; + presUFVolumeL = 0.0F; + presUFRateLHr = 0.0F; + + resetSignalFlags(); + resetAlarmSignalFlags(); + + treatmentStartTimeStamp = 0; + treatmentEndTimeStamp = 0; +} + +/*********************************************************************//** + * @brief + * The transitionToTreatmentMode function prepares for transition to treatment + * mode. + * @details \b Inputs: none + * @details \b Outputs: none + * @return initial state + *************************************************************************/ +U32 transitionToTreatmentMode( void ) +{ +// PRESSURE_LIMIT_CHANGE_RESPONSE_T respRecord; + + // don't re-initialize treatment if tester is returning to treatment mode from a fault + if ( getPreviousOperationMode() != MODE_FAUL ) + { + // Initialize treatment mode each time we transition to it + initTreatmentMode(); + // Initialize treatment sub-modes each time we transition to treatment mode +// initBloodPrime(); + initDialysis(); + initTreatmentPaused(); +// 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 ); + + // Set treatment parameters + presTreatmentTimeSecs = getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION ) * SEC_PER_MIN; + presUFVolumeL = getTreatmentParameterF32( TREATMENT_PARAM_UF_VOLUME ); + presUFRateLHr = presUFVolumeL / ( (F32)getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION ) / (F32)MIN_PER_HOUR ); + setDialysisDDParams( getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), presUFVolumeL, presUFRateLHr ); + + // Direct DD to generate dialysate and bypass while priming blood + cmdStartGenerateDialysate( (F32)getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), presUFRateLHr, + getTreatmentParameterF32( TREATMENT_PARAM_DIALYSATE_TEMPERATURE ), TRUE, + (ACID_CONCENTRATE_TYPE_T)getTreatmentParameterU32( TREATMENT_PARAM_ACID_CONCENTRATE ), + (BICARB_CONCENTRATE_TYPE_T)getTreatmentParameterU32( TREATMENT_PARAM_BICARB_CONCENTRATE ) ); + // Read back limits for transmit to UI. +// 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 ); + + return currentTreatmentState; +} + +/*********************************************************************//** + * @brief + * The getTreatmentState function gets the current treatment mode state. + * @details \b Inputs: currentTreatmentState + * @details \b Outputs: none + * @return currentTreatmentState + *************************************************************************/ +TREATMENT_STATE_T getTreatmentState( void ) +{ + return currentTreatmentState; +} + +/*********************************************************************//** + * @brief + * The isTreatmentCompleted function determines whether the treatment has + * completed (indicating treatment duration has elapsed). + * @details \b Inputs: treatmentCompleted + * @details \b Outputs: none + * @return treatmentCompleted + *************************************************************************/ +BOOL isTreatmentCompleted( void ) +{ + return treatmentCompleted; +} + +/*********************************************************************//** + * @brief + * The isTreatmentResumeBlocked function determines whether the treatment has + * seen an alarm that prevents resumption. + * @details \b Inputs: resumeBlockedByAlarm + * @details \b Outputs: none + * @return resumeBlockedByAlarm + *************************************************************************/ +BOOL isTreatmentResumeBlocked( void ) +{ + return resumeBlockedByAlarm; +} + +/*********************************************************************//** + * @brief + * The getTreatmentTimeRemainingSecs function determines the number of seconds + * remaining in the treatment. + * @details \b Inputs: presTreatmentTimeSecs, treatmentTimeMS + * @details \b Outputs: none + * @return The number of seconds remaining in the treatment. + *************************************************************************/ +U32 getTreatmentTimeRemainingSecs( void ) +{ + U32 result = CALC_TREAT_TIME_REMAINING_IN_SECS(); + + return result; +} + +/*********************************************************************//** + * @brief + * The getActualTreatmentTimeSecs function determines the actual treatment + * duration in seconds. + * @details \b Inputs: treatmentTimeMS + * @details \b Outputs: none + * @return The actual treatment duration in seconds. + *************************************************************************/ +U32 getActualTreatmentTimeSecs( void ) +{ + return ( treatmentTimeMS / MS_PER_SECOND ); +} + +/*********************************************************************//** + * @brief + * The getTreatmentStartTimeStamp function returns the treatment start + * time stamp. + * @details \b Inputs: treatmentStartTimeStamp + * @details \b Outputs: none + * @return the treatment start time stamp + *************************************************************************/ +U32 getTreatmentStartTimeStamp( void ) +{ + return treatmentStartTimeStamp; +} + +/*********************************************************************//** + * @brief + * The getTreatmentEndTimeStamp function returns the treatment end + * time stamp. + * @details \b Inputs: treatmentEndTimeStamp + * @details \b 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 \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if invalid alarm action given. + * @details \b Inputs: none + * @details \b Outputs: given alarm action executed + * @param action ID of alarm action to execute + * @return none + *************************************************************************/ +void signalAlarmActionToTreatmentMode( ALARM_ACTION_T action ) +{ + switch( action ) + { + case ALARM_ACTION_STOP: + // Stop signal actively polled by mode/sub-mode/state + break; + + case ALARM_ACTION_RESUME: + resumeTreatmentAlarmResponseRequest = TRUE; + break; + + case ALARM_ACTION_RINSEBACK: + initiateRinsebackAlarmResponseRequest = TRUE; + break; + + case ALARM_ACTION_END_TREATMENT: + endTreatmentAlarmResponseRequest = TRUE; + break; + + case ALARM_ACTION_ACK: + // Nothing to be done here + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_INVALID_ALARM_ACTION, (U32)action ) + break; + } +} + +/*********************************************************************//** + * @brief + * The signalRinsebackToTreatmentEnd function signals that user wants to end the + * treatment. + * @details \b Inputs: none + * @details \b Outputs: endTreatmentRequest + * @return none + *************************************************************************/ +void signalEndTreatment( void ) +{ + endTreatmentRequest = TRUE; +} + +/*********************************************************************//** + * @brief + * The execTreatmentMode function executes the Treatment Mode state machine. + * @details Inputs: currentTreatmentState + * @details Outputs: currentTreatmentState + * @return current state (sub-mode) + *************************************************************************/ +U32 execTreatmentMode( void ) +{ + BOOL stop = isStopButtonPressed(); + + // Trigger user stop alarm at any time in treatment mode when user presses stop button + if ( TRUE == stop ) + { + activateAlarmNoData( ALARM_ID_TD_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(); +// } + + // Treatment mode state machine + switch ( currentTreatmentState ) + { + case TREATMENT_START_STATE: + currentTreatmentState = handleTreatmentStartState(); + break; + + case TREATMENT_BLOOD_PRIME_STATE: + currentTreatmentState = handleTreatmentBloodPrimeState(); + break; + + case TREATMENT_DIALYSIS_STATE: + currentTreatmentState = handleTreatmentDialysisState(); + break; + +// case TREATMENT_ISO_UF_STATE: +// currentTreatmentState = handleTreatmentIsoUFState(); +// break; +// +// case TREATMENT_SALINE_BOLUS_STATE: +// currentTreatmentState = handleTreatmentSalineBolusState(); +// break; +// +// case TREATMENT_DIALYSATE_PAUSED_STATE: +// currentTreatmentState = handleTreatmentDialysatePausedState(); +// break; + + case TREATMENT_PAUSED_STATE: + currentTreatmentState = handleTreatmentPausedState(); + break; + + case TREATMENT_RINSEBACK_STATE: + currentTreatmentState = handleTreatmentRinsebackState(); + break; + + case TREATMENT_RECIRC_STATE: + currentTreatmentState = handleTreatmentRecircState(); + break; + + case TREATMENT_END_STATE: + currentTreatmentState = handleTreatmentEndState(); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_INVALID_STATE, (U32)currentTreatmentState ); + break; + } + + // Alarm response request flags should be handled at this point, reset in case not handled in current state + resetAlarmSignalFlags(); + // clear signal flags from sub-modes before calling sub-mode executives + resetSignalFlags(); + + // Broadcast treatment data + broadcastTreatmentTimeAndState(); + broadcastTreatmentSettingsRanges(); + broadcastTreatmentPeriodicData(); + // Publish ultrafiltration data at set interval (whether we are performing UF or not) + publishUltrafiltrationData(); + // Publish saline bolus data at set interval (whether we are delivering one or not) + publishSalineBolusData(); + + // Manage air trap control + execAirTrapMonitorTreatment(); + + return currentTreatmentState; +} + +/*********************************************************************//** + * @brief + * The handleTreatmentStartState function handles the Start state of + * the Treatment Mode state machine. Should only pass through this state + * once at very beginning of treatment. + * @details Inputs: none + * @details Outputs: treatmentTimeMS, lastTreatmentTimeStamp + * @return next treatment mode state + *************************************************************************/ +static TREATMENT_STATE_T handleTreatmentStartState( void ) +{ + TREATMENT_STATE_T result = TREATMENT_BLOOD_PRIME_STATE; + + lastTreatmentTimeStamp = getMSTimerCount(); +// transitionToBloodPrime(); + + return result; +} + +/*********************************************************************//** + * @brief + * The handleTreatmentBloodPrimeState function handles the blood prime state of + * the Treatment Mode state machine. + * @details Inputs: presUFRate + * @details Outputs: none + * @return next treatment mode state + *************************************************************************/ +static TREATMENT_STATE_T handleTreatmentBloodPrimeState( void ) +{ + TREATMENT_STATE_T result = TREATMENT_BLOOD_PRIME_STATE; + +// setRinsebackIsCompleted( FALSE ); + +// // Handle alarm stoppage +// if ( TRUE == doesAlarmStatusIndicateStop() ) +// { +// transitionToTreatmentStop(); +// result = TREATMENT_STOP_STATE; +// } +// else +// { +// execBloodPrime(); +// +// // Handle signals from blood prime sub-mode +// if ( TRUE == bloodPrimeToDialysisRequest ) +// { + lastTreatmentTimeStamp = getMSTimerCount(); + // Kick dialysis sub-mode off + setDialysisBloodPumpFlowRate( getTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW ) ); +// setDialysisDialInFlowAndUFRate( getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), presMaxUFVolumeML, presUFRate ); +// +// if ( presUFRate > 0.0 ) +// { +// sendTreatmentLogEventData( UF_START_RESUME_EVENT, 0.0, presUFRate ); +// } + transitionToDialysis(); +// // To update partial blood pump occlusion baseline - start of treatment +// signalBloodPumpPressureOcclBaseline(); + result = TREATMENT_DIALYSIS_STATE; +// } +// } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleTreatmentDialysisState function handles the Dialysis state of + * the Treatment Mode state machine. + * @details \b Inputs: none + * @details \b Outputs: treatmentTimeMS, lastTreatmentTimeStamp, dialysis sub-mode + * executed. + * @return next treatment mode state + *************************************************************************/ +static TREATMENT_STATE_T handleTreatmentDialysisState( void ) +{ + TREATMENT_STATE_T result = TREATMENT_DIALYSIS_STATE; + U32 newTime = getMSTimerCount(); + U32 msSinceLast = calcTimeBetween( lastTreatmentTimeStamp, newTime ); + DIALYSIS_STATE_T dialysisState = getDialysisState(); + + // Update treatment time + treatmentTimeMS += msSinceLast; + lastTreatmentTimeStamp = newTime; + + // End treatment if treatment duration has been reached + if ( CALC_ELAPSED_TREAT_TIME_IN_SECS() >= presTreatmentTimeSecs ) + { + treatmentCompleted = TRUE; +// sendLastTreatmentPeriodicData = TRUE; +// treatmentEndTimeStamp = getRTCTimestamp(); + pauseDialysis(); + requestNewOperationMode( MODE_STAN ); // TODO transitionToTreatmentEnd(); + //SET_ALARM_WITH_1_U32_DATA( ALARM_ID_TD_END_OF_TREATMENT_WARNING, presTreatmentTimeSecs ); + result = TREATMENT_END_STATE; + } + // Otherwise, execute state machine for treatment dialysis sub-mode + else + { + execDialysis(); + // Handle alarm stoppage + if ( TRUE == doesAlarmStatusIndicateStop() ) + { + transitionToTreatmentPaused(); + result = TREATMENT_PAUSED_STATE; + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleTreatmentPausedState function executes the Paused state of the + * Treatment Mode state machine. + * @details \b Inputs: none + * @details \b Outputs: treatment paused sub-mode executed. + * @return next treatment mode state + *************************************************************************/ +static TREATMENT_STATE_T handleTreatmentPausedState( void ) +{ + TREATMENT_STATE_T result = TREATMENT_PAUSED_STATE; + BOOL leavingTreatmentPausedState = TRUE; + + // If user requests resumption of treatment, resume treatment + if ( TRUE == resumeTreatmentAlarmResponseRequest ) + { + resumeTreatmentAlarmResponseRequest = FALSE; + +// if ( TRUE == getBloodIsPrimed() ) + { + lastTreatmentTimeStamp = getMSTimerCount(); + transitionToDialysis(); + result = TREATMENT_DIALYSIS_STATE; + } +// else +// { +// transitionToBloodPrime(); +// result = TREATMENT_BLOOD_PRIME_STATE; +// } +// signalInitiatePressureStabilization( USE_NORMAL_STABILIZATION_PERIOD ); + } + // If user requests rinseback, go to rinseback +// else if ( TRUE == initiateRinsebackAlarmResponseRequest ) +// { +// transitionToRinseback(); +// result = TREATMENT_RINSEBACK_STATE; +// } + // If user requests treatment end, end treatment +// else if ( TRUE == endTreatmentAlarmResponseRequest ) +// { +// sendLastTreatmentPeriodicData = TRUE; +// requestNewOperationMode( MODE_POST ); +// } + // Otherwise execute state machine for treatment paused sub-mode + else + { + execTreatmentPaused(); + leavingTreatmentPausedState = FALSE; + } + + // If leaving treatment paused state, zero alarm countdown timer for UI +// if ( TRUE == leavingTreatmentPausedState ) +// { +// TREATMENT_STOP_PAYLOAD_T data; +// +// data.timeout = 0; +// data.countdown = 0; +// broadcastData( MSG_ID_TD_TREATMENT_PAUSED_TIMER_DATA, COMM_BUFFER_OUT_CAN_TD_BROADCAST, (U08*)&data, sizeof( TREATMENT_PAUSED_PAYLOAD_T ) ); +// } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleTreatmentRinsebackState function executes the rinseback state of the + * Treatment Mode state machine. + * @details \b Inputs: endTreatmentAlarmResponseRequest, resumeTreatmentAlarmResponseRequest, + * rinsebackToRecircRequest, rinsebackToStoppedRequest, endTreatmentRequest + * @details \b 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; + +// // 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 ) +// { +// transitionToTreatmentRecirc(); +// result = TREATMENT_RECIRC_STATE; +// } +// else if ( TRUE == rinsebackToStoppedRequest ) +// { +// transitionToTreatmentStop(); +// result = TREATMENT_STOP_STATE; +// } +// else if ( TRUE == endTreatmentRequest ) +// { +// requestNewOperationMode( MODE_POST ); +// } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleTreatmentRecircState function executes the re-circulate state of the + * Treatment Mode state machine. + * @details \b Inputs: endTreatmentAlarmResponseRequest, rinsebackToStoppedRequest, + * endTreatmentRequest + * @details \b Outputs: sendLastTreatmentPeriodicData + * @return next treatment mode state + *************************************************************************/ +static TREATMENT_STATE_T handleTreatmentRecircState( void ) +{ + TREATMENT_STATE_T result = TREATMENT_RECIRC_STATE; + +// // 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; +// } +// else if ( TRUE == endTreatmentRequest ) +// { +// requestNewOperationMode( MODE_POST ); +// } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleTreatmentEndState function executes the end state of the + * Treatment Mode state machine. + * @details \b Inputs: none + * @details \b Outputs: treatment end sub-mode executed. + * @return next treatment mode state + *************************************************************************/ +static TREATMENT_STATE_T handleTreatmentEndState( void ) +{ + TREATMENT_STATE_T result = TREATMENT_END_STATE; + +// // Handle final rinseback alarm response from user +// if ( TRUE == initiateRinsebackAlarmResponseRequest ) +// { +// signalTreatmentEndAlarmRinsebackUserAction(); +// } +// // Handle alarm response from user to end treatment w/o rinseback +// else if ( TRUE == endTreatmentAlarmResponseRequest ) +// { +// signalTreatmentEndAlarmEndTxUserAction(); +// } +// // End treatment state does not allow resume +// +// // Execute treatment end sub-mode +// execTreatmentEnd(); +// +// // Handle signals from treatment end sub-mode +// if ( TRUE == treatmentEndToRinsebackRequest ) +// { +// transitionToRinseback(); +// result = TREATMENT_RINSEBACK_STATE; +// } +// else if ( TRUE == endTreatmentRequest ) +// { +// requestNewOperationMode( MODE_POST ); +// } + + return result; +} + +/*********************************************************************//** + * @brief + * The broadcastTreatmentTimeAndState function broadcasts treatment time and + * state data during treatment. + * @details \b Inputs: treatmentTimeBroadcastTimerCtr, elapsedTreatmentTimeInSecs, + * presTreatmentTimeSecs, treatmentStateBroadcastTimerCtr + * @details \b Outputs: treatmentTimeBroadcastTimerCtr, treatmentStateBroadcastTimerCtr + * @return none + *************************************************************************/ +void broadcastTreatmentTimeAndState( void ) +{ + U32 elapsedTreatmentTimeInSecs; + + // Update treatment time stats and broadcast - end treatment if time + elapsedTreatmentTimeInSecs = CALC_ELAPSED_TREAT_TIME_IN_SECS(); + // Broadcast treatment time data at interval + if ( ++treatmentTimeBroadcastTimerCtr >= getU32OverrideValue( &treatmentTimePublishInterval ) ) + { + TREATMENT_TIME_DATA_T payload = { 0, 0, 0 }; + + treatmentTimeBroadcastTimerCtr = 0; + + if ( isTreatmentCompleted() != TRUE ) + { + payload.treatmentTimeElapsedinSec = elapsedTreatmentTimeInSecs; + // if alarm preventing treatment resumption, treatment is essentially over and we want to indicate that with published treatment time data + if ( isTreatmentResumeBlocked() != TRUE ) + { + payload.treatmentTimePrescribedinSec = presTreatmentTimeSecs; + payload.treatmentTimeRemaininginSec = presTreatmentTimeSecs - elapsedTreatmentTimeInSecs; + } + else + { + payload.treatmentTimePrescribedinSec = 0; + payload.treatmentTimeRemaininginSec = 0; + } + } + sendMessage( MSG_ID_TD_TREATMENT_TIME_DATA, COMM_BUFFER_OUT_CAN_TD_BROADCAST, (U08*)(&payload), sizeof( TREATMENT_TIME_DATA_T ) ); + } + + // Broadcast treatment state data at interval + if ( ++treatmentStateBroadcastTimerCtr >= getU32OverrideValue( &treatmentStatePublishInterval ) ) + { + TREATMENT_STATE_DATA_T payload; + + treatmentStateBroadcastTimerCtr = 0; + + payload.treatmentSubMode = (U32)currentTreatmentState; + payload.bldPrimeState = 0; // getCurrentBloodPrimeState(); + payload.dialysisState = getDialysisState(); + payload.txStopState = 0; // getCurrentTreatmentStopState(); + payload.rinsebackState = 0; // getCurrentRinsebackState(); + payload.txRecircState = 0; // getCurrentTreatmentRecircState(); + payload.txEndState = 0; // getCurrentTreatmentEndState(); + + sendMessage( MSG_ID_TD_TREATMENT_STATE_DATA, COMM_BUFFER_OUT_CAN_TD_BROADCAST, (U08*)(&payload), sizeof( TREATMENT_STATE_DATA_T ) ); + } +} + +/*********************************************************************//** + * @brief + * The broadcastTreatmentSettingsRanges function computes and broadcasts + * updated treatment parameter ranges that the user may change during treatment. + * It is assumed that prescription settings have already been set prior to calling + * this function. + * @details \b Inputs: current operating mode, treatment states and parameters + * @details \b Outputs: valid ranges message sent on interval + * @return none + *************************************************************************/ +static void broadcastTreatmentSettingsRanges( void ) +{ + if ( ++treatmentParamsRangesBroadcastTimerCtr >= getU32OverrideValue( &treatmentParamRangesPublishInterval ) ) + { + TREATMENT_PARAM_RANGE_BROADCAST_PAYLOAD_T payload; + // Compute minimum treatment duration + U32 presTime = ( presTreatmentTimeSecs / SEC_PER_MIN ); + U32 elapseTime = CALC_ELAPSED_TREAT_TIME_IN_MIN(); + 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.0F ? (U32)presUFRate : 1 ); + U32 maxTime1 = minTime; // TODO + maxTimeRem; + U32 maxTime2 = MAX_TREATMENT_TIME_MINUTES; + U32 maxTime = MAX( maxTime1, maxTime2 ); + // Compute minimum UF volume + F32 minUFVol = 0.0F; // TODO getUltrafiltrationReferenceVolume() + presUFRate; // current UF volume + 1 min at current rate + // Compute maximum UF volume (considering from adjustment of UF rate and time perspectives) + F32 maxUFVol1 = minUFVol + ( (F32)( presTime - elapseTime ) * MAX_UF_RATE_ML_MIN ); + F32 maxUFVol2 = ( presUFRateLHr > 0.0F ? minUFVol + ( (F32)( MAX_TREATMENT_TIME_MINUTES - elapseTime - 1 ) * presUFRateLHr ) : minUFVol ); + F32 maxUFVol = MAX( maxUFVol1, maxUFVol2 ); + // Set minimum dialysate flow rate + U32 minDialRate = MIN_DIALYSATE_FLOW_RATE; + // Set maximum dialysate flow rate + U32 maxDialRate = MAX_DIALYSATE_FLOW_RATE; + + treatmentParamsRangesBroadcastTimerCtr = 0; + + // Now ensure maximums do not exceed the literal maximums + maxTime = MIN( maxTime, MAX_TREATMENT_TIME_MINUTES ); + maxUFVol = MIN( maxUFVol, (F32)MAX_UF_VOLUME_ML ); + + // Send updated treatment parameter ranges to UI + payload.minTreatmentTime = minTime; + payload.maxTreatmentTime = maxTime; + payload.minUFVolume = minUFVol; + payload.maxUFVolume = maxUFVol; + payload.minDialRate = minDialRate; + payload.maxDialRate = maxDialRate; + sendMessage( MSG_ID_TD_TREATMENT_PARAM_RANGES, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08*)(&payload), sizeof( TREATMENT_PARAM_RANGE_BROADCAST_PAYLOAD_T ) ); + } +} + +/*********************************************************************//** + * @brief + * The broadcastTreatmentPeriodicData function computes and broadcasts + * periodic treatment data during treatment. + * @details \b Inputs: treatmentPeriodDataBroadcastTimerCtr + * @details \b 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 = getFilteredArterialPressure(); +// F32 const venousPres = getFilteredVenousPressure(); +// +// if ( ( TREATMENT_DIALYSIS_STATE == getTreatmentState() ) && ( getDialysisState() != DIALYSIS_SALINE_BOLUS_STATE ) ) +// { +// treatmentBloodFlowRateTotal_mL_min += getMeasuredBloodFlowRate(); +// treatmentDialysateFlowRateTotal_mL_min += getMeasuredDialInFlowRate(); +// treatmentDialysateTempTotal_degree_C += getDialysateTemperature(); +// treatmentArterialPressureTotal_mmHg += arterialPres; +// treatmentVenousPressureTotal_mmHg += venousPres; +// } +// +// lastTreatmentPeriodicDataCollectTimeStamp = treatmentTimeMS; +// bloodFlowRateSum_mL_min += getMeasuredBloodFlowRate(); +// dialysateFlowRateSum_mL_min += getMeasuredDialInFlowRate(); +// arterialPressureSum_mmHg += arterialPres; +// venousPressureSum_mmHg += venousPres; +// } +// +// 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; +// +// 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 = uFVolumeCollected; +// bloodFlowRateSum_mL_min = 0.0; +// dialysateFlowRateSum_mL_min = 0.0; +// arterialPressureSum_mmHg = 0.0; +// venousPressureSum_mmHg = 0.0; +// } +} + +/*********************************************************************//** + * @brief + * The getMinTreatmentTimeInMinutes function returns the minimum treatment + * time (in minutes) that the user could set treatment duration to. + * @details \b Inputs: MIN_TREATMENT_TIME_MINUTES + * @details \b Outputs: none + * @return minimum treatment time in minutes + *************************************************************************/ +static U32 getMinTreatmentTimeInMinutes( void ) +{ + U32 treatmentTime = MIN_TREATMENT_TIME_MINUTES; + + if ( TRUE == getTestConfigStatus( TEST_CONFIG_ENABLE_ONE_MINUTE_TREATMENT ) ) + { + treatmentTime = 1; + } + + return treatmentTime; +} + +/*********************************************************************//** + * @brief + * The signalAlarmActionToServiceMode function executes the given alarm action + * as appropriate while in Service Mode. + * @details \b Inputs: none + * @details \b Outputs: given alarm action executed + * @param action ID of alarm action to execute + * @return none + *************************************************************************/ +//void signalAlarmActionToServiceMode( ALARM_ACTION_T action ) +//{ +// // TODO - implement +//} + +/*********************************************************************//** + * @brief + * The resetSignalFlags function resets all non-alarm signal flags. + * @details \b Inputs: none + * @details \b 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 \b Inputs: none + * @details \b Outputs: alarm signal flags set to FALSE + * @return none + *************************************************************************/ +static void resetAlarmSignalFlags( void ) +{ + resumeTreatmentAlarmResponseRequest = FALSE; + initiateRinsebackAlarmResponseRequest = FALSE; + endTreatmentAlarmResponseRequest = FALSE; +} + +/*********************************************************************//** + * @brief + * The publishSalineBolusData function publishes the saline bolus data + * at the set time interval. + * @details \b Inputs: none + * @details \b Outputs: none + * @param dialysisState next dialysis state + * @return next saline bolus state + *************************************************************************/ +static void publishSalineBolusData( void ) +{ + if ( ++salineBolusBroadcastTimerCtr >= SALINE_BOLUS_DATA_PUB_INTERVAL ) + { + SALINE_BOLUS_DATA_PAYLOAD_T data; + + data.tgtSalineVolumeMl = getTreatmentParameterU32( TREATMENT_PARAM_SALINE_BOLUS_VOLUME ); + data.cumSalineVolumeMl = 0.0F; // TODO + data.bolSalineVolumeMl = 0.0F; // TODO + + sendMessage( MSG_ID_TD_SALINE_BOLUS_DATA, COMM_BUFFER_OUT_CAN_TD_BROADCAST, (U08*)(&data), sizeof( SALINE_BOLUS_DATA_PAYLOAD_T ) ); + salineBolusBroadcastTimerCtr = 0; + } +} + +/*********************************************************************//** + * @brief + * The publishUltrafiltrationData function publishes the ultrafiltration data + * at the set time interval. + * @details \b Inputs: presUFVolumeL, presUFRate + * @details \b Outputs: none + * @return none + *************************************************************************/ +static void publishUltrafiltrationData( void ) +{ + if ( ++ultrafiltrationBroadcastTimerCtr >= ULTRAFILTRATION_DATA_PUB_INTERVAL ) + { + UF_DATA_PAYLOAD_T data; + + data.setUFVolumeL = presUFVolumeL; + data.tgtUFRateLHr = presUFRateLHr; + data.ufVolumeDeliveredL = getUltrafiltrationVolumeDrawn(); + data.ufState = (U32)getDialysisState(); + + sendMessage( MSG_ID_TD_ULTRAFILTRATION_DATA, COMM_BUFFER_OUT_CAN_TD_BROADCAST, (U08*)(&data), sizeof( UF_DATA_PAYLOAD_T ) ); + ultrafiltrationBroadcastTimerCtr = 0; + } +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/**@}*/ Index: firmware/App/Modes/ModeTreatment.h =================================================================== diff -u --- firmware/App/Modes/ModeTreatment.h (revision 0) +++ firmware/App/Modes/ModeTreatment.h (revision cd19fd5095128315982b9ef810bd45e68eff8deb) @@ -0,0 +1,102 @@ +/************************************************************************** +* +* Copyright (c) 2025-2025 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.h +* +* @author (last) Sean +* @date (last) 25-Mar-2025 +* +* @author (original) Sean +* @date (original) 25-Mar-2025 +* +***************************************************************************/ + +#ifndef __MODE_TREATMENT_H__ +#define __MODE_TREATMENT_H__ + +#include "TDCommon.h" +#include "TDDefs.h" + +/** + * @defgroup TDTreatmentMode TDTreatmentMode + * @brief Treatment mode unit. + * + * @addtogroup TDTreatmentMode + * @{ + */ + +// ********** public definitions ********** + +#define MAX_DIALYSATE_FLOW_RATE 600 ///< Maximum dialysate inlet flow rate (in mL/min). +#define MIN_DIALYSATE_FLOW_RATE 50 ///< Minimum dialysate inlet flow rate (in mL/min). + +#pragma pack(push,1) + +/// Payload record structure for a treatment time status message. +typedef struct +{ + U32 treatmentTimePrescribedinSec; ///< Treatment time prescribed in seconds. + U32 treatmentTimeElapsedinSec; ///< Treatment time elapsed in seconds. + U32 treatmentTimeRemaininginSec; ///< Treatment time remaining in seconds. +} TREATMENT_TIME_DATA_T; + +/// Payload record structure for a treatment state message. +typedef struct +{ + U32 treatmentSubMode; ///< Treatment submode. + U32 bldPrimeState; ///< Blood prime state. + U32 dialysisState; ///< Dialysis state. + U32 isoUFState; ///< Isolated ultrafiltration state. + U32 txStopState; ///< Treatment stop state. + U32 rinsebackState; ///< Rinse back state. + U32 txRecircState; ///< Treatment recirc state. + U32 txEndState; ///< Treatment end state. +} TREATMENT_STATE_DATA_T; + +/// Payload record structure for a saline bolus data broadcast message. +typedef struct +{ + U32 tgtSalineVolumeMl; ///< Target saline volume in mL. + F32 cumSalineVolumeMl; ///< Cumulative saline volume in mL. + F32 bolSalineVolumeMl; ///< Bolus saline volume in mL. + U32 salineBolusState; ///< Saline bolus state. +} SALINE_BOLUS_DATA_PAYLOAD_T; + +/// Payload record structure for a ultrafiltration data broadcast message. +typedef struct +{ + F32 setUFVolumeL; ///< Set (prescribed) ultrafiltration in L. + F32 tgtUFRateLHr; ///< Calculated target ultrafiltration rate in L/hr. + F32 ufVolumeDeliveredL; ///< Ultrafiltration volume delivered in L. + U32 ufState; ///< Ultrafiltration state. +} UF_DATA_PAYLOAD_T; + +#pragma pack(pop) + +// ********** public function prototypes ********** + +void initTreatmentMode( void ); // Initialize this unit +U32 transitionToTreatmentMode( void ); // Prepares for transition to treatment mode +U32 execTreatmentMode( void ); // Execute the treatment mode state machine (call from OperationModes) + +void signalAlarmActionToTreatmentMode( ALARM_ACTION_T action ); // Execute alarm action as appropriate for treatment mode +void signalEndTreatment( void ); // Requesting transition to post-treatment mode + +void broadcastTreatmentTimeAndState( void ); // Broadcast the times and states of this treatment + +TREATMENT_STATE_T getTreatmentState( void ); // Determine the current treatment sub-mode (state) +BOOL isTreatmentCompleted( void ); // Determine whether the treatment has completed +BOOL isTreatmentResumeBlocked( void ); // Determine whether the treatment is not allowed to be resumed. +U32 getTreatmentTimeRemainingSecs( void ); // Determine number of seconds remaining in the treatment +U32 getActualTreatmentTimeSecs( void ); // Determine the actual treatment duration in seconds + +U32 getTreatmentStartTimeStamp( void ); // Get the treatment start time stamp +U32 getTreatmentEndTimeStamp( void ); // Get the treatment end time stamp + +/**@}*/ + +#endif Index: firmware/App/Modes/ModeTxParams.c =================================================================== diff -u --- firmware/App/Modes/ModeTxParams.c (revision 0) +++ firmware/App/Modes/ModeTxParams.c (revision cd19fd5095128315982b9ef810bd45e68eff8deb) @@ -0,0 +1,1165 @@ +/************************************************************************** +* +* Copyright (c) 2025-2025 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 ModeTxParams.c +* +* @author (last) Sean +* @date (last) 18-Mar-2025 +* +* @author (original) Sean +* @date (original) 18-Mar-2025 +* +***************************************************************************/ + +#include "TDCommon.h" + +#include "AirPump.h" +#include "AirTrap.h" +#include "BloodFlow.h" +#include "Buttons.h" +#include "Messaging.h" +#include "ModeTreatment.h" +#include "ModeTxParams.h" +#include "OperationModes.h" +#include "Pressures.h" +#include "StateTxDialysis.h" +#include "Utilities.h" +#include "Valve3Way.h" +#include "Valves.h" + +/** + * @addtogroup ModeTxParams + * @{ + */ + +// ********** private definitions ********** + +#define MAX_DIALYSATE_VOLUME_ML ( 150 * ML_PER_LITER ) ///< Maximum dialysate volume (in mL) +#define MAX_HEPARIN_VOLUME_ML 10 ///< Maximum heparin volume ( in mL ) + +#define NO_HEPARIN_PRE_STOP_TIME_SET 0 ///< Zero value indicates no Heparin pre-stop time was set by user + +#define NO_HEPARIN_TYPE_SET 0xFFFFFFFF ///< UI will send this value for Heparin type if Heparin not used +#define INSTIT_CHEM_DISINFECT_ENABLE_RANGE 1 ///< Institutional record chemical disinfect enable/disable allowable range + +/// Record for range and default of treatment parameters. +typedef struct +{ + CRITICAL_DATA_TYPES_T dataType; ///< Data type for the treatment parameter + CRITICAL_DATAS_T min; ///< Minimum of range + CRITICAL_DATAS_T max; ///< Maximum of range + CRITICAL_DATAS_T def; ///< Default value +} TREATMENT_PARAMS_PROPERTIES_T; + +/// Record structure for adjustable treatment parameters +typedef struct +{ + U32 bloodFlowRate_mL_min; ///< Original blood flow rate (in mL/min) set by user before treatment start + U32 dialysateFlowRate_mL_min; ///< Original dialysate flow rate (in mL/min) set by user before treatment start + U32 treatmentDuration_min; ///< Original treatment duration (in min) set by user before treatment start + S32 arterialPressureLimitWindow_mmHg; ///< Original alarm limit window for arterial pressure (in mmHg) set by user before treatment start + S32 venousPressureLimitWindow_mmHg; ///< Original alarm limit window for venous pressure (in mmHg) set by user before treatment start + S32 venousPressureLimitAsymmetric_mmHg; ///< Original alarm limit asymmetric for venous pressure (in mmHg) set by user before treatment start + S32 tmpLimitWindow_mmHg; ///< Original alarm limit window for trans-membrane pressure (in mmHg) set by user before treatment start + F32 uFVolume_L; ///< Original ultrafiltration volume (in L) set by user before treatment start +} ADJ_TREATMENT_PARAMS_T; + +#pragma pack(push, 1) +/// Record structure for response to validate Tx params +typedef struct +{ + BOOL accepted; ///< Command accepted. + U32 reason[ NUM_OF_TREATMENT_PARAMS - 1 ]; ///< Rejection reason codes; 1 for each parameter. +} TREATMENT_PARAMS_VAL_RESP_DATA_PAYLOAD_T; + +/// Record structure for response to validate ultrafiltration volume +typedef struct +{ + BOOL accepted; ///< Command accepted. + U32 rejReason; ///< Rejection reason code (if rejected). + F32 ufVolumeMl; ///< Validated ultrafiltration volume (in mL). +} UF_VOLUME_VAL_RESP_DATA_PAYLOAD_T; +#pragma pack(pop) + +// ********** private data ********** + +static TD_TREATMENT_PARAMS_MODE_STATE_T currentTreatmentParamsState; ///< Current state of treatment parameters mode state machine. + +/// Treatment parameter properties (types, ranges and defaults). +const TREATMENT_PARAMS_PROPERTIES_T TREAT_PARAMS_PROPERTIES[ NUM_OF_TREATMENT_PARAMS ] = +{ + { CRITICAL_DATA_TYPE_U32, {.uInt=100}, {.uInt=500}, {.uInt=100} }, // TREATMENT_PARAM_BLOOD_FLOW + { CRITICAL_DATA_TYPE_U32, {.uInt=100}, {.uInt=600}, {.uInt=100} }, // TREATMENT_PARAM_DIALYSATE_FLOW + { CRITICAL_DATA_TYPE_U32, {.uInt=60}, {.uInt=480}, {.uInt=240} }, // TREATMENT_PARAM_TREATMENT_DURATION + { CRITICAL_DATA_TYPE_U32, {.uInt=100}, {.uInt=300}, {.uInt=100} }, // TREATMENT_PARAM_SALINE_BOLUS_VOLUME + { CRITICAL_DATA_TYPE_U32, {.uInt=0}, {.uInt=2}, {.uInt=0} }, // TREATMENT_PARAM_ACID_CONCENTRATE + { CRITICAL_DATA_TYPE_U32, {.uInt=0}, {.uInt=0}, {.uInt=0} }, // TREATMENT_PARAM_BICARB_CONCENTRATE + { CRITICAL_DATA_TYPE_U32, {.uInt=0}, {.uInt=5}, {.uInt=0} }, // TREATMENT_PARAM_DIALYZER_TYPE + { CRITICAL_DATA_TYPE_U32, {.uInt=0}, {.uInt=60}, {.uInt=30} }, // TREATMENT_PARAM_BP_MEAS_INTERVAL + { CRITICAL_DATA_TYPE_U32, {.uInt=100}, {.uInt=300}, {.uInt=200} }, // TREATMENT_PARAM_RINSEBACK_FLOW_RATE + { CRITICAL_DATA_TYPE_S32, {.sInt=120}, {.sInt=200}, {.sInt=120} }, // TREATMENT_PARAM_ART_PRES_LIMIT_WINDOW + { CRITICAL_DATA_TYPE_S32, {.sInt=100}, {.sInt=200}, {.sInt=100} }, // TREATMENT_PARAM_VEN_PRES_LIMIT_WINDOW + { CRITICAL_DATA_TYPE_S32, {.sInt=20}, {.sInt=35}, {.sInt=20} }, // TREATMENT_PARAM_VEN_PRES_LIMIT_ASYMMETRIC + { CRITICAL_DATA_TYPE_S32, {.sInt=40}, {.sInt=100}, {.sInt=40} }, // TREATMENT_PARAM_TMP_PRES_LIMIT_WINDOW + { CRITICAL_DATA_TYPE_F32, {.sFlt=35.0}, {.sFlt=37.0}, {.sFlt=37.0} }, // TREATMENT_PARAM_DIALYSATE_TEMPERATURE + { CRITICAL_DATA_TYPE_F32, {.sFlt=0.0}, {.sFlt=8.0}, {.sFlt=0.0} }, // TREATMENT_PARAM_UF_VOLUME +}; + +// Current treatment parameter values +static CRITICAL_DATA_T treatmentParameters[ NUM_OF_TREATMENT_PARAMS ]; ///< Treatment parameters. +static CRITICAL_DATAS_T stagedParams[ NUM_OF_TREATMENT_PARAMS ]; ///< Temporary staged treatment parameters for validation and awaiting user confirmation. + +// Original treatment parameter values (for those that can be changed during treatment) +static ADJ_TREATMENT_PARAMS_T origTreatmentParams; ///< Originally set (before treatment) treatment parameters. + +static BOOL validTreatParamsReceived = FALSE; ///< Flag indicates user has provided treatment parameters. +static BOOL treatParamsConfirmed = FALSE; ///< Flag indicates user has confirmed the treatment parameters. +static BOOL treatParamsRejected = FALSE; ///< Flag indicates user has rejected the treatment parameters. +static BOOL treatmentCancelled = FALSE; ///< Flag indicates user has cancelled the treatment. +//static HD_INSTITUTIONAL_RECORD_T hdInstitutionalRecord; ///< Institutional record. + +// ********** private function prototypes ********** + +static void resetAllTreatmentParameters( void ); +static TD_TREATMENT_PARAMS_MODE_STATE_T handleWaitForUI2SendState( void ); +static TD_TREATMENT_PARAMS_MODE_STATE_T handleWaitForUI2ConfirmState( void ); +static BOOL checkTreatmentParamsInRange( U32 *reasons ); +static BOOL checkTreatmentParamsDependencies( U32 *reasons ); +static void extractTreatmentParamsFromPayload( TREATMENT_PARAMS_DATA_PAYLOAD_T payload ); +//static void checkPressureParamsRange( TREATMENT_PARAMS_DATA_PAYLOAD_T* txParams ); +static void sendTreatmentParamsResponse( BOOL rejected, U32 *reasons ); +//static void getInstitutionalRecordEdgeValue( TREATMENT_PARAM_T param, CRITICAL_DATAS_T* value, BOOL isMin ); + +/*********************************************************************//** + * @brief + * The initTreatParamsMode function initializes the Treatment Parameters + * Mode unit. + * @details \b Inputs: none + * @details \b Outputs: Treatment Parameters Mode unit initialized. + * @return none + *************************************************************************/ +void initTreatParamsMode( void ) +{ + currentTreatmentParamsState = TD_TREATMENT_PARAMS_MODE_STATE_WAIT_4_UI_2_SEND; + validTreatParamsReceived = FALSE; + treatParamsConfirmed = FALSE; + treatParamsRejected = FALSE; + treatmentCancelled = FALSE; + // Reset all treatment parameters + resetAllTreatmentParameters(); +} + +/*********************************************************************//** + * @brief + * The transitionToTreatParamsMode function prepares for transition to Treatment + * Parameters mode. + * @details \b Inputs: none + * @details \b Outputs: none + * @return initial state + *************************************************************************/ +U32 transitionToTreatParamsMode( void ) +{ + initTreatParamsMode(); + + // Reset treatment + initTreatmentMode(); + initDialysis(); + +// doorClosedRequired( FALSE, FALSE ); + setCurrentSubState( NO_SUB_STATE ); + + // Set user alarm recovery actions allowed in this mode + setAlarmUserActionEnabled( ALARM_USER_ACTION_RESUME, FALSE ); + setAlarmUserActionEnabled( ALARM_USER_ACTION_RINSEBACK, FALSE ); + setAlarmUserActionEnabled( ALARM_USER_ACTION_END_TREATMENT, FALSE ); + + // Start out with all actuators off in treatment parameters mode + signalBloodPumpHardStop(); + setAirPumpState( AIR_PUMP_STATE_OFF, AIR_PUMP_MOTOR_OFF ); + endAirTrapControl(); + set3WayValveState( H13_VALV, VALVE_3WAY_COMMON_TO_CLOSED_STATE ); + set3WayValveState( H20_VALV, VALVE_3WAY_COMMON_TO_CLOSED_STATE ); + setValvePosition( H1_VALV, VALVE_POSITION_A_INSERT_EJECT ); + setValvePosition( H19_VALV, VALVE_POSITION_A_INSERT_EJECT ); + + // Initialize ultrafiltration volume to zero for now - will be set in later state + setTreatmentParameterF32( TREATMENT_PARAM_UF_VOLUME, 0.0F ); + + // Request the concentrate pumps mixing ratios and the DG fill mode prepare time +// cmdRequestDGMixingRatios(); + + // Get the institutional record upon transitioning to treatment parameters +// getNVRecord2Driver( GET_INSTITUTIONAL_RECORD, (U08*)&hdInstitutionalRecord, sizeof( HD_INSTITUTIONAL_RECORD_T ), 0, ALARM_ID_NO_ALARM ); + + return currentTreatmentParamsState; +} + +/*********************************************************************//** + * @brief + * The resetAllTreatmentParameters function resets treatment parameters + * to default values. + * @details \b Inputs: none + * @details \b Outputs: All treatment parameters reset to default values. + * @return none + *************************************************************************/ +static void resetAllTreatmentParameters( void ) +{ + TREATMENT_PARAM_T param; + + for ( param = TREATMENT_PARAM_FIRST_UINT; param < NUM_OF_TREATMENT_PARAMS; param++ ) + { + // Set type, range, and default value for each treatment parameter + treatmentParameters[ param ].typ = TREAT_PARAMS_PROPERTIES[ param ].dataType; + treatmentParameters[ param ].minimum = TREAT_PARAMS_PROPERTIES[ param ].min; + treatmentParameters[ param ].maximum = TREAT_PARAMS_PROPERTIES[ param ].max; + treatmentParameters[ param ].defValue = TREAT_PARAMS_PROPERTIES[ param ].def; + resetCriticalData( &treatmentParameters[ param ] ); + // Set staged parameter values to zero + stagedParams[ param ].uInt = 0; + } + + // Zero original parameter values + origTreatmentParams.bloodFlowRate_mL_min = 0; + origTreatmentParams.dialysateFlowRate_mL_min = 0; + origTreatmentParams.treatmentDuration_min = 0; + origTreatmentParams.arterialPressureLimitWindow_mmHg = 0; + origTreatmentParams.venousPressureLimitWindow_mmHg = 0; + origTreatmentParams.venousPressureLimitAsymmetric_mmHg = 0; + origTreatmentParams.tmpLimitWindow_mmHg = 0; + origTreatmentParams.uFVolume_L = 0.0F; +} + +/*********************************************************************//** + * @brief + * The setTreatmentParameterU32 function sets a given unsigned integer + * treatment parameter to a given value. + * @details \b Inputs: treatmentParameters[] + * @details \b Outputs: treatmentParameters[] + * @param param ID of treatment parameter to set unsigned integer value for + * @param value unsigned integer value to assign to given treatment parameter + * @return TRUE if set was successful, FALSE if not + *************************************************************************/ +BOOL setTreatmentParameterU32( TREATMENT_PARAM_T param, U32 value ) +{ + CRITICAL_DATAS_T integerData; + BOOL result = FALSE; + + integerData.uInt = value; + result = isTreatmentParamInRange( param, integerData ); + + // Validate parameter + if ( param <= TREATMENT_PARAM_LAST_UINT ) + { + if ( TRUE == result ) + { + CRITICAL_DATAS_T data = treatmentParameters[ param ].data; + + data.uInt = value; + result = setCriticalData( &treatmentParameters[ param ], data ); + } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_PARAMS_INVALID_SET_U32_PARAM, (U32)param ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The setTreatmentParameterS32 function sets a given signed integer treatment + * parameter to a given value. + * @details \b Inputs: treatmentParameters[] + * @details \b Outputs: treatmentParameters[] + * @param param ID of treatment parameter to set signed integer value for + * @param value signed integer value to assign to given treatment parameter + * @return TRUE if set was successful, FALSE if not + *************************************************************************/ +BOOL setTreatmentParameterS32( TREATMENT_PARAM_T param, S32 value ) +{ + CRITICAL_DATAS_T unsignedIntData; + BOOL result = FALSE; + + unsignedIntData.sInt = value; + result = isTreatmentParamInRange( param, unsignedIntData ); + + // Validate parameter + if ( ( param >= TREATMENT_PARAM_FIRST_INT ) && ( param <= TREATMENT_PARAM_LAST_INT ) ) + { + if ( TRUE == result ) + { + CRITICAL_DATAS_T data = treatmentParameters[ param ].data; + + data.sInt = value; + result = setCriticalData( &treatmentParameters[ param ], data ); + } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_PARAMS_INVALID_SET_S32_PARAM, (U32)param ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The setTreatmentParameterF32 sets a given floating point treatment parameter + * to a given value. + * @details \b Inputs: treatmentParameters[] + * @details \b Outputs: treatmentParameters[] + * @param param ID of treatment parameter to set floating point value for + * @param value floating point value to assign to given treatment parameter + * @return TRUE if set was successful, FALSE if not + *************************************************************************/ +BOOL setTreatmentParameterF32( TREATMENT_PARAM_T param, F32 value ) +{ + CRITICAL_DATAS_T floatData; + BOOL result = FALSE; + + floatData.sFlt = value; + result = isTreatmentParamInRange( param, floatData ); + + // Validate parameter + if ( ( param >= TREATMENT_PARAM_FIRST_F32 ) && ( param < NUM_OF_TREATMENT_PARAMS ) ) + { + if ( TRUE == result ) + { + CRITICAL_DATAS_T data = treatmentParameters[ param ].data; + + data.sFlt = value; + result = setCriticalData( &treatmentParameters[ param ], data ); + } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_PARAMS_INVALID_SET_F32_PARAM, (U32)param ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getTreatmentParameterU32 function gets the value of a given unsigned + * integer treatment parameter. + * @details \b Inputs: treatmentParameters[] + * @details \b Outputs: none + * @param param ID of treatment parameter to get unsigned integer value for + * @return value of given unsigned integer treatment parameter + *************************************************************************/ +U32 getTreatmentParameterU32( TREATMENT_PARAM_T param ) +{ + U32 result = 1; + + // Validate parameter + if ( param <= TREATMENT_PARAM_LAST_UINT ) + { + CRITICAL_DATAS_T data = getCriticalData( &treatmentParameters[ param ] ); + + result = data.uInt; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_PARAMS_INVALID_GET_U32_PARAM, (U32)param ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getTreatmentParameterS32 function gets the value of a given signed + * integer treatment parameter. + * @details \b Inputs: treatmentParameters[] + * @details \b Outputs: none + * @param param ID of treatment parameter to get signed integer value for + * @return value of given signed integer treatment parameter + *************************************************************************/ +S32 getTreatmentParameterS32( TREATMENT_PARAM_T param ) +{ + S32 result = 1; + + // Validate parameter + if ( ( param >= TREATMENT_PARAM_FIRST_INT ) && ( param <= TREATMENT_PARAM_LAST_INT ) ) + { + CRITICAL_DATAS_T data = getCriticalData( &treatmentParameters[ param ] ); + + result = data.sInt; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_PARAMS_INVALID_GET_S32_PARAM, (U32)param ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getTreatmentParameterF32 function gets the value of a given floating point + * treatment parameter. + * @details \b Inputs: treatmentParameters[] + * @details \b Outputs: none + * @param param ID of treatment parameter to get floating point value for + * @return value of given floating point treatment parameter + *************************************************************************/ +F32 getTreatmentParameterF32( TREATMENT_PARAM_T param ) +{ + F32 result = 1.0; + + // Validate parameter + if ( ( param >= TREATMENT_PARAM_FIRST_F32 ) && ( param < NUM_OF_TREATMENT_PARAMS ) ) + { + CRITICAL_DATAS_T data = getCriticalData( &treatmentParameters[ param ] ); + + result = data.sFlt; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_PARAMS_INVALID_GET_F32_PARAM, (U32)param ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getTreatmentParameterS32DefaultValue function gets the defaultvalue + * of a given signed integer treatment parameter. + * @details \b Inputs: treatmentParameters[] + * @details \b Outputs: none + * @param param ID of treatment parameter to get signed integer default value for + * @return default value of given signed integer treatment parameter + *************************************************************************/ +S32 getTreatmentParameterS32DefaultValue( TREATMENT_PARAM_T param ) +{ + return TREAT_PARAMS_PROPERTIES[ param ].def.sInt; +} + +/*********************************************************************//** + * @brief + * The validateAndSetTreatmentParameters function validates received + * treatment parameters. + * @details \b Inputs: none + * @details \b Outputs: stagedParams[], response sent + * @param message set message from UI which includes the user set treatment + * parameters record. + * @return TRUE if received treatment parameters are valid, FALSE if not + *************************************************************************/ +BOOL validateAndSetTreatmentParameters( MESSAGE_T *message ) +{ + BOOL paramsAreInvalid = TRUE; + BOOL paramsAreInRange, paramsAreConsistent; + BOOL result = FALSE; + TREATMENT_PARAMS_DATA_PAYLOAD_T params; + U32 rejReasons[ NUM_OF_TREATMENT_PARAMS ]; + + // Verify message payload length is valid + if ( sizeof( TREATMENT_PARAMS_DATA_PAYLOAD_T ) == message->hdr.payloadLen ) + { + memcpy( ¶ms, message->payload, sizeof( TREATMENT_PARAMS_DATA_PAYLOAD_T ) ); + + // Check the received arterial and venous pressure values from the UI to be checked and capped against the min and max + // values in the institutional record + // checkPressureParamsRange( ¶ms ); // TODO + + // Extract treatment parameters from given payload to staging array so we can more easily work with them + extractTreatmentParamsFromPayload( params ); + + // Range check each treatment parameter + paramsAreInRange = checkTreatmentParamsInRange( &rejReasons[0] ); + + // Validate dependencies + paramsAreConsistent = TRUE; // checkTreatmentParamsDependencies( &rejReasons[0] ); // TODO + + // Determine overall validity of received treatment parameters + if ( ( TRUE == paramsAreInRange ) && ( TRUE == paramsAreConsistent ) ) + { + paramsAreInvalid = FALSE; + validTreatParamsReceived = TRUE; + } + } + + // Respond to set treatment parameters request message + sendTreatmentParamsResponse( paramsAreInvalid, &rejReasons[0] ); + // Send initial adjustable ranges to UI so UF volume range will be known when UF volume prompted for later + if ( TRUE == validTreatParamsReceived ) + { + U32 setTxDuration = stagedParams[ TREATMENT_PARAM_TREATMENT_DURATION ].uInt; + TREATMENT_PARAM_RANGE_BROADCAST_PAYLOAD_T payload; + + payload.minTreatmentTime = treatmentParameters[ TREATMENT_PARAM_TREATMENT_DURATION ].minimum.uInt; + payload.maxTreatmentTime = treatmentParameters[ TREATMENT_PARAM_TREATMENT_DURATION ].maximum.uInt; + payload.minUFVolume = 0.0F; + payload.maxUFVolume = MIN( (F32)setTxDuration * MAX_UF_RATE_ML_MIN, (F32)MAX_UF_VOLUME_ML ); + payload.minDialRate = treatmentParameters[ TREATMENT_PARAM_DIALYSATE_FLOW ].minimum.uInt; + payload.maxDialRate = treatmentParameters[ TREATMENT_PARAM_DIALYSATE_FLOW ].maximum.uInt; + sendMessage( MSG_ID_TD_TREATMENT_PARAM_RANGES, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08*)(&payload), sizeof( TREATMENT_PARAM_RANGE_BROADCAST_PAYLOAD_T ) ); + } + + result = ( TRUE == paramsAreInvalid ? FALSE : TRUE ); + + return result; +} + +/*********************************************************************//** + * @brief + * The checkTreatmentParamsInRange function checks whether received + * treatment parameters are in range. + * @details \b Inputs: stagedParams[] + * @details \b Outputs: reasons[] + * @param reasons Pointer to array of reject reason codes for each parameter + * @return TRUE if treatment parameters are in range, FALSE if not + *************************************************************************/ +static BOOL checkTreatmentParamsInRange( U32 *reasons ) +{ + BOOL result = TRUE; + TREATMENT_PARAM_T param; + + // Range check treatment parameters up to (but not including) UF volume + for ( param = TREATMENT_PARAM_FIRST_UINT; param < TREATMENT_PARAM_UF_VOLUME; param++ ) + { + if ( FALSE == isTreatmentParamInRange( param, stagedParams[ param ] ) ) + { + reasons[ param ] = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + result = FALSE; + } + else + { + reasons[ param ] = REQUEST_REJECT_REASON_NONE; + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The validateAndSetUFVolume function validates received ultrafiltration + * volume treatment parameter. + * @details \b Inputs: none + * @details \b Outputs: + * @param message set message from UI which includes the user set ultrafiltration + * volume (in mL). + * @return TRUE if received UF volume parameter is valid, FALSE if not + *************************************************************************/ +BOOL validateAndSetUFVolume( MESSAGE_T *message ) +{ + BOOL accepted = FALSE; + REQUEST_REJECT_REASON_CODE_T rejReason = REQUEST_REJECT_REASON_NONE; + F32 uFVolumeMl; + F32 uFVolumeL; + + // Verify message payload length is valid + if ( sizeof( F32 ) == message->hdr.payloadLen ) + { + UF_VOLUME_VAL_RESP_DATA_PAYLOAD_T respPayload; + + memcpy( &uFVolumeMl, message->payload, sizeof( F32 ) ); + uFVolumeL = uFVolumeMl / (F32)ML_PER_LITER; + + // Validate given UF volume + accepted = setTreatmentParameterF32( TREATMENT_PARAM_UF_VOLUME, uFVolumeL ); + + if ( TRUE == accepted ) + { + U32 treatmentDuration = getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION ); + + // store the user set ultrafiltration volume in pre-treatment parameters setup, if it is validated, otherwise keep the initial 0.0 + origTreatmentParams.uFVolume_L = uFVolumeL; + + if ( treatmentDuration > 0 ) + { + F32 uFRate = uFVolumeMl / (F32)treatmentDuration; + + if ( ( uFRate > MAX_UF_RATE_ML_MIN ) || ( uFRate < MIN_UF_RATE_ML_MIN ) ) + { + accepted = FALSE; + rejReason = REQUEST_REJECT_REASON_UF_RATE_OUT_OF_RANGE; + } + } + else + { + accepted = FALSE; + rejReason = REQUEST_REJECT_REASON_TREATMENT_TIME_LESS_THAN_MINIMUM; + } + } + else + { + rejReason = REQUEST_REJECT_REASON_UF_VOLUME_OUT_OF_RANGE; + } + + // Respond to set UF volume request message + uFVolumeL = getTreatmentParameterF32( TREATMENT_PARAM_UF_VOLUME ); + uFVolumeMl = uFVolumeL * (F32)ML_PER_LITER; + respPayload.accepted = accepted; + respPayload.rejReason = rejReason; + respPayload.ufVolumeMl = uFVolumeMl; + sendMessage( MSG_ID_TD_RESP_ULTRAFILTRATION_VOLUME_TO_VALIDATE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08*)(&respPayload), sizeof( UF_VOLUME_VAL_RESP_DATA_PAYLOAD_T ) ); + // setUserSetUFVolumeStatus( accepted ); // TODO - tell pre-tx whether UF volume has been set and accepted + } + + return accepted; +} + +/*********************************************************************//** + * @brief + * The signalUserConfirmationOfTreatmentParameters function sets the user + * confirmation flag signaling user has confirmed or rejected treatment + * parameters. + * @details \b Inputs: none + * @details \b Outputs: treatParamsConfirmed, treatParamsRejected + * @param message confirmation message from UI which includes the user + * confirmation or rejection. + * @return TRUE if confirmation/rejection accepted, FALSE if not + *************************************************************************/ +BOOL signalUserConfirmationOfTreatmentParameters( MESSAGE_T *message ) +{ + BOOL result = FALSE; + BOOL confirmed = FALSE; + + // Verify message payload length is valid + if ( sizeof( BOOL ) == message->hdr.payloadLen ) + { + memcpy( &confirmed, message->payload, sizeof( BOOL ) ); + if ( ( MODE_TPAR == getCurrentOperationMode() ) && ( TD_TREATMENT_PARAMS_MODE_STATE_WAIT_4_UI_2_CONFIRM == currentTreatmentParamsState ) ) + { + treatParamsConfirmed = ( TRUE == confirmed ? TRUE : FALSE ); + treatParamsRejected = ( TRUE == confirmed ? FALSE : TRUE ); + result = TRUE; + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The signalUserCancelTreatment function sets the cancelled treatment + * flag signaling the user has cancelled the treatment. + * @details \b Inputs: none + * @details \b Outputs: treatmentCancelled + * @return TRUE if cancel accepted, FALSE if not + *************************************************************************/ +BOOL signalUserCancelTreatment( void ) +{ + BOOL result = FALSE; + + if ( MODE_TPAR == getCurrentOperationMode() ) + { + treatmentCancelled = TRUE; + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The signalAlarmActionToTreatParamsMode function executes the given alarm action + * as appropriate while in Treatment Parameters Mode. + * @details \b Inputs: none + * @details \b Outputs: given alarm action executed + * @param action ID of alarm action to execute + * @return none + *************************************************************************/ +void signalAlarmActionToTreatParamsMode( ALARM_ACTION_T action ) +{ + // No special handling of alarm actions in this mode. +} + +/*********************************************************************//** + * @brief + * The execTreatParamsMode function executes the Treatment Parameters Mode + * state machine. + * @details \b Inputs: none + * @details \b Outputs: none + * @return current state (sub-mode) + *************************************************************************/ +U32 execTreatParamsMode( void ) +{ + TD_TREATMENT_PARAMS_MODE_STATE_T priorSubState = currentTreatmentParamsState; + BOOL stop = isStopButtonPressed(); + + if ( TRUE == stop ) + { + // Ignore stop button in this mode. + } + + // Execute mode state machine + switch ( currentTreatmentParamsState ) + { + case TD_TREATMENT_PARAMS_MODE_STATE_WAIT_4_UI_2_SEND: + currentTreatmentParamsState = handleWaitForUI2SendState(); + break; + + case TD_TREATMENT_PARAMS_MODE_STATE_WAIT_4_UI_2_CONFIRM: + currentTreatmentParamsState = handleWaitForUI2ConfirmState(); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_PARAMS_INVALID_STATE, (U32)currentTreatmentParamsState ) + break; + + } + + if ( priorSubState != currentTreatmentParamsState ) + { + SEND_EVENT_WITH_2_U32_DATA( TD_EVENT_SUB_MODE_CHANGE, priorSubState, currentTreatmentParamsState ); + } + + return (U32)currentTreatmentParamsState; +} + +/*********************************************************************//** + * @brief + * The handleWaitForUI2SendState function handles the wait for UI to send + * treatment parameters state of treatment parameters mode. + * @details Inputs: + * @details Outputs: + * @return current state (sub-mode) + *************************************************************************/ +static TD_TREATMENT_PARAMS_MODE_STATE_T handleWaitForUI2SendState( void ) +{ + TD_TREATMENT_PARAMS_MODE_STATE_T result = TD_TREATMENT_PARAMS_MODE_STATE_WAIT_4_UI_2_SEND; + + if ( TRUE == treatmentCancelled ) + { + // Go back to standby mode + requestNewOperationMode( MODE_STAN ); + treatmentCancelled = FALSE; + } + else if ( TRUE == validTreatParamsReceived ) + { + // Go to wait for user confirmation state + result = TD_TREATMENT_PARAMS_MODE_STATE_WAIT_4_UI_2_CONFIRM; + validTreatParamsReceived = FALSE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleWaitForUI2ConfirmState function handles the wait for UI to send + * user confirmation state of treatment parameters mode. + * @details \b Inputs: + * @details \b Outputs: + * @return current state (sub-mode) + *************************************************************************/ +static TD_TREATMENT_PARAMS_MODE_STATE_T handleWaitForUI2ConfirmState( void ) +{ + TD_TREATMENT_PARAMS_MODE_STATE_T result = TD_TREATMENT_PARAMS_MODE_STATE_WAIT_4_UI_2_CONFIRM; + + // If user confirms treatment parameters, set them + if ( TRUE == treatParamsConfirmed ) + { + TREATMENT_PARAM_T param; + + // Set all treatment parameters (except UF volume which is not yet received) + for ( param = TREATMENT_PARAM_FIRST_UINT; param < NUM_OF_TREATMENT_PARAMS; param++ ) + { + setCriticalData( &treatmentParameters[ param ], stagedParams[ param ] ); + } + // Retain original settings for treatment that may be adjusted later during treatment + origTreatmentParams.bloodFlowRate_mL_min = getCriticalData( &treatmentParameters[ TREATMENT_PARAM_BLOOD_FLOW ] ).uInt; + origTreatmentParams.dialysateFlowRate_mL_min = getCriticalData( &treatmentParameters[ TREATMENT_PARAM_DIALYSATE_FLOW ] ).uInt; + origTreatmentParams.treatmentDuration_min = getCriticalData( &treatmentParameters[ TREATMENT_PARAM_TREATMENT_DURATION ] ).uInt; + origTreatmentParams.arterialPressureLimitWindow_mmHg = getCriticalData( &treatmentParameters[ TREATMENT_PARAM_ART_PRES_LIMIT_WINDOW ] ).sInt; + origTreatmentParams.venousPressureLimitWindow_mmHg = getCriticalData( &treatmentParameters[ TREATMENT_PARAM_VEN_PRES_LIMIT_WINDOW ] ).sInt; + origTreatmentParams.venousPressureLimitAsymmetric_mmHg = getCriticalData( &treatmentParameters[ TREATMENT_PARAM_VEN_PRES_LIMIT_ASYMMETRIC ] ).sInt; + + // initialize pressure limit settings in pressure driver + setPressureLimitsToOuterBounds(); + + // Go to pre-treatment mode +// requestNewOperationMode( MODE_PRET ); // TODO - restore when pre-tx mode implemented + requestNewOperationMode( MODE_TREA ); + + treatParamsConfirmed = FALSE; + } + else if ( TRUE == treatParamsRejected ) + { + treatParamsRejected = FALSE; + // User rejected last parameter set, so reset them and wait for new set + resetAllTreatmentParameters(); + result = TD_TREATMENT_PARAMS_MODE_STATE_WAIT_4_UI_2_SEND; + } + else if ( TRUE == treatmentCancelled ) + { + // Go back to standby mode + requestNewOperationMode( MODE_STAN ); + treatmentCancelled = FALSE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The extractTreatmentParamsFromPayload function extracts the individual + * treatment parameters received from the UI into a staging array where + * they will be validated and stay until user confirms them. + * @details \b Inputs: none + * @details \b Outputs: stagedParams[] + * @param payload message payload record containing received treatment parameters + * @return none + *************************************************************************/ +static void extractTreatmentParamsFromPayload( TREATMENT_PARAMS_DATA_PAYLOAD_T payload ) +{ + // Pull treatment parameters into data array so we can more easily work with them + memcpy( &stagedParams[0], &payload, sizeof(TREATMENT_PARAMS_DATA_PAYLOAD_T) ); +} + +/*********************************************************************//** + * @brief + * The sendTreatmentParamsResponse function responds to the treatment parameters + * received from the UI. An over-all ok/rejected flag as well as individual reject + * reason codes for each parameter are provided back to the UI. + * @details \b Inputs : none + * @details \b Outputs : Response to treatment parameters message constructed and sent. + * @param rejected 1 if rejected, 0 if parameters ok + * @param reasons array of reject reason codes for each parameter (0=not rejected) + * @return none + *************************************************************************/ +static void sendTreatmentParamsResponse( BOOL rejected, U32 *reasons ) +{ + TREATMENT_PARAMS_VAL_RESP_DATA_PAYLOAD_T payload; + + payload.accepted = ( TRUE == rejected ? FALSE : TRUE ); + memcpy( &payload.reason[0], &reasons[0], sizeof( TREATMENT_PARAMS_DATA_PAYLOAD_T ) ); + sendMessage( MSG_ID_TD_RESP_TREATMENT_PARAMS_TO_VALIDATE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08*)(&payload), sizeof( TREATMENT_PARAMS_VAL_RESP_DATA_PAYLOAD_T ) ); +} + +/*********************************************************************//** + * @brief + * The isTreatmentParamInRange function determines whether a given treatment + * parameter is in range. + * @details \b Inputs: treatParamsRanges[], hdInstitutionalRecord + * @details \b Outputs: none + * @param param ID of parameter to check range for + * @param value value of parameter to check range for + * @return TRUE if given treatment parameter is in range, FALSE if not + *************************************************************************/ +BOOL isTreatmentParamInRange( TREATMENT_PARAM_T param, CRITICAL_DATAS_T value ) +{ + BOOL result = TRUE; // TODO FALSE; + + if ( param < NUM_OF_TREATMENT_PARAMS ) + { +// switch( param ) +// { +// case TREATMENT_PARAM_BLOOD_FLOW: +// result = ( ( value.uInt >= hdInstitutionalRecord.minBloodFlowMLPM ) && +// ( value.uInt <= hdInstitutionalRecord.maxBloodFlowMLPM ) ? TRUE : FALSE ); +// break; +// +// case TREATMENT_PARAM_DIALYSATE_FLOW: +// result = ( ( value.uInt >= hdInstitutionalRecord.minDialysateFlowMLPM ) && +// ( value.uInt <= hdInstitutionalRecord.maxDialysateFlowMLPM ) ? TRUE : FALSE ); +// break; +// +// case TREATMENT_PARAM_TREATMENT_DURATION: +// result = ( ( value.uInt >= hdInstitutionalRecord.minTxDurationMIN ) && +// ( value.uInt <= hdInstitutionalRecord.maxTxDurationMIN ) ? TRUE : FALSE ); +// // If the 1-minute treatment is selected, it is ok to accept the time. This test configuration specifically checks for a 1-minute run +// result |= ( TRUE == getTestConfigStatus( TEST_CONFIG_ENABLE_ONE_MINUTE_TREATMENT ) ? TRUE : FALSE ); +// break; +// +// case TREATMENT_PARAM_SALINE_BOLUS_VOLUME: +// result = ( ( value.uInt >= hdInstitutionalRecord.minSalineBolusVolumeML ) && +// ( value.uInt <= hdInstitutionalRecord.maxSalineBolusVolumeML ) ? TRUE : FALSE ); +// break; +// +// case TREATMENT_PARAM_DIALYSATE_TEMPERATURE: +// result = ( ( value.sFlt >= hdInstitutionalRecord.minDialysateTempC ) && +// ( value.sFlt <= hdInstitutionalRecord.maxDialysateTempC ) ? TRUE : FALSE ); +// break; +// +// case TREATMENT_PARAM_ART_PRES_LIMIT_WINDOW: +// result = ( ( value.sInt >= hdInstitutionalRecord.minArtPressLimitWindowMMHG ) && +// ( value.sInt <= hdInstitutionalRecord.maxArtPressLimitWindowMMHG ) ? TRUE : FALSE ); +// break; +// +// case TREATMENT_PARAM_VEN_PRES_LIMIT_WINDOW: +// result = ( ( value.sInt >= hdInstitutionalRecord.minVenPressLimitWindowMMHG ) && +// ( value.sInt <= hdInstitutionalRecord.maxVenPressLimitWindowMMHG ) ? TRUE : FALSE ); +// break; +// +// case TREATMENT_PARAM_VEN_PRES_LIMIT_ASYMMETRIC: +// result = ( ( value.sInt >= hdInstitutionalRecord.minVenAsymPressLimitMMHG ) && +// ( value.sInt <= hdInstitutionalRecord.maxVenAsymPressLimitMMHG ) ? TRUE : FALSE ); +// break; +// +// case TREATMENT_PARAM_TMP_PRES_LIMIT_WINDOW: +// result = ( ( value.sInt >= hdInstitutionalRecord.minTmpPressLimitWindowMMHG ) && +// ( value.sInt <= hdInstitutionalRecord.maxTmpPressLimitWindowMMHG ) ? TRUE : FALSE ); +// break; +// +// case TREATMENT_PARAM_UF_VOLUME: +// result = ( ( value.sFlt >= hdInstitutionalRecord.minUFVolumeL ) && ( value.sFlt <= hdInstitutionalRecord.maxUFVolumeL ) ? TRUE : FALSE ); +// result |= ( fabs( value.sFlt ) <= NEARLY_ZERO ? TRUE : FALSE ); // There might be a minimum UF volume set in the institutional record but a treatment with 0 vol should be allowed +// break; +// +// default: +//#ifndef _VECTORCAST_ +// // The treatment parameters that do not have any institutional record. +// // Right now, all the F32 and S32 data types are covered in the institutional record and therefore, there is no test case that is either F32 or S32 +// // and gets here so it is removed from VectorCAST to be able to achieve 100% coverage of the function +// // The treatment parameters that do not have any institutional record. +// if ( CRITICAL_DATA_TYPE_U32 == TREAT_PARAMS_PROPERTIES[ param ].dataType ) +//#endif +// { +// result = ( ( value.uInt >= TREAT_PARAMS_PROPERTIES[ param ].min.uInt ) && +// ( value.uInt <= TREAT_PARAMS_PROPERTIES[ param ].max.uInt ) ? TRUE : FALSE ); +// } +//#ifndef _VECTORCAST_ +// // Right now, all the F32 and S32 data types are covered in the institutional record and therefore, there is no test case that is either F32 or S32 +// // and gets here so it is removed from VectorCAST to be able to achieve 100% coverage of the function +// else if ( CRITICAL_DATA_TYPE_S32 == TREAT_PARAMS_PROPERTIES[ param ].dataType ) +// { +// result = ( ( value.sInt >= TREAT_PARAMS_PROPERTIES[ param ].min.sInt ) && +// ( value.sInt <= TREAT_PARAMS_PROPERTIES[ param ].max.sInt ) ? TRUE : FALSE ); +// } +// else +// { +// result = ( ( value.sFlt >= TREAT_PARAMS_PROPERTIES[ param ].min.sFlt ) && +// ( value.sFlt <= TREAT_PARAMS_PROPERTIES[ param ].max.sFlt ) ? TRUE : FALSE ); +// } +//#endif +// } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_PARAMS_INVALID_PARAM, (U32)param ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getS32TreatmentParamLowerRangeLimit function returns the lower range + * limit for a given signed integer treatment parameter. + * @details \b Inputs: none + * @details \b Outputs: none + * @param param ID of parameter to get lower range limit for + * @return lower range limit for given signed integer treatment parameter + *************************************************************************/ +S32 getS32TreatmentParamLowerRangeLimit( TREATMENT_PARAM_T param ) +{ + S32 result = 0; + + if ( param < NUM_OF_TREATMENT_PARAMS ) + { + CRITICAL_DATAS_T value; + // getInstitutionalRecordEdgeValue( param, &value, TRUE ); TODO + value = treatmentParameters[ param ].minimum; + result = value.sInt; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_PARAMS_INVALID_GET_S32_PARAM_MIN_LIMIT, (U32)param ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getS32TreatmentParamUpperRangeLimit function returns the upper range + * limit for a given signed integer treatment parameter. + * @details \b Inputs: none + * @details \b Outputs: none + * @param param ID of parameter to get upper range limit for + * @return upper range limit for given signed integer treatment parameter + *************************************************************************/ +S32 getS32TreatmentParamUpperRangeLimit( TREATMENT_PARAM_T param ) +{ + S32 result = 0; + + if ( param < NUM_OF_TREATMENT_PARAMS ) + { + CRITICAL_DATAS_T value; +// getInstitutionalRecordEdgeValue( param, &value, FALSE ); // TODO + value = treatmentParameters[ param ].maximum; + result = value.sInt; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_PARAMS_INVALID_GET_S32_PARAM_MAX_LIMIT, (U32)param ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getU32TreatmentParamLowerRangeLimit function returns the lower range + * limit for a given unsigned integer treatment parameter. + * @details \b Inputs: none + * @details \b Outputs: none + * @param param ID of parameter to get lower range limit for + * @return lower range limit for given unsigned integer treatment parameter + *************************************************************************/ +U32 getU32TreatmentParamLowerRangeLimit( TREATMENT_PARAM_T param ) +{ + U32 result = 0; + + if ( param < NUM_OF_TREATMENT_PARAMS ) + { + CRITICAL_DATAS_T value; +// getInstitutionalRecordEdgeValue( param, &value, TRUE ); // TODO + value = treatmentParameters[ param ].minimum; + result = value.uInt; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_PARAMS_INVALID_GET_U32_PARAM_MIN_LIMIT, (U32)param ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getU32TreatmentParamUpperRangeLimit function returns the upper range + * limit for a given unsigned integer treatment parameter. + * @details \b Inputs: none + * @details \b Outputs: none + * @param param ID of parameter to get upper range limit for + * @return upper range limit for given unsigned integer treatment parameter + *************************************************************************/ +U32 getU32TreatmentParamUpperRangeLimit( TREATMENT_PARAM_T param ) +{ + U32 result = 0; + + if ( param < NUM_OF_TREATMENT_PARAMS ) + { + CRITICAL_DATAS_T value; +// getInstitutionalRecordEdgeValue( param, &value, FALSE ); // TODO + value = treatmentParameters[ param ].maximum; + result = value.uInt; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_PARAMS_INVALID_GET_U32_PARAM_MAX_LIMIT, (U32)param ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getF32TreatmentParamLowerRangeLimit function returns the lower range + * limit for a given float treatment parameter. + * @details \b Inputs: none + * @details \b Outputs: none + * @param param ID of parameter to get lower range limit for + * @return lower range limit for given float treatment parameter + *************************************************************************/ +F32 getF32TreatmentParamLowerRangeLimit( TREATMENT_PARAM_T param ) +{ + F32 result = 0; + + if ( param < NUM_OF_TREATMENT_PARAMS ) + { + CRITICAL_DATAS_T value; +// getInstitutionalRecordEdgeValue( param, &value, TRUE ); // TODO + value = treatmentParameters[ param ].minimum; + result = value.sFlt; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_PARAMS_INVALID_GET_F32_PARAM_MIN_LIMIT, (U32)param ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getF32TreatmentParamUpperRangeLimit function returns the upper range + * limit for a given float treatment parameter. + * @details \b Inputs: none + * @details \b Outputs: none + * @param param ID of parameter to get lower range limit for + * @return upper range limit for given float treatment parameter + *************************************************************************/ +F32 getF32TreatmentParamUpperRangeLimit( TREATMENT_PARAM_T param ) +{ + F32 result = 0; + + if ( param < NUM_OF_TREATMENT_PARAMS ) + { + CRITICAL_DATAS_T value; +// getInstitutionalRecordEdgeValue( param, &value, FALSE ); // TODO + value = treatmentParameters[ param ].maximum; + result = value.sFlt; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_PARAMS_INVALID_GET_F32_PARAM_MAX_LIMIT, (U32)param ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getS32DefaultTreatmentParamEdge function returns the min or max of + * the default treatment parameters + * @details \b Inputs: TREAT_PARAMS_PROPERTIES + * @details \b Outputs: none + * @param param ID of parameter + * @param isMin to indicate whether minimum is needed for maximum + * @return the requested min or max value + *************************************************************************/ +S32 getS32DefaultTreatmentParamEdge( TREATMENT_PARAM_T param, BOOL isMin ) +{ + S32 value = ( TRUE == isMin ? TREAT_PARAMS_PROPERTIES[ param ].min.sInt : TREAT_PARAMS_PROPERTIES[ param ].max.sInt ); + + return value; +} + +/*********************************************************************//** + * @brief + * The getU32DefaultTreatmentParamEdge function returns the min or max of + * the default treatment parameters + * @details \b Inputs: TREAT_PARAMS_PROPERTIES + * @details \b Outputs: none + * @param param ID of parameter + * @param isMin to indicate whether minimum is needed for maximum + * @return the requested min or max value + *************************************************************************/ +U32 getU32DefaultTreatmentParamEdge( TREATMENT_PARAM_T param, BOOL isMin ) +{ + U32 value = ( TRUE == isMin ? TREAT_PARAMS_PROPERTIES[ param ].min.uInt : TREAT_PARAMS_PROPERTIES[ param ].max.uInt ); + + return value; +} + +/*********************************************************************//** + * @brief + * The getF32DefaultTreatmentParamEdge function returns the min or max of + * the default treatment parameters + * @details \b Inputs: TREAT_PARAMS_PROPERTIES + * @details \b Outputs: none + * @param param ID of parameter + * @param isMin to indicate whether minimum is needed for maximum + * @return the requested min or max value + *************************************************************************/ +F32 getF32DefaultTreatmentParamEdge( TREATMENT_PARAM_T param, BOOL isMin ) +{ + F32 value = ( TRUE == isMin ? TREAT_PARAMS_PROPERTIES[ param ].min.sFlt : TREAT_PARAMS_PROPERTIES[ param ].max.sFlt ); + + return value; +} + +/**@}*/ Index: firmware/App/Modes/ModeTxParams.h =================================================================== diff -u --- firmware/App/Modes/ModeTxParams.h (revision 0) +++ firmware/App/Modes/ModeTxParams.h (revision cd19fd5095128315982b9ef810bd45e68eff8deb) @@ -0,0 +1,105 @@ +/************************************************************************** +* +* Copyright (c) 2025-2025 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 ModeTxParams.h +* +* @author (last) Sean +* @date (last) 18-Mar-2025 +* +* @author (original) Sean +* @date (original) 18-Mar-2025 +* +***************************************************************************/ + +#ifndef __MODE_TX_PARAMS_H__ +#define __MODE_TX_PARAMS_H__ + +#include "TDCommon.h" +#include "TDDefs.h" +#include "Utilities.h" + +/** + * @defgroup ModeTxParams ModeTxParams + * @brief Treatment parameters mode unit. + * + * @addtogroup ModeTxParams + * @{ + */ + +// ********** public definitions ********** + +#define MIN_PRESSURE_ALARM_LIMIT_DELTA_MMHG ( 30 ) ///< Minimum pressure alarm limit delta (in mmHg) +#define MAX_UF_RATE_ML_MIN ( 2000.01F / (F32)MIN_PER_HOUR ) ///< Maximum ultrafiltration rate (in mL/min). Added small decimal to prevent float round off issues. +#define MIN_UF_RATE_ML_MIN ( 0.0F ) ///< Minimum ultrafiltration rate (in mL/min). +#define MAX_UF_VOLUME_ML ( 8 * ML_PER_LITER ) ///< Maximum ultrafiltration volume (in mL). + +/// Record structure for a treatment parameters payload from UI. +typedef struct +{ + U32 bloodFlowRate_mL_min; ///< User set blood flow rate (in mL/min) + U32 dialysateFlowRate_mL_min; ///< User set dialysate flow rate (in mL/min) + U32 treatmentDuration_min; ///< User set treatment duration (in min) + U32 salineBolusVolume_mL; ///< User set saline bolus volume (in mL) + U32 acidConcentrate; ///< User set acid concentrate option + U32 bicarbConcentrate; ///< User set bicarbonate concentrate option + U32 dialyzerType; ///< User set dialyzer type option + U32 bpInterval_min; ///< User set blood pressure measurement interval (in min) + U32 rinsebackFlowRate_mL_min; ///< User set rinseback flow rate (in mL/min) + S32 arterialPressureLimitWindow_mmHg; ///< User set alarm limit window for arterial pressure (in mmHg) + S32 venousPressureLimitWindow_mmHg; ///< User set alarm limit window for venous pressure (in mmHg) + S32 venousPressureLimitAsymmetric_mmHg; ///< User set alarm limit asymmetric for venous pressure (in mmHg) + S32 tmpLimitWindow_mmHg; ///< User set alarm limit window for trans-membrane pressure (in mmHg) + F32 dialysateTemperature_degC; ///< User set dialysate temperature (in deg C) +} TREATMENT_PARAMS_DATA_PAYLOAD_T; + +/// Record structure for reporting all current treatment parameters to Dialin +typedef struct +{ + TREATMENT_PARAMS_DATA_PAYLOAD_T treatment_parameters; ///< Record structure of treatment parameters + F32 uFVolume_L; ///< Current ultrafiltration volume (in L). +} CURRENT_TREATMENT_PARAMS_DATA_PAYLOAD_T; + +/// Payload record structure for treatment parameter range broadcast messages. +typedef struct +{ + U32 minTreatmentTime; ///< Minimum treatment duration (in minutes) + U32 maxTreatmentTime; ///< Maximum treatment duration (in minutes) + F32 minUFVolume; ///< Minimum ultrafiltration volume (in mL) + F32 maxUFVolume; ///< Maximum ultrafiltration volume (in mL) + U32 minDialRate; ///< Minimum dialysate flow rate (in mL/min) + U32 maxDialRate; ///< Maximum dialysate flow rate (in mL/min) +} TREATMENT_PARAM_RANGE_BROADCAST_PAYLOAD_T; + +// ********** public function prototypes ********** + +void initTreatParamsMode( void ); // Initialize this module +U32 transitionToTreatParamsMode( void ); // Prepares for transition to treatment parameters mode +U32 execTreatParamsMode( void ); // Execute the treatment parameters mode state machine (call from OperationModes) + +BOOL setTreatmentParameterU32( TREATMENT_PARAM_T param, U32 value ); // Set a specified unsigned integer treatment parameter value +BOOL setTreatmentParameterS32( TREATMENT_PARAM_T param, S32 value ); // Set a specified signed integer treatment parameter value +BOOL setTreatmentParameterF32( TREATMENT_PARAM_T param, F32 value ); // Set a specified floating point treatment parameter value +U32 getTreatmentParameterU32( TREATMENT_PARAM_T param ); // Get a specified unsigned integer treatment parameter +S32 getTreatmentParameterS32( TREATMENT_PARAM_T param ); // Get a specified signed integer treatment parameter +F32 getTreatmentParameterF32( TREATMENT_PARAM_T param ); // Get a specified floating point treatment parameter +S32 getTreatmentParameterS32DefaultValue( TREATMENT_PARAM_T param ); // Get the default value for a specified signed integer treatment parameter + +BOOL validateAndSetTreatmentParameters( MESSAGE_T *message ); // User provided treatment params to be set and validated +BOOL validateAndSetUFVolume( MESSAGE_T *message ); // User provided ultrafiltration volume to be set and validated + +BOOL signalUserConfirmationOfTreatmentParameters( MESSAGE_T *message ); // Signal user confirmation/rejection of treatment parameters +BOOL signalUserCancelTreatment( void ); // Signal user has cancelled the treatment +void signalAlarmActionToTreatParamsMode( ALARM_ACTION_T action ); // Execute alarm action as appropriate for treatment parameters mode + +BOOL isTreatmentParamInRange( TREATMENT_PARAM_T param, CRITICAL_DATAS_T value ); // Check range for a proposed treatment parameter value + +BOOL testSetTreatmentParameter( MESSAGE_T *message ); // Set a specific treatment parameter value +BOOL testSendCurrentTreatmentParameters( MESSAGE_T *message ); // Update current treatment parameters + +/**@}*/ + +#endif Index: firmware/App/Modes/StateTxDialysis.c =================================================================== diff -u --- firmware/App/Modes/StateTxDialysis.c (revision 0) +++ firmware/App/Modes/StateTxDialysis.c (revision cd19fd5095128315982b9ef810bd45e68eff8deb) @@ -0,0 +1,439 @@ +/************************************************************************** +* +* Copyright (c) 2025-2025 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 StateTxDialysis.c +* +* @author (last) Sean +* @date (last) 15-Apr-2025 +* +* @author (original) Sean +* @date (original) 15-Apr-2025 +* +***************************************************************************/ + +#include "TDCommon.h" +#include "AirTrap.h" +#include "BloodFlow.h" +#include "Buttons.h" +#include "DDInterface.h" +#include "Messaging.h" +#include "ModeTreatment.h" +#include "ModeTxParams.h" +//#include "NVDataMgmt.h" +#include "OperationModes.h" +#include "StateTxDialysis.h" +//#include "Switches.h" +#include "TaskGeneral.h" +#include "Valves.h" + +/** + * @addtogroup StateTxDialysis + * @{ + */ + +// ********** private definitions ********** + +// ********** private data ********** + +static DIALYSIS_STATE_T currentDialysisState; ///< Current state of the dialysis sub-mode state machine. + +static U32 setBloodFlowRate; ///< Currently set blood flow rate (from prescription). +static U32 setDialysateFlowRate; ///< Currently set dialysate flow rate (from prescription). +static F32 setUFVolumeL; ///< Currently set total ultrafiltration volume (in L) for treatment (from prescription). +static F32 setUFRateLHr; ///< Currently set ultrafiltration rate (in L/hr from prescription). +static OVERRIDE_F32_T measUFVolumeL; ///< Current total measured volume (in L) for ultrafiltration . + +static BOOL ufPauseRequested; ///< Flag indicates UF pause has been requested by user. +static BOOL ufResumeRequested; ///< Flag indicates UF resume has been requested by user. +static BOOL autoResumeUF; ///< Flag indicates UF should be auto-resumed after saline bolus completes. + +// ********** private function prototypes ********** + +static void transitionToDialysisState( DIALYSIS_STATE_T newState ); + +static DIALYSIS_STATE_T handleDialysisUltrafiltrationState( void ); +static DIALYSIS_STATE_T handleDialysisUltrafiltrationPausedState( void ); + +static void updateUFVolume( void ); + +/*********************************************************************//** + * @brief + * The initDialysis function initializes the Dialysis sub-mode module. + * Calling this function will reset dialysis and therefore should only + * be called when a new treatment is due to begin. + * @details \b Inputs: none + * @details \b Outputs: Dialysis sub-mode module initialized. + * @return none + *************************************************************************/ +void initDialysis( void ) +{ + currentDialysisState = DIALYSIS_UF_STATE; + + measUFVolumeL.data = 0.0F; + measUFVolumeL.ovData = 0.0F; + measUFVolumeL.ovInitData = 0.0F; + measUFVolumeL.override = OVERRIDE_RESET; + + setBloodFlowRate = 0; + setDialysateFlowRate = 0; + setUFVolumeL = 0.0F; + setUFRateLHr = 0.0F; + + ufPauseRequested = FALSE; + ufResumeRequested = FALSE; + autoResumeUF = FALSE; +} + +/*********************************************************************//** + * @brief + * The transitionToDialysis function prepares for transition to dialysis sub-mode. + * This function will reset anything required for resuming dialysis in a + * treatment that has already begun. It does not reset everything as dialysis + * may be stopped and resumed multiple times due to alarms or user intervention + * and we don't want to start the treatment all over again. + * @details \b Inputs: none + * @details \b Outputs: none + * @return none + *************************************************************************/ +void transitionToDialysis( void ) +{ + PUMP_CONTROL_MODE_T mode = PUMP_CONTROL_MODE_CLOSED_LOOP; + +// doorClosedRequired( TRUE, TRUE ); + + // Set user alarm recovery actions allowed in this sub-mode + setAlarmUserActionEnabled( ALARM_USER_ACTION_RESUME, TRUE ); + setAlarmUserActionEnabled( ALARM_USER_ACTION_RINSEBACK, TRUE ); + setAlarmUserActionEnabled( ALARM_USER_ACTION_END_TREATMENT, TRUE ); + + // Set actuators as appropriate for state + cmdStartGenerateDialysate( setDialysateFlowRate, setUFRateLHr, getTreatmentParameterF32( TREATMENT_PARAM_DIALYSATE_TEMPERATURE ), FALSE, + (ACID_CONCENTRATE_TYPE_T)getTreatmentParameterU32( TREATMENT_PARAM_ACID_CONCENTRATE ), + (BICARB_CONCENTRATE_TYPE_T)getTreatmentParameterU32( TREATMENT_PARAM_BICARB_CONCENTRATE ) ); + transitionToDialysisState( currentDialysisState ); + + // Set substate for event + setCurrentSubState( (U32)currentDialysisState ); +} + +/*********************************************************************//** + * @brief + * The transitionToDialysisState function sets all actuators as appropriate + * go the given new dialysis state. + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if invalid state is given + * @details \b Inputs: none + * @details \b Outputs: none + * @param newState The new state that we are transitioning to. + * @return none + *************************************************************************/ +static void transitionToDialysisState( DIALYSIS_STATE_T newState ) +{ + switch ( newState ) + { + case DIALYSIS_UF_STATE: + setValvePosition( H1_VALV, VALVE_POSITION_B_OPEN ); // set arterial valve to pump blood from patient + setValvePosition( H19_VALV, VALVE_POSITION_B_OPEN ); // set venous valve to open, allowing blood to return to patient + setBloodPumpTargetFlowRate( setBloodFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); + cmdChangeQuf( setUFRateLHr ); + + // Start auto-control of air trap valve + startAirTrapControl(); + break; + + case DIALYSIS_UF_PAUSED_STATE: + // Set valves for dialysis + setValvePosition( H1_VALV, VALVE_POSITION_B_OPEN ); // set arterial valve to pump blood from patient + setValvePosition( H19_VALV, VALVE_POSITION_B_OPEN ); // set venous valve to open, allowing blood to return to patient + + // Restart pumps + setBloodPumpTargetFlowRate( setBloodFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); + cmdChangeQuf( 0.0F ); + + // Start auto-control of air trap valve + startAirTrapControl(); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TX_DIALYSIS_INVALID_STATE1, (U32)newState ) + break; + } +} + +/*********************************************************************//** + * @brief + * The getDialysisState function gets the current dialysis state. + * @details \b Inputs: currentDialysisState + * @details \b Outputs: none + * @return currentDialysisState + *************************************************************************/ +DIALYSIS_STATE_T getDialysisState( void ) +{ + return currentDialysisState; +} + +/*********************************************************************//** + * @brief + * The getUltrafiltrationVolumeDrawn function gets the current total + * ultrafiltration volume (in L) drawn from the patient so far. + * @details \b Inputs: measUFVolumeL + * @details \b Outputs: none + * @return Total ultrafiltration volume (in L) drawn from the patient so far. + *************************************************************************/ +F32 getUltrafiltrationVolumeDrawn( void ) +{ + F32 result = getF32OverrideValue( &measUFVolumeL ); + + return result; +} + +/*********************************************************************//** + * @brief + * The setDialysisBloodPumpFlowRate function sets the blood pump flow rate parameter. + * This function should be called prior to beginning dialysis treatment + * and when the user changes the blood flow rate during treatment. + * @details \b Inputs: none + * @details \b Outputs: setBloodFlowRate + * @param bPFlow target blood pump flow rate (in mL/min) + * @return none + *************************************************************************/ +void setDialysisBloodPumpFlowRate( U32 bPFlow ) +{ + setBloodFlowRate = bPFlow; + + // Make rate changes in real time if currently performing dialysis. + if ( TREATMENT_DIALYSIS_STATE == getTreatmentState() ) + { + setBloodPumpTargetFlowRate( setBloodFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); + } +} + +/*********************************************************************//** + * @brief + * The setDialysisDDParams function sets the dialysate rate and ultrafiltration + * volume and rate parameters. + * @details \b Inputs: none + * @details \b Outputs: setDialysateFlowRate, setDialysateFlowRate, setUFRateLHr + * @param qd target dialysate flow rate (in mL/min) + * @param ufVol target ultrafiltration volume (in L) + * @param quf target ultrafiltration flow rate (in L/hr) + * @return none + *************************************************************************/ +void setDialysisDDParams( U32 qd, F32 ufVol, F32 quf ) +{ + setDialysateFlowRate = qd; + setDialysateFlowRate = ufVol; + setUFRateLHr = quf; +} + +/*********************************************************************//** + * @brief + * The signalPauseResumeUF function handles a request to pause or resume + * ultrafiltration. + * @details \b Inputs: currentDialysisState, setUFRateLHr + * @details \b Outputs: ufPauseRequested, ufResumeRequested + * @param message Message from UI which includes a flag indicating whether + * to pause or resume ultrafiltration. + * @return TRUE if pause + *************************************************************************/ +BOOL signalPauseResumeUF( MESSAGE_T *message ) +{ + TREATMENT_STATE_T trtState = getTreatmentState(); + TD_OP_MODE_T currMode = getCurrentOperationMode(); + UI_RESPONSE_PAYLOAD_T response; + + response.accepted = FALSE; + response.rejectionReason = REQUEST_REJECT_REASON_NONE; + + // Verify payload length is valid + if ( sizeof( BOOL ) == message->hdr.payloadLen ) + { + BOOL payload; + + memcpy( &payload, message->payload, sizeof( BOOL ) ); + + // Handle request to resume ultrafiltration + if ( TRUE == payload ) + { + ufResumeRequested = TRUE; + if ( ( MODE_TREA == currMode ) && ( TREATMENT_DIALYSIS_STATE == trtState ) && ( DIALYSIS_UF_PAUSED_STATE == currentDialysisState ) ) + { + response.accepted = TRUE; + if ( setUFRateLHr > 0.0 ) + { + //sendTreatmentLogEventData( UF_START_RESUME_EVENT, 0.0, setUFRateLHr ); + } + } + else + { + if ( MODE_TREA != currMode ) + { + response.rejectionReason = REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE; + } + else if ( ( TREATMENT_DIALYSIS_STATE != trtState ) || ( DIALYSIS_UF_PAUSED_STATE != currentDialysisState ) ) + { + response.rejectionReason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; + } + else + { + response.rejectionReason = REQUEST_REJECT_REASON_UF_NOT_PAUSED; + } + } + } + // Handle request to pause ultrafiltration + else + { + ufPauseRequested = TRUE; + if ( ( MODE_TREA == currMode ) && ( TREATMENT_DIALYSIS_STATE == trtState ) && ( DIALYSIS_UF_STATE == currentDialysisState ) ) + { + response.accepted = TRUE; + if ( setUFRateLHr > 0.0 ) + { + //sendTreatmentLogEventData( UF_PAUSE_EVENT, setUFRateLHr, 0.0 ); + } + } + else + { + if ( MODE_TREA != currMode ) + { + response.rejectionReason = REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE; + } + else if ( ( TREATMENT_DIALYSIS_STATE != trtState ) || ( DIALYSIS_UF_STATE != currentDialysisState ) ) + { + response.rejectionReason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; + } + else + { + response.rejectionReason = REQUEST_REJECT_REASON_UF_NOT_IN_PROGESS; + } + } + } + } + else + { + response.rejectionReason = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + } + + // Send response w/ reason code if rejected + sendMessage( MSG_ID_TD_UF_PAUSE_RESUME_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08*)(&response), sizeof( UI_RESPONSE_PAYLOAD_T ) ); + + return response.accepted; +} + +/*********************************************************************//** + * @brief + * The pauseDialysis function pauses dialysis. This function will be called + * by Treatment Mode when an alarm occurs or the user pressed the stop button. + * Dialysis may be resumed later. + * @details Inputs: none + * @details Outputs: Pumps stopped. DD commanded to bypass. + * @return none + *************************************************************************/ +void pauseDialysis( void ) +{ + // Stop pumps + signalBloodPumpHardStop(); + // Tell DD to bypass dialyzer while alarm has dialysis paused + cmdBypassDialyzer( TRUE ); +} + +/*********************************************************************//** + * @brief + * The execDialysis function executes the Dialysis sub-mode state machine. + * @details Inputs: currentDialysisState + * @details Outputs: currentDialysisState + * @return none + *************************************************************************/ +void execDialysis( void ) +{ + DIALYSIS_STATE_T priorSubState = currentDialysisState; + + // Dialysis state machine + switch ( currentDialysisState ) + { + case DIALYSIS_UF_STATE: + currentDialysisState = handleDialysisUltrafiltrationState(); + break; + + case DIALYSIS_UF_PAUSED_STATE: + currentDialysisState = handleDialysisUltrafiltrationPausedState(); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TX_DIALYSIS_INVALID_STATE1, (U32)currentDialysisState ) + break; + } + + // Update total UF volume drawn + updateUFVolume(); + + if ( priorSubState != currentDialysisState ) + { + setCurrentSubState( (U32)currentDialysisState ); + SEND_EVENT_WITH_2_U32_DATA( TD_EVENT_SUB_STATE_CHANGE, priorSubState, currentDialysisState ); + } +} + +/*********************************************************************//** + * @brief + * The handleDialysisUltrafiltrationState function handles the ultrafiltration + * state of the Dialysis state machine. + * @details \b Inputs: none + * @details \b Outputs: none + * @return next Dialysis state. + *************************************************************************/ +static DIALYSIS_STATE_T handleDialysisUltrafiltrationState( void ) +{ + DIALYSIS_STATE_T result = DIALYSIS_UF_STATE; + + if ( TRUE == ufPauseRequested ) + { + ufPauseRequested = FALSE; + transitionToDialysisState( DIALYSIS_UF_PAUSED_STATE ); + result = DIALYSIS_UF_PAUSED_STATE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleDialysisUltrafiltrationPausedState function handles the + * ultrafiltration paused state of the Dialysis state machine. + * @details \b Inputs: none + * @details \b Outputs: none + * @return next Dialysis state. + *************************************************************************/ +static DIALYSIS_STATE_T handleDialysisUltrafiltrationPausedState( void ) +{ + DIALYSIS_STATE_T result = DIALYSIS_UF_PAUSED_STATE; + + if ( TRUE == ufResumeRequested ) + { + ufResumeRequested = FALSE; + transitionToDialysisState( DIALYSIS_UF_STATE ); + result = DIALYSIS_UF_STATE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The updateUFVolume function updates the total measured ultrafiltration + * volume based on set rate and whether or not DD is currently running + * the ultrafiltration pump. + * @details \b Inputs: none + * @details \b Outputs: measUFVolumeL + * @return none + *************************************************************************/ +static void updateUFVolume( void ) +{ + // Update total UF volume drawn + measUFVolumeL.data = 0.0F; // TODO +} + +/**@}*/ Index: firmware/App/Modes/StateTxDialysis.h =================================================================== diff -u --- firmware/App/Modes/StateTxDialysis.h (revision 0) +++ firmware/App/Modes/StateTxDialysis.h (revision cd19fd5095128315982b9ef810bd45e68eff8deb) @@ -0,0 +1,54 @@ +/************************************************************************** +* +* Copyright (c) 2025-2025 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 StateTxDialysis.h +* +* @author (last) Sean +* @date (last) 15-Apr-2025 +* +* @author (original) Sean +* @date (original) 15-Apr-2025 +* +***************************************************************************/ + +#ifndef __STATE_TX_DIALYSIS_H__ +#define __STATE_TX_DIALYSIS_H__ + +#include "TDCommon.h" +#include "TDDefs.h" + +/** + * @defgroup StateTxDialysis StateTxDialysis + * @brief Treatment mode dialysis state unit. The dialysis sub-mode is where + * dialysis and (optionally) ultrafiltration are being provided by the system. + * Heparin is added to the blood when appropriate. + * + * @addtogroup StateTxDialysis + * @{ + */ + +// ********** public definitions ********** + +// ********** public function prototypes ********** + +void initDialysis( void ); // Initialize this unit +void transitionToDialysis( void ); // Prepares for transition to treatment dialysis state +void execDialysis( void ); // Execute the treatment dialysis state machine + +void pauseDialysis( void ); // Pauses dialysis due to alarm + +DIALYSIS_STATE_T getDialysisState( void ); // Gets current dialysis state +F32 getUltrafiltrationVolumeDrawn( void ); // Gets current total ultrafiltration volume drawn from patient. + +void setDialysisBloodPumpFlowRate( U32 bPFlow ); // Signal new BP flow rate +void setDialysisDDParams( U32 qd, F32 ufVol, F32 quf ); // Signal new DD params + +BOOL signalPauseResumeUF( MESSAGE_T *message ); // Handles a user request to pause or resume ultrafiltration + +/**@}*/ + +#endif Index: firmware/App/Modes/StateTxPaused.c =================================================================== diff -u --- firmware/App/Modes/StateTxPaused.c (revision 0) +++ firmware/App/Modes/StateTxPaused.c (revision cd19fd5095128315982b9ef810bd45e68eff8deb) @@ -0,0 +1,189 @@ +/************************************************************************** +* +* Copyright (c) 2025-2025 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 StateTxPaused.c +* +* @author (last) Sean +* @date (last) 18-Apr-2025 +* +* @author (original) Sean +* @date (original) 18-Apr-2025 +* +***************************************************************************/ + +#include "AirTrap.h" +#include "BloodFlow.h" +#include "Buttons.h" +#include "DDInterface.h" +#include "Messaging.h" +//#include "NVDataMgmt.h" +#include "OperationModes.h" +#include "StateTxPaused.h" +//#include "Switches.h" +#include "TaskGeneral.h" +#include "Valves.h" + +/** + * @addtogroup StateTxPaused + * @{ + */ + +// ********** private definitions ********** + +/// Treatment paused status broadcast interval. +#define TREATMENT_PAUSED_DATA_PUBLISH_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) + +// ********** private data ********** + +static TREATMENT_PAUSED_STATE_T currentTxPausedState; ///< Current treatment paused state. +static U32 bloodSittingTimerCtr; ///< Timer counter tracks time in this mode while blood is sitting. +static U32 pausedPublishTimerCtr; ///< Timer counter (in GP task intervals) counts time to next treatment paused status broadcast. + +static OVERRIDE_U32_T treatmentPausedPublishInterval; ///< Interval (in task intervals) at which to publish treatment paused state data to CAN bus. + +// ********** private function prototypes ********** + +/*********************************************************************//** + * @brief + * The initTreatmentPaused function initializes the Treatment Paused State unit. + * @details \b Inputs: none + * @details \b Outputs: Treatment Paused State unit initialized. + * @return none + *************************************************************************/ +void initTreatmentPaused( void ) +{ + currentTxPausedState = TREATMENT_PAUSED_RECIRC_STATE; // Assume blood and dialysate will recirculate initially - will stop pump(s) as appropriate in state machine + bloodSittingTimerCtr = 0; + pausedPublishTimerCtr = TREATMENT_PAUSED_DATA_PUBLISH_INTERVAL; + + treatmentPausedPublishInterval.data = TREATMENT_PAUSED_DATA_PUBLISH_INTERVAL; + treatmentPausedPublishInterval.ovData = TREATMENT_PAUSED_DATA_PUBLISH_INTERVAL; + treatmentPausedPublishInterval.ovInitData = TREATMENT_PAUSED_DATA_PUBLISH_INTERVAL; + treatmentPausedPublishInterval.override = OVERRIDE_RESET; +} + +/*********************************************************************//** + * @brief + * The transitionToTreatmentPaused function prepares for transition to + * Treatment Paused state. + * @details \b Inputs: currentTxPausedState + * @details \b Outputs: none + * @return none + *************************************************************************/ +void transitionToTreatmentPaused( void ) +{ + initTreatmentPaused(); + + setCurrentSubState( (U32)currentTxPausedState ); + setCurrent4thLevelState( NO_SUB_STATE ); + // Set user alarm recovery actions allowed in this sub-mode + setAlarmUserActionEnabled( ALARM_USER_ACTION_RESUME, TRUE ); + if ( FALSE ) // TODO ( TRUE == getRinsebackCompleted() ) + { // block rinseback action if already done + setAlarmUserActionEnabled( ALARM_USER_ACTION_RINSEBACK, FALSE ); + } + else + { + setAlarmUserActionEnabled( ALARM_USER_ACTION_RINSEBACK, TRUE ); + } + setAlarmUserActionEnabled( ALARM_USER_ACTION_END_TREATMENT, TRUE ); + +// setupForBloodRecirculationState(); +// setupForDialysateRecirculationState(); + // temporary actuator setup until setup functions implemented TODO + signalBloodPumpHardStop(); + setValvePosition( H1_VALV, VALVE_POSITION_C_CLOSE ); + setValvePosition( H19_VALV, VALVE_POSITION_C_CLOSE ); + cmdBypassDialyzer( TRUE ); + cmdChangeQuf( 0.0F ); + startAirTrapControl(); + +// signalInitiatePressureStabilization( USE_NORMAL_STABILIZATION_PERIOD ); + + // Reset saline bolus state in case alarm interrupted one +// resetSalineBolus(); + + // Reset blood leak zeroing params +// resetBloodLeakZeroingVariables(); + + // Should always have an alarm active in treatment stop sub-mode so that user can take action + if ( FALSE == isAnyAlarmActive() ) + { +// if ( TRUE == getRinsebackCompleted() ) +// { +// activateAlarmNoData( ALARM_ID_TD_TREATMENT_STOPPED_AFTER_RINSEBACK ); // No escalation after rinseback because no blood in blood line +// } +// else + { + activateAlarmNoData( ALARM_ID_TD_TREATMENT_STOPPED_BY_USER ); + } + // coming back to stop state via non-alarm path, so no audio - just want alarm for its options + signalAlarmSilence( ALARM_SILENCE_CMD_CANCEL ); + } +} + +/*********************************************************************//** + * @brief + * The execTreatmentPaused function executes the Treatment Paused state machine. + * @details \b Inputs: currentTxPausedState + * @details \b Outputs: currentTxPausedState + * @return none + *************************************************************************/ +void execTreatmentPaused( void ) +{ + TREATMENT_PAUSED_STATE_T priorSubState = currentTxPausedState; + +// switch ( currentTxPausedState ) +// { +// case TREATMENT_PAUSED_RECIRC_STATE: +// currentTxPausedState = handleTreatmentStopRecircState(); +// break; +// +// case TREATMENT_PAUSED_RECIRC_DIALYSATE_ONLY_STATE: +// currentTxPausedState = handleTreatmentStopDialysateRecircState(); +// break; +// +// case TREATMENT_PAUSED_RECIRC_BLOOD_ONLY_STATE: +// currentTxPausedState = handleTreatmentStopBloodRecircState(); +// break; +// +// case TREATMENT_PAUSED_NO_RECIRC_STATE: +// currentTxPausedState = handleTreatmentStopNoRecircState(); +// break; +// +// case TREATMENT_PAUSED_RECOVER_BLOOD_DETECT_STATE: +// currentTxPausedState = handleTreatmentStopRecoverBloodDetectState(); +// break; +// +// default: +// SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_TREATMENT_STOP_INVALID_STATE, currentTxStopState ); +// break; +// } + + if ( priorSubState != currentTxPausedState ) + { + setCurrentSubState( (U32)currentTxPausedState ); + SEND_EVENT_WITH_2_U32_DATA( TD_EVENT_SUB_STATE_CHANGE, priorSubState, currentTxPausedState ); + } + // Broadcast treatment stop status +// publishTreatmentStopData(); +} + +/*********************************************************************//** + * @brief + * The getCurrentTreatmentPausedState function returns the current state of the + * treatment paused sub-mode. + * @details \b Inputs: currentTxPausedState + * @details \b Outputs: none + * @return currentTxPausedState + *************************************************************************/ +TREATMENT_PAUSED_STATE_T getCurrentTreatmentPausedState( void ) +{ + return currentTxPausedState; +} + +/**@}*/ Index: firmware/App/Modes/StateTxPaused.h =================================================================== diff -u --- firmware/App/Modes/StateTxPaused.h (revision 0) +++ firmware/App/Modes/StateTxPaused.h (revision cd19fd5095128315982b9ef810bd45e68eff8deb) @@ -0,0 +1,42 @@ +/************************************************************************** +* +* Copyright (c) 2024-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 StateTxPaused.h +* +* @author (last) Sean +* @date (last) 18-Apr-2025 +* +* @author (original) Sean +* @date (original) 18-Apr-2025 +* +***************************************************************************/ + +#ifndef __STATE_TX_PAUSED_H__ +#define __STATE_TX_PAUSED_H__ + +#include "TDCommon.h" +#include "TDDefs.h" + +/** + * @defgroup StateTxPaused StateTxPaused + * @brief Treatment Paused state unit. + * + * @addtogroup StateTxPaused + * @{ + */ + +// ********** public function prototypes ********** + +void initTreatmentPaused( void ); // Initialize this unit +void transitionToTreatmentPaused( void ); // Prepares for transition to treatment paused state +void execTreatmentPaused( void ); // Execute the treatment paused state machine + +TREATMENT_PAUSED_STATE_T getCurrentTreatmentPausedState( void );// Get current treatment paused state + +/**@}*/ + +#endif