Index: firmware/App/Modes/ModePreTreat.c =================================================================== diff -u -r6c933adfd50a0bc041dc29f4bfa15de5e9f4843a -r81e5d76c3906a8c18be914f5736a796436fd85b5 --- firmware/App/Modes/ModePreTreat.c (.../ModePreTreat.c) (revision 6c933adfd50a0bc041dc29f4bfa15de5e9f4843a) +++ firmware/App/Modes/ModePreTreat.c (.../ModePreTreat.c) (revision 81e5d76c3906a8c18be914f5736a796436fd85b5) @@ -7,8 +7,8 @@ * * @file ModePreTreat.c * -* @author (last) Vijay Pamula -* @date (last) 31-Jul-2026 +* @author (last) Varshini Nagabooshanam +* @date (last) 19-Aug-2026 * * @author (original) Dara Navaei * @date (original) 25-Sep-2025 @@ -19,11 +19,13 @@ #include "AirTrap.h" #include "BloodFlow.h" #include "Buttons.h" +#include "DrySelfTests.h" #include "DDInterface.h" #include "Messaging.h" #include "ModePreTreat.h" #include "OperationModes.h" #include "Prime.h" +#include "StatePreTxHeparinSetup.h" #include "StatePreTxRecirculate.h" #include "SyringePump.h" #include "TaskGeneral.h" @@ -40,33 +42,50 @@ // ********** private definitions ********** +/// Number of task cycles to delay UI transition after sub-mode completion. +#define SUBMODE_COMPLETE_UI_TRANSITION_TIME_COUNT ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) + /// Interval (ms/task time) at which the Pre-Treatment state data is published on the CAN bus. #define PRE_TREATMENT_STATE_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) /// Initial offset used to stagger the Pre-Treatment state data broadcast. #define PRE_TREATMENT_STATE_DATA_PUB_INITIAL_OFFSET 5U +#define PRE_TX_DEFAULT_QD_ML_MIN 400 ///< Default dialysate flow rate during recirculation when Rx is not entered in mL/min. +#define PRE_TX_INTERMEDIATE_QD_ML_MIN 300 ///< Intermediate dialysate flow rate for low prescribed Qd in mL/min. +#define PRE_TX_LOW_QD_THRESHOLD_ML_MIN 200 ///< Maximum prescribed Qd requiring the intermediate Qd transition in mL/min. +#define PRE_TX_LOW_QD_TRANSITION_TIME_MS ( 4 * SEC_PER_MIN * MS_PER_SECOND ) ///< Low Qd transition time before applying the prescribed Qd in milliseconds. + // ********** private data ********** static TD_PRE_TREATMENT_MODE_STATE_T currentPreTreatmentState; ///< Current Pre-Treatment sub-state static BOOL goToInstallStateRequested; ///< Flag indicating a request to transition to Install state. -static BOOL continueFromRecirculateRequested; ///< Flag indicating a request to transition to Confirm Rx. +static BOOL alarmActionResumeReceived; ///< Flag indicates alarm action resume received. +static U32 submodeCompleteTransitionTimeCounter; ///< Sub-mode completed transition wait time counter. +static BOOL continueFromRecirculateRequested; ///< Flag indicating a request to transition to Patient Connection state. +static BOOL continueFromHeparinSetupRequested; ///< Flag indicating a request to transition to Patient Connection state. static BOOL treatmentStartRequested; ///< Flag indicating the UI requested treatment start. static U32 preTreatmentStateBroadcastTimerCtr; ///< Pre-Treatment state data broadcast timer counter. static OVERRIDE_U32_T preTreatmentStatePublishInterval; ///< Pre-Treatment state data publication interval override. +static BOOL lowQdTransitionActive; ///< Flag indicating low Qd transition is active. +static U32 lowQdTransitionStartTime; ///< Start time of the low Qd transition. +static BOOL defaultQdApplied; ///< Flag indicating default Qd has been applied while Rx is unavailable. +static BOOL preTreatmentRxUpdated; ///< Flag indicating a new or updated Rx was received. static BOOL resumePreTxAlarmResponseRequest; ///< Flag indicates user has requested PreTx resume. // ********** private function prototypes ********** -static void setPreTreatStateTransition( void ); ///< Configure actuators and variables for Pre-Treatment state transitions. -static TD_PRE_TREATMENT_MODE_STATE_T handleInstallState( void ); ///< Handle Install state during Pre-Treatment -static TD_PRE_TREATMENT_MODE_STATE_T handleSelfTestDryState( void ); ///< Handle Self Test Dry state during Pre-Treatment -static TD_PRE_TREATMENT_MODE_STATE_T handlePrimeState( void ); ///< Handle Prime state during Pre-Treatment -static TD_PRE_TREATMENT_MODE_STATE_T handleRecirculateState( void ); ///< Handle Recirculate state during Pre-Treatment -static TD_PRE_TREATMENT_MODE_STATE_T handleRxState( void ); ///< Handle Confirm Rx state during Pre-Treatment -static TD_PRE_TREATMENT_MODE_STATE_T handlePatientConnectionState( void ); ///< Handle Patient Connection state during Pre-Treatment -static void publishPreTreatmentStates( void ); ///< Publish Pre-Treatment states to the UI. +static void setPreTreatStateTransition( void ); +static TD_PRE_TREATMENT_MODE_STATE_T handleInstallState( void ); +static TD_PRE_TREATMENT_MODE_STATE_T handleDrySelfTestState( void ); +static TD_PRE_TREATMENT_MODE_STATE_T handlePrimeState( void ); +static TD_PRE_TREATMENT_MODE_STATE_T handleRecirculateState( void ); +static TD_PRE_TREATMENT_MODE_STATE_T handleRxState( void ); +static TD_PRE_TREATMENT_MODE_STATE_T handleHeparinSetupState( void ); +static TD_PRE_TREATMENT_MODE_STATE_T handlePatientConnectionState( void ); +static void handlePreTreatmentQdTransition( void ); +static void publishPreTreatmentStates( void ); /*********************************************************************//** * @brief @@ -78,21 +97,28 @@ **************************************************************************/ void initPreTreatmentMode( void ) { - // Start a fresh Treatment Parameters session for this run. initTreatmentParameters(); - currentPreTreatmentState = TD_PRE_TREATMENT_TUBING_SET_INSTALL_STATE; + currentPreTreatmentState = TD_PRE_TREATMENT_TUBING_SET_INSTALL_STATE; goToInstallStateRequested = FALSE; + alarmActionResumeReceived = FALSE; continueFromRecirculateRequested = FALSE; + continueFromHeparinSetupRequested = FALSE; treatmentStartRequested = FALSE; + submodeCompleteTransitionTimeCounter = 0; + lowQdTransitionActive = FALSE; + lowQdTransitionStartTime = 0U; + defaultQdApplied = FALSE; + preTreatmentRxUpdated = FALSE; preTreatmentStateBroadcastTimerCtr = PRE_TREATMENT_STATE_DATA_PUB_INITIAL_OFFSET; - preTreatmentStatePublishInterval = (OVERRIDE_U32_T) { PRE_TREATMENT_STATE_DATA_PUB_INTERVAL, PRE_TREATMENT_STATE_DATA_PUB_INTERVAL, PRE_TREATMENT_STATE_DATA_PUB_INTERVAL, 0 }; + initPreTxHeparinSetup(); + initDrySelfTests(); } /*********************************************************************//** @@ -146,22 +172,25 @@ break; case TD_PRE_TREATMENT_SELF_TEST_DRY_STATE: - currentPreTreatmentState = handleSelfTestDryState(); + currentPreTreatmentState = handleDrySelfTestState(); break; case TD_PRE_TREATMENT_PRIME_STATE: currentPreTreatmentState = handlePrimeState(); break; case TD_PRE_TREATMENT_CONFIRM_RX_STATE: - // Confirm Rx state currentPreTreatmentState = handleRxState(); break; case TD_PRE_TREATMENT_RECIRCULATE_STATE: currentPreTreatmentState = handleRecirculateState(); break; + case TD_PRE_TREATMENT_HEPARIN_SETUP_STATE: + currentPreTreatmentState = handleHeparinSetupState(); + break; + case TD_PRE_TREATMENT_PATIENT_CONNECTION_STATE: currentPreTreatmentState = handlePatientConnectionState(); break; @@ -173,17 +202,33 @@ break; } + if ( currentPreTreatmentState > TD_PRE_TREATMENT_PRIME_STATE ) + { + handlePreTreatmentQdTransition(); + } if ( prevPreTreatmentState != currentPreTreatmentState ) { setPreTreatStateTransition(); } - publishPreTreatmentStates(); return (U32)currentPreTreatmentState; } /*********************************************************************//** + * @brief + * The getPreTreatmentSubState function gets the current + * pre-treatment mode state. + * @details \b Inputs: currentPreTreatmentState + * @details \b Outputs: none + * @return currentPreTreatmentState + *************************************************************************/ +TD_PRE_TREATMENT_MODE_STATE_T getPreTreatmentSubState( void ) +{ + return currentPreTreatmentState; +} + +/*********************************************************************//** * @brief * The setPreTreatStateTransition function sets the actuators and variables * for the state transition in Pre-Treatment mode. @@ -206,7 +251,7 @@ break; case TD_PRE_TREATMENT_SELF_TEST_DRY_STATE: - // TODO: actuator configuration + transitionToDrySelfTests(); break; case TD_PRE_TREATMENT_PRIME_STATE: @@ -219,6 +264,10 @@ setValvePosition( H19_VALV, VALVE_POSITION_C_CLOSE ); break; + case TD_PRE_TREATMENT_HEPARIN_SETUP_STATE: + // Heparin Setup transition is already handled in handleRxState(). + break; + case TD_PRE_TREATMENT_RECIRCULATE_STATE: // No action required. break; @@ -246,7 +295,6 @@ } /*********************************************************************//** - * @brief * The handleInstallState function calls Tube Set Install Service and * advances to Self Test Dry state once the service signals * completion. @@ -258,39 +306,57 @@ { TD_PRE_TREATMENT_MODE_STATE_T state = TD_PRE_TREATMENT_TUBING_SET_INSTALL_STATE; - // call tube set install service to auto-load tube set + // Call Tube Set Install Service to auto-load the tube set. execTubeSetInstall(); if ( TRUE == isTubeSetInstallComplete() ) { - state = TD_PRE_TREATMENT_SELF_TEST_DRY_STATE; + state = TD_PRE_TREATMENT_SELF_TEST_DRY_STATE ; } return state; } /*********************************************************************//** * @brief - * The handleSelfTestDryState function executes the Self Test Dry state - * of pre-treatment mode. - * @details \b Inputs: TODO fill up if any - * @details \b Outputs: TODO fill up if any - * @return next Pre-Treatment mode state. + * The handleDrySelfTestState function executes the Dry Self-Test + * pre-treatment sub-mode. + * @details \b Inputs: alarmActionResumeReceived, + * goToInstallStateRequested, submodeCompleteTransitionTimeCounter, + * @details \b Outputs: alarmActionResumeReceived, + * goToInstallStateRequested, submodeCompleteTransitionTimeCounter + * @return current Pre-Treatment state *************************************************************************/ -static TD_PRE_TREATMENT_MODE_STATE_T handleSelfTestDryState( void ) +static TD_PRE_TREATMENT_MODE_STATE_T handleDrySelfTestState( void ) { TD_PRE_TREATMENT_MODE_STATE_T state = TD_PRE_TREATMENT_SELF_TEST_DRY_STATE; + if ( TRUE == alarmActionResumeReceived ) + { + alarmActionResumeReceived = FALSE; + signalResumeDrySelfTests(); + } + execDrySelfTests(); if ( TRUE == goToInstallStateRequested ) { goToInstallStateRequested = FALSE; - initTubeSetInstall(); + state = TD_PRE_TREATMENT_TUBING_SET_INSTALL_STATE; } + else if ( DRY_SELF_TESTS_COMPLETE_STATE == getDrySelfTestsState() ) + { + if ( submodeCompleteTransitionTimeCounter++ >= SUBMODE_COMPLETE_UI_TRANSITION_TIME_COUNT ) + { + submodeCompleteTransitionTimeCounter = 0; + setAlarmUserActionEnabled( ALARM_USER_ACTION_RESUME, TRUE ); + state = TD_PRE_TREATMENT_PRIME_STATE; + } + } + else + { + submodeCompleteTransitionTimeCounter = 0; + } - setAlarmUserActionEnabled( ALARM_USER_ACTION_RESUME, TRUE ); - state = TD_PRE_TREATMENT_PRIME_STATE; - return state; } @@ -346,6 +412,29 @@ /*********************************************************************//** * @brief + * The handleHeparinSetupState function executes the Heparin Setup state of + * pre-treatment mode. + * @details \b Inputs: continueFromHeparinSetupRequested. + * @details \b Outputs: continueFromHeparinSetupRequested + * @return next Pre-Treatment mode state. + *************************************************************************/ +static TD_PRE_TREATMENT_MODE_STATE_T handleHeparinSetupState( void ) +{ + TD_PRE_TREATMENT_MODE_STATE_T state = TD_PRE_TREATMENT_HEPARIN_SETUP_STATE; + + execPreTxHeparinSetup(); + + if ( TRUE == continueFromHeparinSetupRequested ) + { + continueFromHeparinSetupRequested = FALSE; + state = TD_PRE_TREATMENT_PATIENT_CONNECTION_STATE; + } + + return state; +} + +/*********************************************************************//** + * @brief * The handleRxState function executes the Confirm Rx pre-treatment step. * @details \b Inputs: none * @details \b Outputs: Requests transition to the next Pre-Treatment state when the prescription @@ -356,36 +445,62 @@ { BOOL paramsValid = getValidTreatParamsReceived(); BOOL paramsConfirmed = getTreatParamsConfirmed(); + BOOL heparinIsPrescribed = ( ( getTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME ) > 0.0F ) || + ( getTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_DELIVERY_RATE ) > 0.0F ) ) ? TRUE : FALSE; BOOL isDialysateGoodToDeliver = TRUE; // TODO replace TRUE with getDialysateGoodToDeliverStatus() when we are ready F32 bicarbConvFactor = BICARBONATE_CONVERSION_FACTOR; F32 presUFVolumeL = 0.0F; F32 presUFRateMlMin = 0.0F; + U32 prescribedQd = 0U; + F32 prescribedDialTemp = 0.0F; + F32 ddQd = 0.0F; + F32 ddDialTemp = 0.0F; U32 ddSubMode = getDDSubMode(); TD_PRE_TREATMENT_MODE_STATE_T state = TD_PRE_TREATMENT_CONFIRM_RX_STATE; DD_OP_MODE_T ddOpMode = getDDOpMode(); - // Valid + confirmed – move to next state: Recirculate State + // Valid + confirmed – move to Heparin Setup or Patient Connection. if ( ( TRUE == paramsValid ) && ( TRUE == paramsConfirmed ) ) { - // TODO this command of requesting dialysate delivery will move to appropriate state in pre-treatment once implemented if ( ( ddOpMode == DD_MODE_PREG ) && ( ddSubMode == DD_PRE_GEN_DIALYSATE_WAIT_FOR_GEND ) ) { presUFVolumeL = getTreatmentParameterF32( TREATMENT_PARAM_UF_VOLUME ); presUFRateMlMin = ( presUFVolumeL * (F32)ML_PER_LITER ) / (F32)getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION ); + prescribedQd = getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ); + prescribedDialTemp = getTreatmentParameterF32( TREATMENT_PARAM_DIALYSATE_TEMPERATURE ); + + ddQd = (F32)prescribedQd; + ddDialTemp = prescribedDialTemp; + + if ( ( prescribedQd <= PRE_TX_LOW_QD_THRESHOLD_ML_MIN ) && + ( ( TRUE == lowQdTransitionActive ) || ( TRUE == preTreatmentRxUpdated ) ) ) + { + ddQd = (F32)PRE_TX_INTERMEDIATE_QD_ML_MIN; + ddDialTemp = prescribedDialTemp + 1.0F; + } + // Direct DD to generate dialysate and bypass while priming blood - cmdStartGenerateDialysate( (F32)getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), presUFRateMlMin, - 0, //getTreatmentParameterF32( TREATMENT_PARAM_DIALYSATE_TEMPERATURE ), //TODO: Update temperature with tx param temp when we are ready + cmdStartGenerateDialysate( ddQd, + presUFRateMlMin, + 0, // ddDialTemp, //TODO: Update temperature with tx param temp when we are ready TRUE, getTreatmentParameterF32( TREATMENT_PARAM_ACID_CONCENTRATE_CONV_FACTOR ), bicarbConvFactor, getTreatmentParameterU32( TREATMENT_PARAM_SODIUM ), getTreatmentParameterU32( TREATMENT_PARAM_BICARBONATE ) ); } + if ( TRUE == heparinIsPrescribed ) + { + transitionToPreTxHeparinSetup(); + state = TD_PRE_TREATMENT_HEPARIN_SETUP_STATE; + } + else + { + state = TD_PRE_TREATMENT_PATIENT_CONNECTION_STATE; + } + } - state = TD_PRE_TREATMENT_PATIENT_CONNECTION_STATE; - } - - return state; + return state; } /*********************************************************************//** @@ -412,6 +527,73 @@ /*********************************************************************//** * @brief + * The handlePreTreatmentQdTransition function manages the dialysate flow + * and temperature transition after priming is complete. + * @details \b Inputs: preTreatmentRxUpdated, lowQdTransitionActive, + * lowQdTransitionStartTime, defaultQdApplied, treatment parameters. + * @details \b Outputs: preTreatmentRxUpdated, lowQdTransitionActive, + * lowQdTransitionStartTime, defaultQdApplied, dialysate flow rate, + * dialysate target temperature. + * @return none. + *************************************************************************/ +static void handlePreTreatmentQdTransition( void ) +{ + U32 prescribedQd; + F32 prescribedDialTemp; + + if ( TRUE != getValidTreatParamsReceived() ) + { + if ( TRUE != defaultQdApplied ) + { + cmdChangeQd( PRE_TX_DEFAULT_QD_ML_MIN ); + defaultQdApplied = TRUE; + } + } + else + { + prescribedQd = getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ); + prescribedDialTemp = getTreatmentParameterF32( TREATMENT_PARAM_DIALYSATE_TEMPERATURE ); + + if ( TRUE == preTreatmentRxUpdated ) + { + preTreatmentRxUpdated = FALSE; + defaultQdApplied = FALSE; + + if ( prescribedQd <= PRE_TX_LOW_QD_THRESHOLD_ML_MIN ) + { + if ( TRUE != lowQdTransitionActive ) + { + cmdChangeQd( PRE_TX_INTERMEDIATE_QD_ML_MIN ); + + lowQdTransitionStartTime = getMSTimerCount(); + lowQdTransitionActive = TRUE; + } + + cmdChangeDialysateTemperature( prescribedDialTemp + 1.0F ); + } + else + { + cmdChangeQd( prescribedQd ); + cmdChangeDialysateTemperature( prescribedDialTemp ); + + lowQdTransitionActive = FALSE; + } + } + + if ( ( TRUE == lowQdTransitionActive ) && + ( TRUE == didTimeout( lowQdTransitionStartTime, + PRE_TX_LOW_QD_TRANSITION_TIME_MS ) ) ) + { + cmdChangeQd( prescribedQd ); + cmdChangeDialysateTemperature( prescribedDialTemp ); + + lowQdTransitionActive = FALSE; + } + } +} + +/*********************************************************************//** + * @brief * The PreTxRequestTubeSetInstall function signals a request to transition * the Pre-Treatment mode state machine to Install state. * @details \b Inputs: none @@ -438,93 +620,142 @@ /*********************************************************************//** * @brief - * The handleStartTreatmentRequest function handles the UI request to - * start treatment. - * @details \b Message \b Received: MSG_ID_UI_START_TREATMENT_REQUEST. - * @details \b Message \b Sent: MSG_ID_TD_START_TREATMENT_RESPONSE. - * @details \b Inputs: current operation mode and Pre-Treatment state. - * @details \b Outputs: treatmentStartRequested. - * @param message Pointer to the received Start Treatment request message. - * @return TRUE if the request was accepted, otherwise FALSE. + * The PreTxRequestContinueFromHeparinSetupRequested function signals a request to + * transition the Pre-Treatment mode state machine to Patient Connection state. + * @details \b Inputs: none + * @details \b Outputs: continueFromHeparinSetupRequested + * @return none *************************************************************************/ +void PreTxRequestContinueFromHeparinSetupRequested( void ) +{ + continueFromHeparinSetupRequested = TRUE; +} + +/*********************************************************************//** +* @brief +* The handleStartTreatmentRequest function handles the UI request to +* start treatment. +* @details \b Message \b Received: MSG_ID_UI_START_TREATMENT_REQUEST. +* @details \b Message \b Sent: MSG_ID_TD_START_TREATMENT_RESPONSE. +* @details \b Inputs: current operation mode and Pre-Treatment state. +* @details \b Outputs: treatmentStartRequested. +* @param message Pointer to the received Start Treatment request message. +* @return TRUE if the request was accepted, otherwise FALSE. +*************************************************************************/ BOOL handleStartTreatmentRequest( MESSAGE_T *message ) { - TD_OP_MODE_T mode = getCurrentOperationMode(); - TD_PRE_TREATMENT_MODE_STATE_T preTxState = currentPreTreatmentState; - U32 payloadLen = message->hdr.payloadLen; - BOOL accepted = FALSE; - UI_RESPONSE_PAYLOAD_T response; + TD_OP_MODE_T mode = getCurrentOperationMode(); + TD_PRE_TREATMENT_MODE_STATE_T preTxState = currentPreTreatmentState; + U32 payloadLen = message->hdr.payloadLen; + BOOL accepted = FALSE; + UI_RESPONSE_PAYLOAD_T response; - response.accepted = FALSE; - response.rejectionReason = REQUEST_REJECT_REASON_ACTION_DISABLED_IN_CURRENT_STATE; + response.accepted = FALSE; + response.rejectionReason = REQUEST_REJECT_REASON_ACTION_DISABLED_IN_CURRENT_STATE; - if ( ( 0U == payloadLen ) && ( MODE_PRET == mode ) && - ( TD_PRE_TREATMENT_PATIENT_CONNECTION_STATE == preTxState ) ) + if ( ( 0U == payloadLen ) && ( MODE_PRET == mode ) && + ( TD_PRE_TREATMENT_PATIENT_CONNECTION_STATE == preTxState ) ) - { - treatmentStartRequested = TRUE; - accepted = TRUE; - response.accepted = TRUE; - response.rejectionReason = REQUEST_REJECT_REASON_NONE; - } + { + treatmentStartRequested = TRUE; + accepted = TRUE; + response.accepted = TRUE; + response.rejectionReason = REQUEST_REJECT_REASON_NONE; + } - sendMessage( MSG_ID_TD_START_TREATMENT_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, - (U08 *)&response, sizeof( UI_RESPONSE_PAYLOAD_T ) ); + sendMessage( MSG_ID_TD_START_TREATMENT_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, + (U08 *)&response, sizeof( UI_RESPONSE_PAYLOAD_T ) ); - return accepted; + return accepted; } /*********************************************************************//** - * @brief - * The signalPreTreatmentBackoutToStandby function handles a request to - * back out of Pre-Treatment to Standby. - * @details \b Inputs: current operation mode, currentPreTreatmentState, - * and Tube Set Install state. - * @details \b Outputs: Requests Standby Mode when backout is allowed. - * @return TRUE if the request is accepted, otherwise FALSE. - *************************************************************************/ +* @brief +* The signalPreTreatmentBackoutToStandby function handles a request to +* back out of Pre-Treatment to Standby. +* @details \b Inputs: current operation mode, currentPreTreatmentState, +* and Tube Set Install state. +* @details \b Outputs: Requests Standby Mode when backout is allowed. +* @return TRUE if the request is accepted, otherwise FALSE. +*************************************************************************/ BOOL signalPreTreatmentBackoutToStandby( void ) { - BOOL accepted = FALSE; + BOOL accepted = FALSE; - if ( ( MODE_PRET == getCurrentOperationMode() ) && - ( TD_PRE_TREATMENT_TUBING_SET_INSTALL_STATE == currentPreTreatmentState ) && - ( TRUE == isTubeSetInstallAwaitingConfirmation() ) ) - { - requestNewOperationMode( MODE_STAN ); - accepted = TRUE; - } + if ( ( MODE_PRET == getCurrentOperationMode() ) && + ( TD_PRE_TREATMENT_TUBING_SET_INSTALL_STATE == currentPreTreatmentState ) && + ( TRUE == isTubeSetInstallAwaitingConfirmation() ) ) + { + requestNewOperationMode( MODE_STAN ); + accepted = TRUE; + } - return accepted; + return accepted; } /*********************************************************************//** * @brief + * The signalPreTreatmentRxUpdated function signals that a new or updated + * treatment prescription has been received during Pre-Treatment. + * @details \b Inputs: none. + * @details \b Outputs: preTreatmentRxUpdated. + * @return none. + *************************************************************************/ +void signalPreTreatmentRxUpdated( void ) +{ + preTreatmentRxUpdated = TRUE; +} + +/*********************************************************************//** + * @brief * The signalAlarmActionToPreTreatmentMode function executes the given alarm action * as appropriate while in Pre-Treatment Mode. - * @details \b Inputs: currentPreTreatmentState - * @details \b Outputs: given alarm action executed - * @param action ID of alarm action to execute + * @details \b Inputs: currentPreTreatmentState and current Heparin Setup sub-state. + * @details \b Outputs: Alarm action handled for the active Pre-Treatment state. + * @param action ID of alarm action to execute. * @return none *************************************************************************/ void signalAlarmActionToPreTreatmentMode( ALARM_ACTION_T action ) { switch ( action ) { case ALARM_ACTION_STOP: - // TODO add logic once we have pre-treatment mode developed + // TODO add logic once we have pre-treatment mode developed. break; case ALARM_ACTION_RESUME: resumePreTxAlarmResponseRequest = TRUE; - if ( TD_PRE_TREATMENT_RECIRCULATE_STATE == currentPreTreatmentState ) - { + if ( TD_PRE_TREATMENT_SELF_TEST_DRY_STATE == currentPreTreatmentState ) + { + signalResumeDrySelfTests(); + } + else if ( TD_PRE_TREATMENT_RECIRCULATE_STATE == currentPreTreatmentState ) + { signalResumePreTxRecirculate(); - } - break; + } + else if ( TD_PRE_TREATMENT_HEPARIN_SETUP_STATE == currentPreTreatmentState ) + { + signalResumePreTxHeparinSetup(); + } + else + { + // No action required. + } + break; + case ALARM_ACTION_ACK: + if ( ( TD_PRE_TREATMENT_HEPARIN_SETUP_STATE == currentPreTreatmentState ) && + ( TRUE == isPreTxHeparinAwaitingSyringeLoadConfirmation() ) && + ( FALSE == isAlarmActive( ALARM_ID_TD_PRE_TX_HEPARIN_LOAD_SYRINGE ) ) ) + { + // OK on the Load Syringe clear-only alarm confirms that + // the syringe was loaded and resumes the paused state. + signalResumePreTxHeparinSetup(); + } + break; + default: - // do not handle other actions in pre-treatment mode + // Do not handle other actions in Pre-Treatment mode. break; } } @@ -559,7 +790,7 @@ payload.mSubMode = (U32)currentPreTreatmentState; payload.mInstallState = (U32)getTubeSetInstallState(); - payload.mSelfTestDryState = 0; + payload.mSelfTestDryState = getDrySelfTestsState(); payload.mPrimeState = 0; payload.mRecirculateState = getPreTxRecirculateState(); payload.mConfirmRxState = 0; Index: firmware/App/Modes/ModePreTreat.h =================================================================== diff -u -r6c933adfd50a0bc041dc29f4bfa15de5e9f4843a -r81e5d76c3906a8c18be914f5736a796436fd85b5 --- firmware/App/Modes/ModePreTreat.h (.../ModePreTreat.h) (revision 6c933adfd50a0bc041dc29f4bfa15de5e9f4843a) +++ firmware/App/Modes/ModePreTreat.h (.../ModePreTreat.h) (revision 81e5d76c3906a8c18be914f5736a796436fd85b5) @@ -7,8 +7,8 @@ * * @file ModePreTreat.h * -* @author (last) Vijay Pamula -* @date (last) 30-Jul-2026 +* @author (last) Varshini Nagabooshanam +* @date (last) 19-Aug-2026 * * @author (original) Dara Navaei * @date (original) 25-Sep-2025 @@ -38,10 +38,15 @@ void signalAlarmActionToPreTreatmentMode( ALARM_ACTION_T action ); // Execute alarm action as appropriate for pre-treatment mode BOOL signalPreTxResumeRequest( void ); // Signal resume alarm response from user +TD_PRE_TREATMENT_MODE_STATE_T getPreTreatmentSubState( void ); // Get the current pre-treatment sub mode. void PreTxRequestTubeSetInstall( void ); // Request Pre-Treatment mode to transition to Install state. +void PreTxRequestContinueFromRecirculate( void ); // Request Pre-Treatment mode to transition to Patient Connection state. +void PreTxRequestTubeSetInstall( void ); // Request Pre-Treatment mode to transition to Install state. void PreTxRequestContinueFromRecirculate( void ); // Request Pre-Treatment mode to transition to Confirm Rx. +void PreTxRequestContinueFromHeparinSetupRequested(void ); // Request Pre-Treatment mode to transition to Patient Connection state. BOOL handleStartTreatmentRequest ( MESSAGE_T *message ); // Handle UI request to start treatment. BOOL signalPreTreatmentBackoutToStandby( void ); // Request transition from Pre-Treatment Install: Await Confirmation to Standby. +void signalPreTreatmentRxUpdated( void ); // Signal that a new or updated Rx was received. BOOL testPreTreatmentStatePublishIntervalOverride( MESSAGE_T *message ); Index: firmware/App/Modes/ModeStandby.c =================================================================== diff -u -r6c933adfd50a0bc041dc29f4bfa15de5e9f4843a -r81e5d76c3906a8c18be914f5736a796436fd85b5 --- firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 6c933adfd50a0bc041dc29f4bfa15de5e9f4843a) +++ firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 81e5d76c3906a8c18be914f5736a796436fd85b5) @@ -7,25 +7,32 @@ * * @file ModeStandby.c * -* @author (last) Vijay Pamula -* @date (last) 27-Jul-2026 +* @author (last) Varshini Nagabooshanam +* @date (last) 19-Aug-2026 * * @author (original) Sean Nash * @date (original) 01-Aug-2024 * ***************************************************************************/ +#include "AirPump.h" #include "AirTrap.h" #include "BloodFlow.h" +#include "Bubbles.h" #include "Buttons.h" +#include "Compatible.h" #include "DDInterface.h" #include "Messaging.h" +#include "ModeInitPOST.h" +#include "ModePostTreat.h" #include "ModePreTreat.h" -#include "ModeTreatment.h" #include "ModeStandby.h" +#include "ModeTreatment.h" #include "OperationModes.h" #include "Switches.h" +#include "SyringePump.h" #include "SystemCommTD.h" +#include "SyringePump.h" #include "TxParams.h" #include "Valve3Way.h" #include "Valves.h" @@ -52,6 +59,7 @@ static TD_STANDBY_STATE_T handleStandbyModeStartState( void ); static TD_STANDBY_STATE_T handleStandbyModeWaitForTreatmentState( void ); +static void setStandbyStateTransition( void ); /*********************************************************************//** * @brief @@ -79,39 +87,48 @@ *************************************************************************/ U32 transitionToStandbyMode( void ) { - TD_OP_MODE_T previousOpMode = getPreviousOperationMode(); + TD_OP_MODE_T previousOpMode = getPreviousOperationMode(); //TODO +// U08 requestPayload[3] = { 0U, 0U, 0U }; // Re-initialize when transitioning to standby mode initStandbyMode(); resetDDInterface(); + resetAirTrap(); + resetBloodPumpRotorCount(); + resetPreLoadStatus(); + setVenousBubbleDetectionEnabled( H18_BBLD, FALSE ); setCurrentSubState( NO_SUB_STATE ); +// clearNoRetriggerFlag(); // Alarm flag // 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 ); - // Pumps should be off - signalBloodPumpHardStop(); -// stopSyringePump(); - // Set valves to default positions set3WayValveState( H13_VALV, VALVE_3WAY_COMMON_TO_CLOSED_STATE ); set3WayValveState( H20_VALV, VALVE_3WAY_COMMON_TO_CLOSED_STATE ); - if ( getValveState( H1_VALV ) < VALVE_STATE_IDLE ) + if ( VALVE_STATE_IDLE == getValveState( H1_VALV ) ) { setValvePosition( H1_VALV, VALVE_POSITION_A_INSERT_EJECT ); } - if ( getValveState( H19_VALV ) < VALVE_STATE_IDLE ) + if ( VALVE_STATE_IDLE == getValveState( H19_VALV ) ) { setValvePosition( H19_VALV, VALVE_POSITION_A_INSERT_EJECT ); } - + // Standby currently supports Start and Wait For Treatment states. + currentStandbyState = STANDBY_START_STATE; + // Pumps should be off + signalBloodPumpHardStop(); +// stopSyringePump(); doorClosedRequired( FALSE ); // door no longer required to be closed in standby mode // Request DD service record and usage information from DD -// sendDGServiceRequestToDG(); -// sendDGUsageInfoRequestToDG(); +// sendDDServiceRequestToDD(); + //TODO: Service record id not available +// sendMessage( MSG_ID_TD_DD_REQUEST_SERVICE_RECORD_FROM_TD, COMM_BUFFER_OUT_CAN_TD_2_DD, requestPayload, sizeof( requestPayload ) ); +// sendMessage( MSG_ID_TD_DD_USAGE_INFO_REQUEST, COMM_BUFFER_OUT_CAN_TD_2_DD, requestPayload, sizeof( requestPayload ) ); +// sendDDUsageInfoRequestToDD(); //TODO need to enable return currentStandbyState; } @@ -126,6 +143,7 @@ U32 execStandbyMode( void ) { BOOL stop = isStopButtonPressed(); + TD_STANDBY_STATE_T prevStandbyState = currentStandbyState; if ( TRUE == stop ) { @@ -148,64 +166,56 @@ currentStandbyState = STANDBY_START_STATE; break; } + if ( prevStandbyState != currentStandbyState ) + { + setStandbyStateTransition(); + } return currentStandbyState; } /*********************************************************************//** * @brief * The handleStandbyModeStartState function handles the standby start state. - * This state waits for the door to be closed and then initiates homing of - * pumps and valves and transitions to the wait for treatment state. - * @details \b Inputs: - * @details \b Outputs: + * This state initiates homing of the syringe pump and pinch valves, + * then transitions to Wait For Treatment after homing completes and + * then initiates homing of pumps and valves and transitions to the + * wait for treatment state. + * @details \b Inputs: homingInitiated + * @details \b Outputs: homingInitiated * @return next state of the standby mode state machine *************************************************************************/ static TD_STANDBY_STATE_T handleStandbyModeStartState( void ) { - TD_STANDBY_STATE_T state = STANDBY_WAIT_FOR_TREATMENT_STATE; + TD_STANDBY_STATE_T state = STANDBY_START_STATE; - // Wait for door to be closed so we can home actuators -// if ( STATE_CLOSED == getSwitchState( H9_SWCH ) ) -// { - // If we haven't already initiated homing of actuators, initiate now - if ( homingInitiated != TRUE ) - { - VALVE_T valve; + // If we haven't already initiated homing of actuators, initiate now + if ( FALSE == homingInitiated ) + { + VALVE_T valve; - // Home pumps and valves - for ( valve = FIRST_VALVE; valve < NUM_OF_VALVES; ++valve ) - { - homeValve( valve, FALSE, TRUE ); - } -// homeBloodPump(); -// homeDialInPump(); -// homeDialOutPump(); -// retractSyringePump(); + // Initiate homing for both pinch valves. + for ( valve = FIRST_VALVE; valve < NUM_OF_VALVES; ++valve ) + { + homeValve( valve, FALSE, TRUE ); + } + // Retract syringe pump if not already home. + if ( FALSE == isSyringePumpHome() ) + { + retractSyringePump(); + } - homingInitiated = TRUE; - } -// else -// { -// // If homing has been initiated, wait for syringe pump to home and the verify force sensor calibration -//#ifndef _RELEASE_ -// if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_SYRINGE_PUMP ) ) -// { -// state = STANDBY_WAIT_FOR_TREATMENT_STATE; // Go to wait for treatment state after above check -// } -// else -//#endif -// { -// if ( ( TRUE == isSyringePumpHome() ) && ( TRUE == isSyringePumpStopped() ) ) -// { -// syringePumpVerifyForceSensorDACCalibration(); -// homingInitiated = FALSE; // reset for next time -// doorClosedRequired( FALSE ); // door no longer required to be closed in standby mode -// state = STANDBY_WAIT_FOR_TREATMENT_STATE; // Go to wait for treatment state after above check -// } -// } -// } -// } + homingInitiated = TRUE; + } + else if ( ( VALVE_STATE_IDLE == getValveState( H1_VALV ) ) && + ( VALVE_STATE_IDLE == getValveState( H19_VALV ) ) ) + { + // After homing completes, move both pinch valves to Position A. + setValvePosition( H1_VALV, VALVE_POSITION_A_INSERT_EJECT ); + setValvePosition( H19_VALV, VALVE_POSITION_A_INSERT_EJECT ); + homingInitiated = FALSE; + state = STANDBY_WAIT_FOR_TREATMENT_STATE; + } return state; } @@ -221,43 +231,50 @@ static TD_STANDBY_STATE_T handleStandbyModeWaitForTreatmentState( void ) { TD_STANDBY_STATE_T state = STANDBY_WAIT_FOR_TREATMENT_STATE; - DD_OP_MODE_T ddOperationMode = getDDOpMode(); F32 bicarbConvFactor = BICARBONATE_CONVERSION_FACTOR; + TD_VERSIONS_T payload; + //TODO +// DD_OP_MODE_T ddOperationMode = getDDOpMode(); -// switch ( dgOperationMode ) +// switch ( ddOperationMode ) // { -// case DG_MODE_GENE: -// // If DG is in idle generation state while we are in standby mode, transition DG to standby too -// cmdStopDG(); +// case DD_MODE_GENE: +// // If DD is in idle generation state while we are in standby mode, transition DD to standby too +// cmdStopDD(); // break; // -// // If DG is any of the cleaning modes, set the HD standby to be in the corresponding cleaning mode -// case DG_MODE_FLUS: -// case DG_MODE_HEAT: -// case DG_MODE_CHEM: -// case DG_MODE_CHFL: -// case DG_MODE_HCOL: -// case DG_MODE_ROPS: -// setRequestedCleaningMode( dgOperationMode ); -// state = STANDBY_WAIT_FOR_DG_CLEANING_MODE_TO_START_STATE; +// // If DD is any of the cleaning modes, set the TD standby to be in the corresponding cleaning mode +// case DD_MODE_HEAT: +// case DD_MODE_HCOL: +// case DD_MODE_ROPS: +// setRequestedCleaningMode( ddOperationMode ); +// state = STANDBY_WAIT_FOR_DD_CLEANING_MODE_TO_START_STATE; +// // DD cleaning mode handling is not enabled yet. +// // Stay in Wait For Treatment until DD returns to a supported standby state. // break; // // default: -// // Do nothing. There are other DG modes that HD standby does not need to act upon them. +// // Do nothing. There are other DD modes that TD standby does not need to act upon them. // break; // } - // If DD is communicating and we don't yet have DD version info, request it -// if ( TRUE == isDDCommunicating() ) -// { -// DG_VERSIONS_T ddVersion = getDDVersion(); -// -// if ( 0 == dgVersion.compatibilityRev ) -// { -// sendFWVersionRequest(); -// } -// } + // If DD is communicating and we don't yet have DD version info, request it. + if ( TRUE == isDDCommunicating() ) + { + if ( FALSE == isDDCompatible() ) + { + // Populate TD firmware version payload. + payload.major = (U08)TD_VERSION_MAJOR; + payload.minor = (U08)TD_VERSION_MINOR; + payload.micro = (U08)TD_VERSION_MICRO; + payload.build = (U16)TD_VERSION_BUILD; + payload.compatibilityRev = (U32)SW_COMPATIBILITY_REV; + sendMessage( MSG_ID_FW_VERSIONS_REQUEST, COMM_BUFFER_OUT_CAN_TD_2_DD, + (U08 *)&payload, sizeof( TD_VERSIONS_T ) ); + } + } + // If treatment start is requested by user, initiate treatment workflow (transition to treatment params mode). if ( TRUE == treatStartReqReceived ) { @@ -266,7 +283,7 @@ // Initialize treatment modes before starting a new treatment initPreTreatmentMode(); initTreatmentMode(); -// initPostTreatmentMode(); + initPostTreatmentMode(); resetAirTrap(); // Send UI default pressure settings since user is not asked to set them. respRecord.artPresLimitWindowmmHg = getSysConfigTreatmentParameterU32DefaultValue( TREATMENT_PARAM_ART_PRES_LIMIT_WINDOW ); @@ -282,17 +299,72 @@ getTreatmentParameterU32( TREATMENT_PARAM_SODIUM ), getTreatmentParameterU32( TREATMENT_PARAM_BICARBONATE ) ); // Start treatment workflow with pretreatment mode - requestNewOperationMode( MODE_PRET ); - treatStartReqReceived = FALSE; // Set fluid type setFluidType( modality ); + requestNewOperationMode( MODE_PRET ); + treatStartReqReceived = FALSE; } return state; } /*********************************************************************//** * @brief + * The setStandbyStateTransition function sets the actuators and variables + * for Standby state transitions. + * @details \b Inputs: newState + * @details \b Outputs: Actuators configured for the new Standby state. + * @param newState New Standby state. + * @return none + *************************************************************************/ +static void setStandbyStateTransition( void ) +{ + // Common Standby actuator settings. + resetAirTrap(); + + setAirPumpState( AIR_PUMP_STATE_OFF, + AIR_PUMP_MOTOR_OFF ); + + set3WayValveState( H13_VALV, + VALVE_3WAY_COMMON_TO_CLOSED_STATE ); + + set3WayValveState( H20_VALV, + VALVE_3WAY_COMMON_TO_CLOSED_STATE ); + + stopSyringePump(); + signalBloodPumpHardStop(); + + switch ( currentStandbyState ) + { + case STANDBY_START_STATE: + // Homing is handled in handleStandbyModeStartState(). + break; + + case STANDBY_WAIT_FOR_TREATMENT_STATE: + setValvePosition( H1_VALV, + VALVE_POSITION_A_INSERT_EJECT ); + + setValvePosition( H19_VALV, + VALVE_POSITION_A_INSERT_EJECT ); + + // TODO: + // H5 Ejector Off + // Dialyzer Bypassed + // Qd 0 + // Quf 0 + // Qs 0 + break; + + default: + SET_ALARM_WITH_2_U32_DATA( + ALARM_ID_TD_SOFTWARE_FAULT, + SW_FAULT_ID_MODE_STANDBY_INVALID_STATE, + currentStandbyState ); + break; + } +} +/*********************************************************************//** + * @brief * The setFluidType function sets the fluid type based on the user's * treatment selection from the home screen. * @details \b Inputs: none @@ -352,52 +424,99 @@ BOOL signalUserInitiateTreatment( MESSAGE_T *message ) { BOOL result = FALSE; - U32 cmd = 0; - TD_OP_MODE_T mode = getCurrentOperationMode(); + INITIATE_TREATMENT_REQUEST_PAYLOAD_T cmd; + TD_OP_MODE_T mode = getCurrentOperationMode(); REQUEST_REJECT_REASON_CODE_T rejReason = REQUEST_REJECT_REASON_NONE; INITIATE_TREATMENT_REQUEST_PAYLOAD_T request; UI_RESPONSE_PAYLOAD_T response; + memset( &cmd, 0, sizeof( INITIATE_TREATMENT_REQUEST_PAYLOAD_T ) ); + memset( &response, 0, sizeof( UI_RESPONSE_PAYLOAD_T ) ); // Verify message payload length is valid if ( sizeof( INITIATE_TREATMENT_REQUEST_PAYLOAD_T ) == message->hdr.payloadLen ) { memcpy( &request, message->payload, sizeof( INITIATE_TREATMENT_REQUEST_PAYLOAD_T ) ); - cmd = request.command; + cmd.command = request.command; - if ( USER_COMMAND_INITIATE == cmd ) + if ( USER_COMMAND_INITIATE == cmd.command ) { - // Verify TD is in standby mode waiting for treatment start request - if ( ( mode != MODE_STAN ) || ( STANDBY_WAIT_FOR_TREATMENT_STATE != currentStandbyState ) ) + // Verify TD is in Standby mode and waiting for treatment start request. + if ( ( MODE_STAN != mode ) || ( STANDBY_WAIT_FOR_TREATMENT_STATE != currentStandbyState ) ) { rejReason = REQUEST_REJECT_REASON_NOT_ALLOWED_IN_CURRENT_MODE; } + else if ( TRUE == treatStartReqReceived ) + { + rejReason = REQUEST_REJECT_REASON_REQUEST_ALREADY_PENDING; + } else if ( request.modality >= NUM_OF_TREATMENT_MODALITY_TYPES ) { rejReason = REQUEST_REJECT_REASON_INVALID_COMMAND; } #ifndef TEST_UI_ONLY - // Verify DD is communicating with HD - else if ( isDDCommunicating() != TRUE ) + // Verify DD is communicating. + else if ( TRUE != isDDCommunicating() ) { rejReason = REQUEST_REJECT_REASON_DD_COMM_LOST; } - // Verify DD is not busy - else if ( ( DD_MODE_STAN != getDDOpMode() ) || ( DD_STANDBY_MODE_STATE_IDLE != getDDSubMode() ) ) // || ( isDDPOSTPassed() != TRUE ) ) + // Verify DD is ready and not busy with flush/disinfect/cleaning/generation. + else if ( ( DD_MODE_STAN != getDDOpMode() ) || ( DD_STANDBY_MODE_STATE_IDLE != getDDSubMode() ) ) { - rejReason = REQUEST_REJECT_REASON_DD_NOT_IN_STANDBY_IDLE_STATE; + rejReason = REQUEST_REJECT_REASON_DD_BUSY; } + else if ( FALSE == isDDCompatible() ) + { + rejReason = REQUEST_REJECT_REASON_DD_INCOMPATIBLE; + } + // TODO: Need to uncomment below after implementation +// else if ( TRUE == isDDDisinfectionOverdue() ) +// { +// rejReason = REQUEST_REJECT_REASON_DISINFECT_HAS_BEEN_EXPIRED; +// } +// else if ( TRUE == isDDFlushOverdue() ) +// { +// rejReason = REQUEST_REJECT_REASON_FILTER_FLUSH_HAS_BEEN_EXPIRED; +// } +// else if ( TRUE == isDDTemperatureTooHigh() ) +// { +// rejReason = REQUEST_REJECT_REASON_DD_TEMPERATURE_OUT_OF_RANGE; +// } +// else if ( TRUE == isDDServiceOverdue() ) +// { +// rejReason = REQUEST_REJECT_REASON_DD_SERVICE_IS_DUE; +// } +// else if ( TRUE == isTDServiceOverdue() ) +// { +// rejReason = REQUEST_REJECT_REASON_TD_SERVICE_IS_DUE; +// } +// else if ( FALSE == isFPStandbymode() ) +// { +// rejReason = REQUEST_REJECT_REASON_FP_BUSY; +// } +// else if ( TRUE == isfpServiceOverdue() ) +// { +// rejReason = REQUEST_REJECT_REASON_FP_SERVICE_IS_DUE; +// } + #endif else { - // If request to start treatment not rejected, set flag to initiate treatment workflow +// Low battery is a warning only, not a rejection. + //TODO +// if ( TRUE == isBatteryRemainingCapacityLessThan60Wh() ) +// { +// SET_ALARM( ALARM_ID_TD_LOW_BATTERY_CHARGE ); +// } + + // If request to start treatment not rejected, set flag to initiate treatment workflow. result = TRUE; treatStartReqReceived = TRUE; // Save modality to set later modality = (TREATMENT_TYPE_T)request.modality; } } - else if ( USER_COMMAND_CANCEL == cmd ) + else if ( USER_COMMAND_CANCEL == cmd.command ) { result = signalPreTreatmentBackoutToStandby(); @@ -408,14 +527,18 @@ } else { - rejReason = REQUEST_REJECT_REASON_INVALID_COMMAND; + rejReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; } } + else + { + rejReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + } - // Respond to request to start treatment - response.accepted = result; + // Respond to request to start treatment. + response.accepted = result; response.rejectionReason = rejReason; - sendMessage( MSG_ID_TD_RESP_INITIATE_TREATMENT_WORKFLOW, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08*)(&response), sizeof( UI_RESPONSE_PAYLOAD_T ) ); + sendMessage( MSG_ID_TD_RESP_INITIATE_TREATMENT_WORKFLOW, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08*) &response, sizeof( UI_RESPONSE_PAYLOAD_T ) ); return result; } @@ -434,22 +557,25 @@ switch ( action ) { case ALARM_ACTION_STOP: -// if ( isAlarmActive( ALARM_ID_HD_VENOUS_BUBBLE_DETECTED ) != TRUE ) -// { -// // no stop action in standby mode -// } -// // if Dialin enabled bubble detection, stop on venous bubble detection alarm -// else -// { -// // Pumps should be off -// signalBloodPumpHardStop(); -// stopSyringePump(); -// -// // Set valves to safe positions -// setValveAirTrap( STATE_CLOSED ); -// setValvePosition( H1_VALV, VALVE_POSITION_C_CLOSE ); -// setValvePosition( H19, VALVE_POSITION_C_CLOSE ); -// } + if ( isAlarmActive( ALARM_ID_TD_VENOUS_BUBBLE_DETECTED ) != TRUE ) + { + // no stop action in standby mode + } + // if Dialin enabled bubble detection, stop on venous bubble detection alarm + else + { + // Pumps should be off + signalBloodPumpHardStop(); + stopSyringePump(); + + // Set air trap valves to safe positions + set3WayValveState( H13_VALV, VALVE_3WAY_COMMON_TO_CLOSED_STATE ); + set3WayValveState( H20_VALV, VALVE_3WAY_COMMON_TO_CLOSED_STATE ); + + // Set pinch valves to safe positions + setValvePosition( H1_VALV, VALVE_POSITION_C_CLOSE ); + setValvePosition( H19_VALV, VALVE_POSITION_C_CLOSE ); + } break; default: Index: firmware/App/Modes/StatePreTxRecirculate.c =================================================================== diff -u -r25aeff9e9994d2e7aab3b4e6171c56fdac6a01fe -r81e5d76c3906a8c18be914f5736a796436fd85b5 --- firmware/App/Modes/StatePreTxRecirculate.c (.../StatePreTxRecirculate.c) (revision 25aeff9e9994d2e7aab3b4e6171c56fdac6a01fe) +++ firmware/App/Modes/StatePreTxRecirculate.c (.../StatePreTxRecirculate.c) (revision 81e5d76c3906a8c18be914f5736a796436fd85b5) @@ -8,7 +8,7 @@ * @file StatePreTxRecirculate.c * * @author (last) Vijay Pamula -* @date (last) 11-Jun-2026 +* @date (last) 18-Aug-2026 * * @author (original) Vijay Pamula * @date (original) 03-Jun-2026 @@ -38,8 +38,10 @@ // ********** private definitions ********** -#define PRE_TX_RECIRC_BLOOD_FLOW_RATE_ML_MIN 100 ///< Blood pump flow rate during recirculation in mL/min. -#define RECIRC_MEDIUM_TIME_MS ( 90 * SEC_PER_MIN * MS_PER_SECOND ) ///< Pre-Treatment recirc time before medium priority warning in milliseconds. +#define PRE_TX_RECIRC_INITIAL_BLOOD_FLOW_RATE_ML_MIN 500 ///< Initial blood pump flow rate during recirculation in mL/min. +#define PRE_TX_RECIRC_BLOOD_FLOW_RATE_ML_MIN 300 ///< Blood pump flow rate after the initial recirculation period in mL/min. +#define PRE_TX_RECIRC_INITIAL_BLOOD_FLOW_TIME_MS ( 30 * MS_PER_SECOND ) ///< Initial high blood flow duration in milliseconds. +#define RECIRC_MEDIUM_TIME_MS ( 90 * SEC_PER_MIN * MS_PER_SECOND ) ///< Recirculation time before medium priority warning. /// Enumeration of Pre-Treatment Recirculation sub-states. typedef enum PreTxRecirculate_States @@ -56,6 +58,7 @@ static U32 preTxRecircStartTime; ///< Recirculation start time (ms timer count). static BOOL recircMediumAlarmGiven; ///< Flag indicating medium recirculation alarm has been raised. +static BOOL initialBloodFlowComplete; ///< Flag indicating the initial high blood flow period is complete. // ********** private function prototypes ********** @@ -72,15 +75,16 @@ * @details \b Inputs: none. * @details \b Outputs: currentPreTxRecircState, * recircResumeRequested, preTxRecircStartTime, - * recircMediumAlarmGiven. + * recircMediumAlarmGiven, initialBloodFlowComplete * @return none. *************************************************************************/ void initPreTxRecirculate( void ) { - currentPreTxRecircState = PRE_TX_RECIRCULATE_STATE; - recircResumeRequested = FALSE; - preTxRecircStartTime = getMSTimerCount(); - recircMediumAlarmGiven = FALSE; + currentPreTxRecircState = PRE_TX_RECIRCULATE_STATE; + recircResumeRequested = FALSE; + preTxRecircStartTime = getMSTimerCount(); + recircMediumAlarmGiven = FALSE; + initialBloodFlowComplete = FALSE; } /*********************************************************************//** @@ -181,16 +185,28 @@ * @details \b Alarm: ALARM_ID_TD_PRIME_COMPLETED_MEDIUM if the * recirculation timeout expires. * @details \b Inputs: preTxRecircStartTime, - * recircMediumAlarmGiven. - * @details \b Outputs: recircMediumAlarmGiven. + * recircMediumAlarmGiven, initialBloodFlowComplete + * @details \b Outputs: recircMediumAlarmGiven, initialBloodFlowComplete * @return next Recirculate sub-state. *************************************************************************/ static PRE_TX_RECIRCULATE_STATE_T handlePreTxRecirculateState( void ) { PRE_TX_RECIRCULATE_STATE_T state = PRE_TX_RECIRCULATE_STATE; + if ( ( TRUE != initialBloodFlowComplete ) && + ( TRUE == didTimeout( preTxRecircStartTime, + PRE_TX_RECIRC_INITIAL_BLOOD_FLOW_TIME_MS ) ) ) + { + setBloodPumpTargetFlowRate( PRE_TX_RECIRC_BLOOD_FLOW_RATE_ML_MIN, + MOTOR_DIR_FORWARD, + PUMP_CONTROL_MODE_OPEN_LOOP ); + + initialBloodFlowComplete = TRUE; + } + if ( ( FALSE == recircMediumAlarmGiven ) && - ( TRUE == didTimeout( preTxRecircStartTime, RECIRC_MEDIUM_TIME_MS ) ) ) + ( TRUE == didTimeout( preTxRecircStartTime, + RECIRC_MEDIUM_TIME_MS ) ) ) { recircMediumAlarmGiven = TRUE; activateAlarmNoData( ALARM_ID_TD_PRIME_COMPLETED_MEDIUM ); @@ -231,8 +247,8 @@ * @brief * The setupPreTxRecirculate function configures the actuators * required for Pre-Treatment Recirculation. - * @details \b Inputs: none - * @details \b Outputs: none + * @details \b Inputs: initialBloodFlowComplete , preTxRecircStartTime + * @details \b Outputs: initialBloodFlowComplete * @return none *************************************************************************/ static void setupPreTxRecirculate( void ) @@ -249,11 +265,25 @@ retractEjector(); stopSyringePump(); - setBloodPumpTargetFlowRate( PRE_TX_RECIRC_BLOOD_FLOW_RATE_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + if ( ( TRUE == initialBloodFlowComplete ) || + ( TRUE == didTimeout( preTxRecircStartTime, + PRE_TX_RECIRC_INITIAL_BLOOD_FLOW_TIME_MS ) ) ) + { + initialBloodFlowComplete = TRUE; + setBloodPumpTargetFlowRate( PRE_TX_RECIRC_BLOOD_FLOW_RATE_ML_MIN, + MOTOR_DIR_FORWARD, + PUMP_CONTROL_MODE_OPEN_LOOP ); + } + else + { + setBloodPumpTargetFlowRate( PRE_TX_RECIRC_INITIAL_BLOOD_FLOW_RATE_ML_MIN, + MOTOR_DIR_FORWARD, + PUMP_CONTROL_MODE_OPEN_LOOP ); + } + // Direct DD to bypass dialyzer and perform no ultrafiltration cmdBypassDialyzer( TRUE ); - cmdChangeQd( getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ) ); cmdChangeQuf( 0.0F ); } Index: firmware/App/Services/AlarmMgmtSWFaults.h =================================================================== diff -u -r6c933adfd50a0bc041dc29f4bfa15de5e9f4843a -r81e5d76c3906a8c18be914f5736a796436fd85b5 --- firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision 6c933adfd50a0bc041dc29f4bfa15de5e9f4843a) +++ firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision 81e5d76c3906a8c18be914f5736a796436fd85b5) @@ -7,8 +7,8 @@ * * @file AlarmMgmtSWFaults.h * -* @author (last) Praneeth Bunne -* @date (last) 07-Aug-2026 +* @author (last) Varshini Nagabooshanam +* @date (last) 14-Aug-2026 * * @author (original) Sean Nash * @date (original) 01-Aug-2024 @@ -204,12 +204,15 @@ SW_FAULT_ID_TD_BP_MODULE_STATE = 173, SW_FAULT_ID_INVALID_RINSEBACK_STATE = 174, SW_FAULT_ID_TREATMENT_INVALID_RECIRC_STATE = 175, - SW_FAULT_ID_PID_CTRL_INVALID_CONTROLLER1 = 176, - SW_FAULT_ID_PID_CTRL_INVALID_CONTROLLER3 = 177, - SW_FAULT_ID_PID_CTRL_INVALID_CONTROLLER4 = 178, - SW_FAULT_ID_PID_CTRL_INVALID_SIGNAL = 179, - SW_FAULT_ID_MODE_PRE_TX_PRIME_INVALID_STATE = 180, - SW_FAULT_ID_INVALID_DD_BAL_CHAMBER_DATA = 181, + SW_FAULT_ID_TD_INVALID_PRE_TX_HEPARIN_SETUP_STATE =176, + SW_FAULT_ID_TD_INVALID_PRE_TX_HEPARIN_SETUP_REQUESTED_STATE = 177, + SW_FAULT_ID_TD_INVALID_DRY_SELF_TEST_STATE = 178, + SW_FAULT_ID_PID_CTRL_INVALID_CONTROLLER1 = 179, + SW_FAULT_ID_PID_CTRL_INVALID_CONTROLLER3 = 180, + SW_FAULT_ID_PID_CTRL_INVALID_CONTROLLER4 = 181, + SW_FAULT_ID_PID_CTRL_INVALID_SIGNAL = 182, + SW_FAULT_ID_MODE_PRE_TX_PRIME_INVALID_STATE = 183, + SW_FAULT_ID_INVALID_DD_BAL_CHAMBER_DATA = 184, NUM_OF_SW_FAULT_IDS } SW_FAULT_ID_T; Index: firmware/App/Services/DDInterface.c =================================================================== diff -u -r25aeff9e9994d2e7aab3b4e6171c56fdac6a01fe -r81e5d76c3906a8c18be914f5736a796436fd85b5 --- firmware/App/Services/DDInterface.c (.../DDInterface.c) (revision 25aeff9e9994d2e7aab3b4e6171c56fdac6a01fe) +++ firmware/App/Services/DDInterface.c (.../DDInterface.c) (revision 81e5d76c3906a8c18be914f5736a796436fd85b5) @@ -8,7 +8,7 @@ * @file DDInterface.c * * @author (last) Varshini Nagabooshanam -* @date (last) 15-Jun-2026 +* @date (last) 19-Aug-2026 * * @author (original) Sean Nash * @date (original) 01-Aug-2024 @@ -527,6 +527,36 @@ /*********************************************************************//** * @brief + * The cmdChangeDialysateTemperature function sends a generate dialysate + * command to the DD with a given new dialysate temperature. + * @details \b Inputs: none + * @details \b Outputs: dialysateDeliveryCmdSet + * @details \b Message \b Sent: Continue generate dialysate command w/ new + * dialysate temperature. + * @param dialTemp Target dialysate temperature in deg C. + * @return none + *************************************************************************/ +void cmdChangeDialysateTemperature( F32 dialTemp ) +{ + if ( TRUE == dialysateDeliveryCmdSet.start ) + { + dialysateDeliveryCmdSet.dialTemp = dialTemp; + +#ifndef TEST_UI_ONLY + sendMessage( MSG_ID_DD_GEN_DIALYSATE_REQUEST_DATA, + COMM_BUFFER_OUT_CAN_TD_2_DD, + (U08*)(&dialysateDeliveryCmdSet), + sizeof( DIALYSATE_DELIVERY_REQ_PAYLOAD_T ) ); +#endif + } + else + { + // TODO - s/w fault? + } +} + +/*********************************************************************//** + * @brief * The cmdBypassDialyzer function sends a generate dialysate command to the DD * with a given flag indicating whether dialyzer should be bypassed. * @details \b Inputs: none @@ -682,7 +712,8 @@ { dialysateDeliveryCmdSet.substitutionRate = qs; #ifndef TEST_UI_ONLY - sendMessage( MSG_ID_DD_GEN_DIALYSATE_REQUEST_DATA, COMM_BUFFER_OUT_CAN_TD_2_DD, (U08*)(&dialysateDeliveryCmdSet), sizeof( DIALYSATE_DELIVERY_REQ_PAYLOAD_T ) ); + sendMessage( MSG_ID_DD_GEN_DIALYSATE_REQUEST_DATA, COMM_BUFFER_OUT_CAN_TD_2_DD, + (U08*)(&dialysateDeliveryCmdSet), sizeof( DIALYSATE_DELIVERY_REQ_PAYLOAD_T ) ); #endif } else Index: firmware/App/Services/DDInterface.h =================================================================== diff -u -r25aeff9e9994d2e7aab3b4e6171c56fdac6a01fe -r81e5d76c3906a8c18be914f5736a796436fd85b5 --- firmware/App/Services/DDInterface.h (.../DDInterface.h) (revision 25aeff9e9994d2e7aab3b4e6171c56fdac6a01fe) +++ firmware/App/Services/DDInterface.h (.../DDInterface.h) (revision 81e5d76c3906a8c18be914f5736a796436fd85b5) @@ -7,8 +7,8 @@ * * @file DDInterface.h * -* @author (last) Praneeth Bunne -* @date (last) 27-May-2026 +* @author (last) Vijay Pamula +* @date (last) 19-Aug-2026 * * @author (original) Sean Nash * @date (original) 01-Aug-2024 @@ -63,6 +63,7 @@ void cmdStartGenerateDialysate( F32 qd, F32 quf, F32 dialTemp, BOOL bypass, F32 acidConvFactor, F32 bicarbConvFactor, U32 sodium, U32 bicarbonate ); void cmdChangeQd( F32 qd ); void cmdChangeQuf( F32 quf ); +void cmdChangeDialysateTemperature( F32 dialTemp ); void cmdBypassDialyzer( BOOL bypass ); void cmdStopGenerateDialysate( void ); void cmdSubstitutionRate (F32 qs ); Index: firmware/App/Services/Messaging.c =================================================================== diff -u -r6c933adfd50a0bc041dc29f4bfa15de5e9f4843a -r81e5d76c3906a8c18be914f5736a796436fd85b5 --- firmware/App/Services/Messaging.c (.../Messaging.c) (revision 6c933adfd50a0bc041dc29f4bfa15de5e9f4843a) +++ firmware/App/Services/Messaging.c (.../Messaging.c) (revision 81e5d76c3906a8c18be914f5736a796436fd85b5) @@ -7,8 +7,8 @@ * * @file Messaging.c * -* @author (last) Praneeth Bunne -* @date (last) 10-Aug-2026 +* @author (last) Varshini Nagabooshanam +* @date (last) 19-Aug-2026 * * @author (original) Sean Nash * @date (original) 01-Aug-2024 @@ -27,6 +27,7 @@ #include "Compatible.h" #include "CpldInterface.h" #include "DDInterface.h" +#include "DrySelfTests.h" #include "Ejector.h" #include "FluidBolus.h" #include "FpgaTD.h" @@ -40,7 +41,6 @@ #include "PAL.h" #include "Pressures.h" #include "Prime.h" -#include "RotaryValve.h" #include "StateTxBloodPrime.h" #include "StateTxDialysis.h" #include "StateTxPaused.h" @@ -139,6 +139,7 @@ { MSG_ID_UI_TREATMENT_SET_POINT_DIALYSATE_TEMP_CHANGE_REQUEST, &validateAndSetDialysateTemperature }, { MSG_ID_UI_BLOOD_PRIME_CMD_REQUEST, &bloodPrimeHandleCmdRequest }, { MSG_ID_UI_TREATMENT_SET_POINT_BLOOD_FLOW_CHANGE_REQUEST, &bloodPrimeHandleBloodFlowChangeRequest }, + { MSG_ID_UI_TUBE_SET_AUTHENTICATION_ACK_RESPONSE, &drySelfTestHandleTubingSetAuthResponse }, { MSG_ID_UI_ADJUST_DISPOSABLES_CONFIRM_REQUEST, &handleAutoLoadRequest }, { MSG_ID_UI_SETUP_TUBING_SET_CONNECTIONS_CONFIRM_REQUEST, &handleSetupTubingSetConnectionConfirmRequest }, { MSG_ID_UI_ADJUST_DISPOSABLES_REMOVAL_CONFIRM_REQUEST, &handleAutoEjectRequest }, @@ -171,9 +172,6 @@ { MSG_ID_TD_AIR_TRAP_LEVEL_RAW_OVERRIDE_REQUEST, &testRawLevelSensorOverride }, { MSG_ID_TD_AIR_TRAP_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testAirTrapDataPublishIntervalOverride }, { MSG_ID_TD_3_WAY_VALVE_SET_STATE_REQUEST, &testSet3WayValve }, - { MSG_ID_TD_ROTARY_PINCH_VALVE_SET_POS_REQUEST, &testSetValve }, - { MSG_ID_TD_ROTARY_PINCH_VALVE_STATUS_OVERRIDE_REQUEST, &testValveStatusOverride }, - { MSG_ID_TD_ROTARY_PINCH_VALVE_POSITION_OVERRIDE_REQUEST, &testValveEncoderPositionOverride }, { MSG_ID_TD_VALVES_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testValvesDataPublishIntervalOverride }, { MSG_ID_TD_PINCH_VALVE_SET_POSITION_REQUEST, &testValveSetABCCmdPosition }, { MSG_ID_TD_PINCH_VALVE_HOME_REQUEST, &testHomeValve },