Index: firmware/App/Modes/ModePreTreat.c =================================================================== diff -u -r83310420ae862de4724f8cfbbaeda9936c47801b -ree84e20f729b0aace2b1728c16de9a89e06eee38 --- firmware/App/Modes/ModePreTreat.c (.../ModePreTreat.c) (revision 83310420ae862de4724f8cfbbaeda9936c47801b) +++ firmware/App/Modes/ModePreTreat.c (.../ModePreTreat.c) (revision ee84e20f729b0aace2b1728c16de9a89e06eee38) @@ -41,6 +41,8 @@ static BOOL goToInstallStateRequested; ///< Flag indicating a request to transition to Install state. static BOOL continueFromRecirculateRequested; ///< Flag indicating a request to transition to Patient Connection state. +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. @@ -119,11 +121,11 @@ break; case TD_PRE_TREATMENT_SELF_TEST_DRY_STATE: - // currentPreTreatmentState = handleSelfTestDryState(); + currentPreTreatmentState = handleSelfTestDryState(); break; case TD_PRE_TREATMENT_PRIME_STATE: - // currentPreTreatmentState = handlePrimeState(); + currentPreTreatmentState = handlePrimeState(); break; case TD_PRE_TREATMENT_CONFIRM_RX_STATE: @@ -243,8 +245,7 @@ state = TD_PRE_TREATMENT_TUBING_SET_INSTALL_STATE; } - // TODO: Transition to Prime state on completion when implemented - // state = TD_PRE_TREATMENT_PRIME_STATE; + state = TD_PRE_TREATMENT_PRIME_STATE; return state; } @@ -253,17 +254,21 @@ * @brief * The handlePrimeState function executes the Prime state of * pre-treatment mode. - * @details \b Inputs: TODO fill up if any - * @details \b Outputs: TODO fill up if any + * @details \b Inputs: none + * @details \b Outputs: none * @return next Pre-Treatment mode state. *************************************************************************/ static TD_PRE_TREATMENT_MODE_STATE_T handlePrimeState( void ) { TD_PRE_TREATMENT_MODE_STATE_T state = TD_PRE_TREATMENT_PRIME_STATE; - // TODO: Transition to Recirculate state on completion when implemented - // state = TD_PRE_TREATMENT_RECIRCULATE_STATE; + execPrime(); + if ( PRIME_COMPLETE_STATE == getCurrentPrimeState() ) + { + state = TD_PRE_TREATMENT_RECIRCULATE_STATE; + } + return state; } @@ -401,6 +406,7 @@ break; case ALARM_ACTION_RESUME: + resumePreTxAlarmResponseRequest = TRUE; if ( TD_PRE_TREATMENT_RECIRCULATE_STATE == currentPreTreatmentState ) { signalResumePreTxRecirculate(); @@ -413,4 +419,16 @@ } } +/*********************************************************************//** + * @brief + * The signalPreTxResumeRequest function signals that user wants to resume. + * @details \b Inputs: resumePreTxAlarmResponseRequest + * @details \b Outputs: none + * @return TRUE if resume has been requested, FALSE if not + *************************************************************************/ +BOOL signalPreTxResumeRequest( void ) +{ + return resumePreTxAlarmResponseRequest; +} + /**@}*/ Index: firmware/App/Modes/ModePreTreat.h =================================================================== diff -u -r2f282113c1540be57b9d00833224d7ce93d460cd -ree84e20f729b0aace2b1728c16de9a89e06eee38 --- firmware/App/Modes/ModePreTreat.h (.../ModePreTreat.h) (revision 2f282113c1540be57b9d00833224d7ce93d460cd) +++ firmware/App/Modes/ModePreTreat.h (.../ModePreTreat.h) (revision ee84e20f729b0aace2b1728c16de9a89e06eee38) @@ -36,6 +36,7 @@ U32 transitionToPreTreatmentMode( void ); // Prepares for transition to pre-treatment mode U32 execPreTreatmentMode( void ); // Execute the pre-treatment mode state machine (call from OperationModes) void signalAlarmActionToPreTreatmentMode( ALARM_ACTION_T action ); // Execute alarm action as appropriate for pre-treatment mode +BOOL signalPreTxResumeRequest( void ); 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. Index: firmware/App/Services/AlarmMgmtSWFaults.h =================================================================== diff -u -r8345f0415ce34f2f47afcbf613a00216769f51c6 -ree84e20f729b0aace2b1728c16de9a89e06eee38 --- firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision 8345f0415ce34f2f47afcbf613a00216769f51c6) +++ firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision ee84e20f729b0aace2b1728c16de9a89e06eee38) @@ -199,6 +199,7 @@ SW_FAULT_ID_PRE_TX_RECIRC_INVALID_STATE = 168, SW_FAULT_ID_TD_VALVES_INVALID_VALVE2 = 169, SW_FAULT_ID_INVALID_TUBE_SET_TYPE = 170, + SW_FAULT_ID_MODE_PRE_TX_PRIME_INVALID_STATE = 171, NUM_OF_SW_FAULT_IDS } SW_FAULT_ID_T; Index: firmware/App/Services/DDInterface.c =================================================================== diff -u -r1b83a4555c4040a45cecfbea45b6570812ab281e -ree84e20f729b0aace2b1728c16de9a89e06eee38 --- firmware/App/Services/DDInterface.c (.../DDInterface.c) (revision 1b83a4555c4040a45cecfbea45b6570812ab281e) +++ firmware/App/Services/DDInterface.c (.../DDInterface.c) (revision ee84e20f729b0aace2b1728c16de9a89e06eee38) @@ -43,13 +43,16 @@ static BOOL ddStartCommandSent; ///< Flag indicates command to start DD has been sent. static BOOL ddStarted; ///< Flag indicates whether we have commanded the DD to start or stop. static BOOL isDialysateGoodtoDeliver; ///< Flag indicating whether dialysate is good to deliver. +static U32 currentGenDState; ///< Current state of DD GenD mode. static BOOL ddOpModeDataFreshFlag; ///< Flag to signal the handleDDOpMode() to process fresh dd op mode data. static BOOL ddDialysatePressureFreshFlag; ///< Flag to signal static PRE_GEN_DIALYSATE_REQ_PAYLOAD_T preGenDialysateCmdSet; ///< Set of pre-generate dialysate parameters to send to the DD static DIALYSATE_DELIVERY_REQ_PAYLOAD_T dialysateDeliveryCmdSet; ///< Set of dialysate delivery parameters to send to the DD during treatment. +static PRIME_DATA_REQ_PAYLOAD_T primeDataCmdSet; + // DD command response static DD_CMD_RESPONSE_T ddCmdResp[ NUM_OF_DD_COMMANDS ]; ///< Keep the latest DD command response for each command. @@ -73,6 +76,7 @@ ddSubMode = 0; dialysatePressure = 0.0F; isDialysateGoodtoDeliver = FALSE; + currentGenDState = 0; ddOpModeDataFreshFlag = FALSE; ddDialysatePressureFreshFlag = FALSE; @@ -121,6 +125,9 @@ dialysateDeliveryCmdSet.sodium = 0; dialysateDeliveryCmdSet.bicarbonate = 0; dialysateDeliveryCmdSet.substitutionRate = 0.0F; + + primeDataCmdSet.chamberHValveOpen = FALSE; + primeDataCmdSet.primeFluidDiscardStart = FALSE; } /**********************************************************************//** @@ -267,6 +274,7 @@ if ( message->hdr.payloadLen == sizeof( GEN_DIALYSATE_MODE_DATA_T ) ) { isDialysateGoodtoDeliver = payload.isDialysateGoodtoDeliver; + currentGenDState = payload.genDialysateExecState; result = TRUE; } else @@ -307,6 +315,18 @@ /*********************************************************************//** * @brief + * The getCurrentGenDState function gets the current state of gen dialysate. + * @details \b Inputs: currentGenDState + * @details \b Outputs: none + * @return Current state of gen dialysate + *************************************************************************/ +BOOL getCurrentGenDState( void ) +{ + return currentGenDState; +} + +/*********************************************************************//** + * @brief * The setDialysatePressure function sets the latest dialysate pressure * reported by the DD sub-system. * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if message invalid. @@ -625,7 +645,58 @@ } } +/*********************************************************************//** + * @brief + * The cmdDDChamberHValveOpen function sends a prime data request to the DD + * to open or close the Chamber H vent valve (D47) during dialysate circuit + * prime depressurization. + * @details \b Message \b Sent: MSG_ID_DD_TD_PRIME_REQUEST_DATA + * @details \b Inputs: none + * @details \b Outputs: primeDataCmdSet + * @param valveOpenRequest TRUE to open the Chamber H vent valve, FALSE to close it + * @return none + *************************************************************************/ +void cmdDDChamberHValveOpen( BOOL valveOpenRequest ) +{ + if ( TRUE == dialysateDeliveryCmdSet.start ) + { + primeDataCmdSet.chamberHValveOpen = valveOpenRequest; +#ifndef TEST_UI_ONLY + sendMessage( MSG_ID_DD_TD_PRIME_REQUEST_DATA, COMM_BUFFER_OUT_CAN_TD_2_DD, (U08*)(&primeDataCmdSet), sizeof( PRIME_DATA_REQ_PAYLOAD_T ) ); +#endif + } + else + { + // TODO - s/w fault? + } +} +/*********************************************************************//** + * @brief + * The cmdDDprimeFluidDiscard function sends a prime data request to the DD + * to start or stop discarding the priming fluid via the ultrafiltration + * pump (D76) during priming fluid discard and dialyzer reverse prime. + * @details \b Message \b Sent: MSG_ID_DD_TD_PRIME_REQUEST_DATA + * @details \b Inputs: none + * @details \b Outputs: primeDataCmdSet + * @param primeFluidDiscardRequest TRUE to start priming fluid discard, FALSE to stop it + * @return none + *************************************************************************/ +void cmdDDprimeFluidDiscard( BOOL primeFluidDiscardRequest ) +{ + if ( TRUE == dialysateDeliveryCmdSet.start ) + { + primeDataCmdSet.primeFluidDiscardStart = primeFluidDiscardRequest; +#ifndef TEST_UI_ONLY + sendMessage( MSG_ID_DD_TD_PRIME_REQUEST_DATA, COMM_BUFFER_OUT_CAN_TD_2_DD, (U08*)(&primeDataCmdSet), sizeof( PRIME_DATA_REQ_PAYLOAD_T ) ); +#endif + } + else + { + // TODO - s/w fault? + } +} + /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ Index: firmware/App/Services/DDInterface.h =================================================================== diff -u -r9c833ef5623ce842267e284d958820ac0dc3a7fc -ree84e20f729b0aace2b1728c16de9a89e06eee38 --- firmware/App/Services/DDInterface.h (.../DDInterface.h) (revision 9c833ef5623ce842267e284d958820ac0dc3a7fc) +++ firmware/App/Services/DDInterface.h (.../DDInterface.h) (revision ee84e20f729b0aace2b1728c16de9a89e06eee38) @@ -52,6 +52,7 @@ U32 getDDSubMode( void ); F32 getDialysatePressure( void ); BOOL getDialysateGoodToDeliverStatus( void ); +BOOL getCurrentGenDState( void ); BOOL setDDOpMode( MESSAGE_T *message ); BOOL setDialysateData( MESSAGE_T *message ); @@ -63,7 +64,9 @@ void cmdChangeQuf( F32 quf ); void cmdBypassDialyzer( BOOL bypass ); void cmdStopGenerateDialysate( void ); -void cmdSubstitutionRate (F32 qs ); +void cmdSubstitutionRate (F32 qs ); +void cmdDDChamberHValveOpen( BOOL valveOpenRequest ); +void cmdDDprimeFluidDiscard( BOOL primeFluidDiscardRequest ); void handleDDCommandResponse( DD_CMD_RESPONSE_T *ddCmdRespPtr ); BOOL getDDCommandResponse( U32 commandID, DD_CMD_RESPONSE_T *cmdRespPtr ); Index: firmware/App/Services/StateServices/Prime.c =================================================================== diff -u --- firmware/App/Services/StateServices/Prime.c (revision 0) +++ firmware/App/Services/StateServices/Prime.c (revision ee84e20f729b0aace2b1728c16de9a89e06eee38) @@ -0,0 +1,1122 @@ +/************************************************************************** +* +* Copyright (c) 2026-2026 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 Prime.c +* +* @author (last) Praneeth Bunne +* @date (last) 16-Jul-2026 +* +* @author (original) Praneeth Bunne +* @date (original) 16-Jul-2026 +* +***************************************************************************/ + +#include // Used for fabs() functions + +#include "AirPump.h" +#include "AirTrap.h" +#include "BloodFlow.h" +#include "DDInterface.h" +#include "LevelSensors.h" +#include "Pressures.h" +#include "Prime.h" +#include "Switches.h" +#include "TaskGeneral.h" +#include "Timers.h" +#include "TxParams.h" +#include "Valves.h" +#include "Valve3Way.h" + +/** + * @addtogroup Prime + * @{ + */ + +// ********** private definitions ********** + +/// Interval (ms/task time) at which the prime data is published on the CAN bus. +#define PRIME_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) + +/// Overall time allowed to complete priming. +#define PRIME_TOTAL_DURATION_INTERVAL ( 8U * 60U * MS_PER_SECOND ) + +/// Max time allowed paused before pause timeout alarms. +#define PRIME_PAUSE_TIMEOUT_INTERVAL ( 5U * 60U * MS_PER_SECOND ) + +/// Air pump duty cycle used for active air trap raise/lower during blood circuit prime. +#define AIR_PUMP_DUTY_CYCLE_PRIME_PCT 50.0F + +/// Venous pressure lower bound during active air removal. +#define BC_NEG_VEN_PRES_LIMIT_MMHG -150.0F + +/// Duration limit for bc prime initial reverse state. +#define BC_INITIAL_REV_PRIME_INTERVAL ( 40U * MS_PER_SECOND ) + +/// Duration of pause in bc prime initial reverse state. +#define BC_INITIAL_REV_PRIME_PAUSE_INTERVAL ( 500U ) + +/// Number of neg pressure pause events allowed before alarming. +#define BC_INITIAL_REV_MAX_RETRIES 2U + +/// Max purge time for bc initial dialyzer prime state +#define BC_MAX_PURGE_INTERVAL ( 8U * MS_PER_SECOND ) + +/// Blood tubing set fill flow rate. +#define INITIAL_SET_BLOOD_FLOW_RATE 150U + +/// Blood pump flow rate used while pinch valve is closed during clear stage pinch cycling. +#define PINCH_SET_BLOOD_FLOW_RATE 50U + +/// Blood pump flow rate used during clear stage 3 saline purge. +#define SALINE_PURGE_SET_BLOOD_FLOW_RATE 400U + +/// Blood pump flow rate used during post-prime recirculation. +#define RECIRC_SET_BLOOD_FLOW_RATE 300U + +/// Max time allowed for each blood circuit clear stage. +#define SLOW_PURGE_INTERVAL ( 20U * MS_PER_SECOND ) + +/// Duration the arterial pinch valve stays closed during each pinch cycle. +#define PINCH_INTERVAL_MS ( 5U * MS_PER_SECOND ) + +///< Target venous pressure during pinching +#define TARGET_VEN_PRES_LIMIT_MMHG 200.0F + +/// Target dialysate flow rate used to calculate dialysate circuit initial prime duration. +#define TARGET_DIALYSATE_FLOW_RATE 600U + +/// Venous pressure limit above which dialysate circuit prime pauses to depressurize. +#define DC_PRIME_VEN_PRES_LIMIT_MMHG 250U + +/// Venous pressure limit below which dialysate circuit prime resumes after depressurizing. +#define DC_PRIME_RESUME_VEN_PRES_LIMIT_MMHG 150U + +/// Max time allowed for venous pressure to stabilize during dialysate circuit depressurize. +#define VEN_PRES_STABILIZATION_TIMEOUT_INTERVAL_MS ( 5U * MS_PER_SECOND ) + +/// Estimated blood tubing set cartridge volume, used to calculate prime discard duration. +#define CARTRIDGE_VOLUME 123.8F + +/// Maximum ultrafiltration pump (D76) speed used during priming fluid discard and reverse prime. +#define MAX_UF_RATE 200U + +/// Duration of each forward pass in the blood pump reversal sequence. +#define BC2_FWD_RECIRC_INTERVAL ( 25U * MS_PER_SECOND ) + +/// Duration of the venous pinch pressure cycling window within each forward pass. +#define BC2_PINCH_CYCLE_INTERVAL ( 15U * MS_PER_SECOND ) + +/// Duration of the reverse pass in the blood pump reversal sequence. +#define BC2_REV_RECIRC_INTERVAL ( 10U * MS_PER_SECOND ) + +/// Blood pump stop duration between forward and reverse passes. +#define BC2_PAUSE_INTERVAL ( 1U * MS_PER_SECOND ) + +/// Venous pressure limit above which the venous pinch valve closes during forward pass pinch cycling. +#define BC2_MAX_VEN_PRES_LIMIT_MMHG 200U + +/// Venous pressure limit below which the venous pinch valve reopens during forward pass pinch cycling. +#define BC2_STABLE_VEN_PRES_LIMIT_MMHG 100U + +// ********** private data ********** + +static TD_PRIME_STATE_T currentPrimeState; ///< Current state of the Prime state machine. +static TD_PRIME_STATE_T prevPrimeState; ///< Previous state of the Prime state machine. +static TD_PRIME_STATE_T nextStateAfterAirTrapLower; ///< Next state to transition to once air trap lowers. + +static U32 primeStartTime; ///< Priming start time (ms), used for elapsed time / pause adjustment. +static U32 primePauseStartTime; ///< Time pause was entered (ms). +static U32 primePublishTimerCtr; ///< Timer counter for next status broadcast. +static U32 primeElapsedAtPauseMs; ///< Elapsed active prime time captured at pause entry. +static U32 stateEntryTimerCtr; ///< Timer counter for state entry. +static U32 bcRevPrimePauseTimerCtr; ///< Timer counter for bc initial rev prime pause. +static U32 bcRevPrimeRetryCtr; ///< Counter for bc rev prime retry. +static U32 pinchStartTime; ///< Timer counter for pinch valve cycle. +static U32 dialyzerDialysateVolume; ///< Selected dialyzer jacket (dialysate) volume (mL). +static U32 dilayzerBloodVolume; ///< Selected dialyzer core (blood) volume (mL). +static U32 dcDepressurizeElapsedMs; ///< Timer counter for dc depressurize venous pressure stabilization. +static U32 dcInitialPrimeInterval; ///< Calculated dc initial dialyzer prime duration (ms). +static U32 dcDiscardDuration; ///< Calculated priming fluid discard duration (ms). +static U32 dcReversePrimeDuration; ///< Calculated dialyzer reverse prime duration (ms). +static U32 dcDiscardAndRevPrimeInterval; ///< Greater of dcDiscardDuration and dcReversePrimeDuration (ms). +static BOOL revRecircVisited; ///< Flag indicates bc2 reverse recirc pass has been completed. +static BOOL primeResumeRequested; ///< Flag indicates user requested resume from pause. + +// ********** private function prototypes ********** + +static TD_PRIME_STATE_T handlePrimeBCInitialReverseState( void ); +static TD_PRIME_STATE_T handlePrimeBCWaitForAirTrapLowerState( void ); +static TD_PRIME_STATE_T handlePrimeBCInitialDialyzerState( void ); +static TD_PRIME_STATE_T handlePrimeBCFillState( void ); +static TD_PRIME_STATE_T handlePrimeBCClearState1( void ); +static TD_PRIME_STATE_T handlePrimeBCClearState2( void ); +static TD_PRIME_STATE_T handlePrimeBCClearState3( void ); +static TD_PRIME_STATE_T handlePrimeWaitForDialysateReadyState( void ); +static TD_PRIME_STATE_T handlePrimeDCInitialDialyzerState( void ); +static TD_PRIME_STATE_T handlePrimeDCDepressurizeState( void ); +static TD_PRIME_STATE_T handleWaitForAirTrapFillState( void ); +static TD_PRIME_STATE_T handleBC2ForwardRecircState( void ); +static TD_PRIME_STATE_T handleBC2PauseToRotateOppDirState( void ); +static TD_PRIME_STATE_T handleBC2ReverserRecircState( void ); +static TD_PRIME_STATE_T handlePrimeDiscardAndReversePrimeState( void ); +static TD_PRIME_STATE_T handlePrimePauseState( void ); + +static void resetPrimeFlags( void ); +static void publishPrimeData( void ); + +/*********************************************************************//** + * @brief + * The initPrime function initializes the prime service module. + * This function will reset anything required before the start of priming sequence. + * @details \b Inputs: none + * @details \b Outputs: Prime service initialized. + * @return none + *************************************************************************/ +void initPrime( void ) +{ + currentPrimeState = PRIME_START_STATE; + prevPrimeState = PRIME_START_STATE; + nextStateAfterAirTrapLower = PRIME_BC_INITIAL_DIALYZER_STATE; + primeStartTime = 0; + primePauseStartTime = 0; + primePublishTimerCtr = PRIME_DATA_PUB_INTERVAL - 8; + stateEntryTimerCtr = 0; + bcRevPrimePauseTimerCtr = 0; + bcRevPrimeRetryCtr = 0; + dcDepressurizeElapsedMs = 0; + revRecircVisited = FALSE; + primeResumeRequested = FALSE; + dialyzerDialysateVolume = getDialyzerDialysateVolume( getTreatmentParameterF32( TREATMENT_PARAM_DIALYZER_TYPE ) ); + dilayzerBloodVolume = getDialyzerBloodVolume( getTreatmentParameterF32( TREATMENT_PARAM_DIALYZER_TYPE ) ); + dcInitialPrimeInterval = (U32)( ( ( dialyzerDialysateVolume * 60.0F ) / (F32)TARGET_DIALYSATE_FLOW_RATE + 30.0F ) * (F32)MS_PER_SECOND ); + dcDiscardDuration = (U32)( ( ( dilayzerBloodVolume + CARTRIDGE_VOLUME ) * 1.5F ) / MAX_UF_RATE ) * (F32)( SEC_PER_MIN * MS_PER_SECOND ) ; + dcReversePrimeDuration = (U32)( ( ( dialyzerDialysateVolume * 0.5F * (F32)SEC_PER_MIN ) / (F32)MAX_UF_RATE ) + 30.0F ) * (F32)MS_PER_SECOND; + dcDiscardAndRevPrimeInterval = ( dcDiscardDuration > dcReversePrimeDuration ) ? dcDiscardDuration : dcReversePrimeDuration; +} + +/*********************************************************************//** + * @brief + * The setPrimeStateTransition function performs the actuator setup + * (valves, blood pump, air pump/trap) required upon entry into the given + * Prime state. Called both during normal forward state progression and + * during pause/resume to deterministically re-establish actuator state. + * @details \b Inputs: nextStateAfterAirTrapLower, revRecircVisited + * @details \b Outputs: stateEntryTimerCtr, pinchStartTime, actuator commands + * @param state target Prime state being transitioned into + * @return none + *************************************************************************/ +static void setPrimeStateTransition( TD_PRIME_STATE_T state ) +{ + switch ( state ) + { + case PRIME_BC_INITIAL_REVERSE_STATE: + signalBloodPumpHardStop(); + setValvePosition( H1_VALV, VALVE_POSITION_A_INSERT_EJECT ); + setValvePosition( H19_VALV, VALVE_POSITION_B_OPEN ); + set3WayValveState( H20_VALV, VALVE_3WAY_COMMON_TO_OPEN_STATE ); + setAirPumpState( AIR_PUMP_STATE_ON, AIR_PUMP_DUTY_CYCLE_PRIME_PCT ); + stateEntryTimerCtr = getMSTimerCount(); + bcRevPrimePauseTimerCtr = 0; + bcRevPrimeRetryCtr = 0; + break; + + case PRIME_BC_AIR_TRAP_LOWER_STATE: + if ( PRIME_BC_INITIAL_DIALYZER_STATE == nextStateAfterAirTrapLower ) + { + // Leaving Venous Line state -- stop the H12/H20 reverse-prime drive. + setAirPumpState( AIR_PUMP_STATE_OFF, AIR_PUMP_MOTOR_OFF ); + } + else + { + // Leaving Dialyzer Purge state -- stop the forward BP purge. + signalBloodPumpHardStop(); + setValvePosition( H1_VALV, VALVE_POSITION_B_OPEN ); + } + set3WayValveState( H20_VALV, VALVE_3WAY_COMMON_TO_CLOSED_STATE ); + set3WayValveState( H13_VALV, VALVE_3WAY_COMMON_TO_OPEN_STATE ); + setAirPumpState( AIR_PUMP_STATE_ON, AIR_PUMP_DUTY_CYCLE_PRIME_PCT ); + break; + + case PRIME_BC_INITIAL_DIALYZER_STATE: + setValvePosition( H1_VALV, VALVE_POSITION_C_CLOSE ); + setBloodPumpTargetFlowRate( MAX_SET_BLOOD_FLOW_RATE, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + stateEntryTimerCtr = getMSTimerCount(); + break; + + case PRIME_BC_FILL_STATE: + setValvePosition( H1_VALV, VALVE_POSITION_C_CLOSE ); + setBloodPumpTargetFlowRate( INITIAL_SET_BLOOD_FLOW_RATE, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + break; + + case PRIME_BC_CLEAR_STATE1: + signalBloodPumpHardStop(); + set3WayValveState( H20_VALV, VALVE_3WAY_COMMON_TO_CLOSED_STATE ); + setValvePosition( H1_VALV, VALVE_POSITION_B_OPEN ); + setValvePosition( H19_VALV, VALVE_POSITION_B_OPEN ); + setBloodPumpTargetFlowRate( INITIAL_SET_BLOOD_FLOW_RATE, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + stateEntryTimerCtr = getMSTimerCount(); + pinchStartTime = getMSTimerCount(); + break; + + case PRIME_BC_CLEAR_STATE2: + setValvePosition( H1_VALV, VALVE_POSITION_B_OPEN ); + setValvePosition( H19_VALV, VALVE_POSITION_B_OPEN ); + setBloodPumpTargetFlowRate( MAX_SET_BLOOD_FLOW_RATE, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + stateEntryTimerCtr = getMSTimerCount(); + break; + + case PRIME_BC_CLEAR_STATE3: + setValvePosition( H1_VALV, VALVE_POSITION_B_OPEN ); + setValvePosition( H19_VALV, VALVE_POSITION_B_OPEN ); + setBloodPumpTargetFlowRate( SALINE_PURGE_SET_BLOOD_FLOW_RATE, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + stateEntryTimerCtr = getMSTimerCount(); + pinchStartTime = getMSTimerCount(); + break; + + case PRIME_WAIT_FOR_DIALYSATE_READY_STATE: + signalBloodPumpHardStop(); + setValvePosition( H1_VALV, VALVE_POSITION_B_OPEN ); + setValvePosition( H19_VALV, VALVE_POSITION_B_OPEN ); + break; + + case PRIME_DC_INITIAL_DIALYSATE_STATE: + cmdBypassDialyzer( FALSE ); + stateEntryTimerCtr = getMSTimerCount(); + dcDepressurizeElapsedMs = getMSTimerCount(); + break; + + case PRIME_DC_DEPRESSURIZE_STATE: + // TODO: Remove if not required in future. + //cmdDDChamberHValveOpen( TRUE ); + break; + + case PRIME_WAIT_FOR_AIR_TRAP_FILL_STATE: + cmdBypassDialyzer( TRUE ); + startAirTrapControl(); + break; + + case PRIME_BC2_FORWARD_RECIRC_STATE: + setValvePosition( H1_VALV, VALVE_POSITION_A_INSERT_EJECT ); + setValvePosition( H19_VALV, VALVE_POSITION_B_OPEN ); + setBloodPumpTargetFlowRate( MAX_SET_BLOOD_FLOW_RATE, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + stateEntryTimerCtr = getMSTimerCount(); + break; + + case PRIME_BC2_PAUSE_TO_ROTATE_OPP_DIR_STATE: + signalBloodPumpHardStop(); + stateEntryTimerCtr = getMSTimerCount(); + break; + + case PRIME_BC2_REVERSE_RECIRC_STATE: + revRecircVisited = TRUE; + setValvePosition( H19_VALV, VALVE_POSITION_B_OPEN ); + setBloodPumpTargetFlowRate( MAX_SET_BLOOD_FLOW_RATE, MOTOR_DIR_REVERSE, PUMP_CONTROL_MODE_OPEN_LOOP ); + stateEntryTimerCtr = getMSTimerCount(); + break; + + case PRIME_DC_DISCARD_AND_REVERSE_PRIME_STATE: + signalBloodPumpHardStop(); + cmdDDprimeFluidDiscard( TRUE ); + //cmdChangeQuf( MAX_UF_RATE ); + setValvePosition( H1_VALV, VALVE_POSITION_A_INSERT_EJECT ); + setValvePosition( H19_VALV, VALVE_POSITION_B_OPEN ); + setBloodPumpTargetFlowRate( RECIRC_SET_BLOOD_FLOW_RATE, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + stateEntryTimerCtr = getMSTimerCount(); + break; + + case PRIME_PAUSE_STATE: + signalBloodPumpHardStop(); + setValvePosition( H1_VALV, VALVE_POSITION_C_CLOSE ); + setValvePosition( H19_VALV, VALVE_POSITION_C_CLOSE ); + + 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 ); + + cmdBypassDialyzer( TRUE ); + cmdDDprimeFluidDiscard( FALSE ); + + primePauseStartTime = getMSTimerCount(); + prevPrimeState = currentPrimeState; + break; + + case PRIME_COMPLETE_STATE: + cmdDDprimeFluidDiscard( FALSE ); + signalBloodPumpHardStop(); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_PRE_TX_PRIME_INVALID_STATE, (U32)state ); + break; + } +} + +/*********************************************************************//** + * @brief + * The execPrime function executes the prime service state machine. + * @details \b Inputs: currentPrimeState + * @details \b Outputs: currentPrimeState + * @return none + *************************************************************************/ +void execPrime( void ) +{ + TD_PRIME_STATE_T priorPrimeState = currentPrimeState; + + // Does alarm indicate stop? + if ( TRUE == doesAlarmStatusIndicateStop() ) + { + setPrimeStateTransition( PRIME_PAUSE_STATE ); + currentPrimeState = PRIME_PAUSE_STATE; + } + + // execute prime service state machine + switch ( currentPrimeState ) + { + case PRIME_START_STATE: + setPrimeStateTransition ( PRIME_BC_INITIAL_REVERSE_STATE ); + currentPrimeState = PRIME_BC_INITIAL_REVERSE_STATE; + break; + + case PRIME_BC_INITIAL_REVERSE_STATE: + currentPrimeState = handlePrimeBCInitialReverseState(); + break; + + case PRIME_BC_AIR_TRAP_LOWER_STATE: + currentPrimeState = handlePrimeBCWaitForAirTrapLowerState(); + break; + + case PRIME_BC_INITIAL_DIALYZER_STATE: + currentPrimeState = handlePrimeBCInitialDialyzerState(); + break; + + case PRIME_BC_FILL_STATE: + currentPrimeState = handlePrimeBCFillState(); + break; + + case PRIME_BC_CLEAR_STATE1: + currentPrimeState = handlePrimeBCClearState1(); + break; + + case PRIME_BC_CLEAR_STATE2: + currentPrimeState = handlePrimeBCClearState2(); + break; + + case PRIME_BC_CLEAR_STATE3: + currentPrimeState = handlePrimeBCClearState3(); + break; + + case PRIME_WAIT_FOR_DIALYSATE_READY_STATE: + currentPrimeState = handlePrimeWaitForDialysateReadyState(); + break; + + case PRIME_DC_INITIAL_DIALYSATE_STATE: + currentPrimeState = handlePrimeDCInitialDialyzerState(); + break; + + case PRIME_DC_DEPRESSURIZE_STATE: + currentPrimeState = handlePrimeDCDepressurizeState(); + break; + + case PRIME_WAIT_FOR_AIR_TRAP_FILL_STATE: + currentPrimeState = handleWaitForAirTrapFillState(); + break; + + case PRIME_BC2_FORWARD_RECIRC_STATE: + currentPrimeState = handleBC2ForwardRecircState(); + break; + + case PRIME_BC2_PAUSE_TO_ROTATE_OPP_DIR_STATE: + currentPrimeState = handleBC2PauseToRotateOppDirState(); + break; + + case PRIME_BC2_REVERSE_RECIRC_STATE: + currentPrimeState = handleBC2ReverserRecircState(); + break; + + case PRIME_DC_DISCARD_AND_REVERSE_PRIME_STATE: + currentPrimeState = handlePrimeDiscardAndReversePrimeState(); + break; + + case PRIME_PAUSE_STATE: + currentPrimeState = handlePrimePauseState(); + break; + + case PRIME_COMPLETE_STATE: + // ok, do nothing here. pre-treatment will move on to recirculate once we get here. + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_PRE_TX_PRIME_INVALID_STATE, currentPrimeState ); + break; + } + + // Prime flags should be handled by now + resetPrimeFlags(); + + if ( priorPrimeState != currentPrimeState ) + { + SEND_EVENT_WITH_2_U32_DATA( TD_EVENT_SUB_STATE_CHANGE, priorPrimeState, currentPrimeState ); + } + + // Broadcast priming data + publishPrimeData(); +} + +/*********************************************************************//** + * @brief + * The getCurrentPrimeState function returns the current state of prime sub-mode. + * @details \b Inputs: currentPrimeState + * @details \b Outputs: none + * @return current prime state + *************************************************************************/ +TD_PRIME_STATE_T getCurrentPrimeState( void ) +{ + return currentPrimeState; +} + +/*********************************************************************//** + * @brief + * The signalResumePrime function signals the prime service to resume + * previous operation. + * @details \b Inputs: none + * @details \b Outputs: primeResumeRequested + * @return none + *************************************************************************/ +void signalResumePrime( void ) +{ + primeResumeRequested = TRUE; +} + +/*********************************************************************//** + * @brief + * The resetPrimeFlags function resets all prime signal flags. + * @details \b Inputs: none + * @details \b Outputs: signal flags set to FALSE + * @return none + *************************************************************************/ +static void resetPrimeFlags( void ) +{ + primeResumeRequested = FALSE; +} + +/*********************************************************************//** + * @brief + * The handlePrimeBcVenousLineState function handles prime blood circuit + * initial reverse state of prime service. Primes the venous line and air trap + * via active air removal until H17 reads fluid. + * @details \b Inputs: stateEntryTimerCtr, bcRevPrimePauseTimerCtr, bcRevPrimeRetryCtr + * @details \b Outputs: stateEntryTimerCtr, bcRevPrimePauseTimerCtr, bcRevPrimeRetryCtr + * nextStateAfterAirTrapLower + * @return next Prime state + *************************************************************************/ +static TD_PRIME_STATE_T handlePrimeBCInitialReverseState( void ) +{ + TD_PRIME_STATE_T state = PRIME_BC_INITIAL_REVERSE_STATE; + F32 venPres = getFilteredVenousPressure(); + + // Does h17 reads fluid? + if ( AIR_TRAP_LEVEL_FLUID == getLevelSensorState( H17_LEVL ) ) + { + nextStateAfterAirTrapLower = PRIME_BC_INITIAL_DIALYZER_STATE; + setPrimeStateTransition ( PRIME_BC_AIR_TRAP_LOWER_STATE ); + state = PRIME_BC_AIR_TRAP_LOWER_STATE; + } + else if ( AIR_PUMP_STATE_ON == getAirPumpState() ) + { + // Currently running - keep pulling, unless negative pressure limit hit + if ( venPres <= BC_NEG_VEN_PRES_LIMIT_MMHG ) + { + setAirPumpState( AIR_PUMP_STATE_OFF, AIR_PUMP_MOTOR_OFF ); + set3WayValveState( H20_VALV, VALVE_3WAY_COMMON_TO_CLOSED_STATE ); + bcRevPrimePauseTimerCtr = getMSTimerCount(); + bcRevPrimeRetryCtr++; + + // Max retries exceeded? + if ( bcRevPrimeRetryCtr >= BC_INITIAL_REV_MAX_RETRIES ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_TD_INITIAL_BC_REV_PRIME_LIMIT_REACHED, bcRevPrimeRetryCtr ); + } + } + else + { + set3WayValveState( H20_VALV, VALVE_3WAY_COMMON_TO_OPEN_STATE ); + setAirPumpState( AIR_PUMP_STATE_ON, AIR_PUMP_DUTY_CYCLE_PRIME_PCT ); + } + } + // Pause time reached? + else if ( TRUE == didTimeout( bcRevPrimePauseTimerCtr, BC_INITIAL_REV_PRIME_PAUSE_INTERVAL ) ) + { + // Paused, recheck delay elapsed - exclude the paused interval from the 40s timer, then resume + stateEntryTimerCtr += calcTimeSince( bcRevPrimePauseTimerCtr ); + setAirPumpState( AIR_PUMP_STATE_ON, AIR_PUMP_DUTY_CYCLE_PRIME_PCT ); + set3WayValveState( H20_VALV, VALVE_3WAY_COMMON_TO_OPEN_STATE ); + } + else + { + // Paused, still waiting on the 0.5s recheck delay - no action. + } + + // Max time exceeded for this state? + if ( TRUE == didTimeout( stateEntryTimerCtr, BC_INITIAL_REV_PRIME_INTERVAL ) ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_TD_INITIAL_BC_REV_PRIME_TIMEOUT, BC_INITIAL_REV_PRIME_INTERVAL ); + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handlePrimeBCAirTrapLowerState function handles wait for air trap lower + * state of prime service. Actively lowers the air trap fluid level until H17 reads air, + * then transitions to whichever state requested the lower operation. + * @details Inputs: none + * @details Outputs: none + * @return next Prime state + *************************************************************************/ +static TD_PRIME_STATE_T handlePrimeBCWaitForAirTrapLowerState( void ) +{ + TD_PRIME_STATE_T state = PRIME_BC_AIR_TRAP_LOWER_STATE; + + // Does h17 reads air? + if ( AIR_TRAP_LEVEL_AIR == getLevelSensorState( H17_LEVL ) ) + { + setPrimeStateTransition ( nextStateAfterAirTrapLower ); + state = nextStateAfterAirTrapLower; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handlePrimeBCInitialDialyzerState function handles the prime blood circuit + * initial dialyzer state of prime service. Runs BP at maximum rate to purge + * the residual air pocket from the blood pump tubing until H17 reads fluid + * or the max purge interval elapses. + * @details \b Inputs: stateEntryTimerCtr + * @details \b Outputs: nextStateAfterAirTrapLower + * @return next Prime state + *************************************************************************/ +static TD_PRIME_STATE_T handlePrimeBCInitialDialyzerState( void ) +{ + TD_PRIME_STATE_T state = PRIME_BC_INITIAL_DIALYZER_STATE; + + // Does h17 reads fluid or max time reached? + if ( ( AIR_TRAP_LEVEL_FLUID == getLevelSensorState( H17_LEVL ) ) || + ( TRUE == didTimeout( stateEntryTimerCtr, BC_MAX_PURGE_INTERVAL ) ) ) + { + nextStateAfterAirTrapLower = PRIME_BC_FILL_STATE; + setPrimeStateTransition ( PRIME_BC_AIR_TRAP_LOWER_STATE ); + state = PRIME_BC_AIR_TRAP_LOWER_STATE; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handlePrimeBCFillState function handles the prime blood circuit + * fill state of prime service. Fills the dialyzer core at the initial + * blood flow rate until H17 reads fluid. + * @details \b Inputs: none + * @details \b Outputs: none + * @return next Prime state + *************************************************************************/ +static TD_PRIME_STATE_T handlePrimeBCFillState( void ) +{ + TD_PRIME_STATE_T state = PRIME_BC_FILL_STATE; + + // Does h17 reads fluid? + if ( AIR_TRAP_LEVEL_FLUID == getLevelSensorState( H17_LEVL ) ) + { + setPrimeStateTransition( PRIME_BC_CLEAR_STATE1 ); + state = PRIME_BC_CLEAR_STATE1; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handlePrimeBCClearState1 function handles prime blood circuit clear + * stage 1 of prime service. Runs BP at the 150 mL/min, cycling the arterial + * pinch valve every 5s to build venous pressure and clear residual air, + * while maintaining the air trap level, until 20s elapses. + * @details \b Inputs: stateEntryTimerCtr, pinchStartTime + * @details \b Outputs: stateEntryTimerCtr, pinchStartTime + * @return next Prime state + *************************************************************************/ +static TD_PRIME_STATE_T handlePrimeBCClearState1( void ) +{ + TD_PRIME_STATE_T state = PRIME_BC_CLEAR_STATE1; + + // Max time for this state - 20 secs + if ( TRUE == didTimeout( stateEntryTimerCtr, SLOW_PURGE_INTERVAL ) ) + { + setPrimeStateTransition ( PRIME_BC_CLEAR_STATE2 ); + state = PRIME_BC_CLEAR_STATE2; + } + // Check pressure on each pinch + else if ( VALVE_POSITION_C_CLOSE == getValvePosition( H1_VALV ) ) + { + if ( getFilteredVenousPressure() >= TARGET_VEN_PRES_LIMIT_MMHG ) + { + setValvePosition( H1_VALV, VALVE_POSITION_B_OPEN ); + setBloodPumpTargetFlowRate( INITIAL_SET_BLOOD_FLOW_RATE, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + pinchStartTime = getMSTimerCount(); + } + } + //Check if airtrap is filling + else if ( TRUE == isAirTrapControlling() ) + { + if ( AIR_TRAP_LEVEL_FLUID == getLevelSensorState( H17_LEVL ) ) + { + endAirTrapControl(); + stateEntryTimerCtr = getMSTimerCount(); + pinchStartTime = getMSTimerCount(); + } + } + // Air trap refill + else if ( AIR_TRAP_LEVEL_AIR == getLevelSensorState( H17_LEVL ) ) + { + startAirTrapControl(); + } + // 5 secs pinch time check + else if ( TRUE == didTimeout( pinchStartTime, PINCH_INTERVAL_MS ) ) + { + setValvePosition( H1_VALV, VALVE_POSITION_C_CLOSE ); + setBloodPumpTargetFlowRate( INITIAL_SET_BLOOD_FLOW_RATE, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + } + else + { + // No action required, continue for 5 secs + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handlePrimeBCClearState2 function handles prime blood circuit clear + * stage 2 of prime service. Runs BP at maximum rate for a fixed 20s, + * maintaining air trap level, to clear residual air pockets. + * @details \b Inputs: stateEntryTimerCtr + * @details \b Outputs: stateEntryTimerCtr, pinchStartTime + * @return next Prime state + *************************************************************************/ +static TD_PRIME_STATE_T handlePrimeBCClearState2( void ) +{ + TD_PRIME_STATE_T state = PRIME_BC_CLEAR_STATE2; + + // Max time for this state - 20 secs + if ( TRUE == didTimeout( stateEntryTimerCtr, SLOW_PURGE_INTERVAL ) ) + { + setPrimeStateTransition( PRIME_BC_CLEAR_STATE3 ); + state = PRIME_BC_CLEAR_STATE3; + } + //Check if airtrap is filling + else if ( TRUE == isAirTrapControlling() ) + { + if ( AIR_TRAP_LEVEL_FLUID == getLevelSensorState( H17_LEVL ) ) + { + endAirTrapControl(); + stateEntryTimerCtr = getMSTimerCount(); + pinchStartTime = getMSTimerCount(); + } + } + // Air trap refill + else if ( AIR_TRAP_LEVEL_AIR == getLevelSensorState( H17_LEVL ) ) + { + startAirTrapControl(); + } + else + { + // No action required, continue. + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handlePrimeBCClearState3 function handles prime blood circuit clear + * stage 3 of prime service. Runs BP at 400 mL/min, cycling the arterial + * pinch valve to build venous pressure while maintaining air trap level, until 20s elapses. + * @details \b Inputs: stateEntryTimerCtr, pinchStartTime + * @details \b Outputs: stateEntryTimerCtr, pinchStartTime + * @return next Prime state + *************************************************************************/ +static TD_PRIME_STATE_T handlePrimeBCClearState3( void ) +{ + TD_PRIME_STATE_T state = PRIME_BC_CLEAR_STATE3; + + // Max time for this state - 20 secs + if ( TRUE == didTimeout( stateEntryTimerCtr, SLOW_PURGE_INTERVAL ) ) + { + setPrimeStateTransition( PRIME_WAIT_FOR_DIALYSATE_READY_STATE ); + state = PRIME_WAIT_FOR_DIALYSATE_READY_STATE; + } + // Check pressure on each pinch + else if ( VALVE_POSITION_C_CLOSE == getValvePosition( H1_VALV ) ) + { + if ( getFilteredVenousPressure() >= TARGET_VEN_PRES_LIMIT_MMHG ) + { + setValvePosition( H1_VALV, VALVE_POSITION_B_OPEN ); + setBloodPumpTargetFlowRate( SALINE_PURGE_SET_BLOOD_FLOW_RATE, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + pinchStartTime = getMSTimerCount(); + } + } + //Check if airtrap is filling + else if ( TRUE == isAirTrapControlling() ) + { + if ( AIR_TRAP_LEVEL_FLUID == getLevelSensorState( H17_LEVL ) ) + { + endAirTrapControl(); + stateEntryTimerCtr = getMSTimerCount(); + pinchStartTime = getMSTimerCount(); + } + } + // Air trap refill + else if ( AIR_TRAP_LEVEL_AIR == getLevelSensorState( H17_LEVL ) ) + { + startAirTrapControl(); + } + // 5 secs pinch time check + else if ( TRUE == didTimeout( pinchStartTime, PINCH_INTERVAL_MS ) ) + { + setValvePosition( H1_VALV, VALVE_POSITION_C_CLOSE ); + setBloodPumpTargetFlowRate( SALINE_PURGE_SET_BLOOD_FLOW_RATE, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + } + else + { + // No action required, continue for 5 secs + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handlePrimeWaitForDialysateReadyState function handles the Wait + * for dilaysate circuit of prime service. Waits for the DD until it is + * ready to deliver dialysate before starting dialysate circuit prime. + * @details \b Inputs: none + * @details \b Outputs: none + * @return next Prime state + *************************************************************************/ +static TD_PRIME_STATE_T handlePrimeWaitForDialysateReadyState( void ) +{ + TD_PRIME_STATE_T state = PRIME_WAIT_FOR_DIALYSATE_READY_STATE; + + if ( TRUE == getDialysateGoodToDeliverStatus() ) + { + setPrimeStateTransition( PRIME_DC_INITIAL_DIALYSATE_STATE ); + state = PRIME_DC_INITIAL_DIALYSATE_STATE; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handlePrimeDCInitialDialyzerState function handles dialysate circuit + * initial dialyzer state of prime prime service. Passes dialysate through + * dialyzer. + * @details \b Inputs: stateEntryTimerCtr, dcInitialPrimeInterval + * @details \b Outputs: none + * @return next Prime state + *************************************************************************/ +static TD_PRIME_STATE_T handlePrimeDCInitialDialyzerState( void ) +{ + TD_PRIME_STATE_T state = PRIME_DC_INITIAL_DIALYSATE_STATE; + F32 venPres = getFilteredVenousPressure(); + + if ( fabs( venPres ) > DC_PRIME_VEN_PRES_LIMIT_MMHG ) + { + setPrimeStateTransition( PRIME_DC_DEPRESSURIZE_STATE ); + state = PRIME_DC_DEPRESSURIZE_STATE; + } + else if ( DD_GEND_DIALYSATE_DELIVERY_STATE == getCurrentGenDState() ) + { + if ( TRUE == didTimeout( stateEntryTimerCtr, dcInitialPrimeInterval ) ) + { + cmdBypassDialyzer( TRUE ); + startAirTrapControl(); + state = PRIME_WAIT_FOR_AIR_TRAP_FILL_STATE; + } + } + else + { + // No action required. + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handlePrimeDCDepressurizeState function handles dialysate circuit + * depressurize state of prime service. Waits for pressure to return + * within the resume limit, alarming if stabilization does not occur + * within 5s. + * @details \b Alarm: ALARM_ID_TD_VENOUS_PRESSURE_HIGH if venous pressure does + * not stabilize within 5s. + * @details \b Inputs: dcDepressurizeElapsedMs + * @details \b Outputs: dcDepressurizeElapsedMs + * @return next Prime state + *************************************************************************/ +static TD_PRIME_STATE_T handlePrimeDCDepressurizeState( void ) +{ + TD_PRIME_STATE_T state = PRIME_DC_DEPRESSURIZE_STATE; + F32 venPres = getFilteredVenousPressure(); + + if ( fabs( venPres ) <= DC_PRIME_RESUME_VEN_PRES_LIMIT_MMHG ) + { + //cmdDDChamberHValveOpen( FALSE ); + setPrimeStateTransition ( PRIME_DC_INITIAL_DIALYSATE_STATE ); + state = PRIME_DC_INITIAL_DIALYSATE_STATE; + } + else if ( ++dcDepressurizeElapsedMs >= VEN_PRES_STABILIZATION_TIMEOUT_INTERVAL_MS ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_TD_VENOUS_PRESSURE_HIGH, (U32)venPres ); + } +// else if ( DD_GEND_SPENT_CHAMBER_VENT_OPEN_STATE == getCurrentGenDState() ) +// { +// +// if ( ++dcDepressurizeElapsedMs >= VEN_PRES_STABILIZATION_TIMEOUT_INTERVAL_MS ) +// { +// SET_ALARM_WITH_1_U32_DATA( ALARM_ID_TD_VENOUS_PRESSURE_HIGH, (U32)venPres ); +// } +// } + else + { + // No action required. + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleWaitForAirTrapFillState function waits for the air trap to + * fill to the upper level sensor (H16) before starting the blood pump + * reversal sequence. + * @details \b Inputs: none + * @details \b Outputs: none + * @return next Prime state + *************************************************************************/ +static TD_PRIME_STATE_T handleWaitForAirTrapFillState( void ) +{ + TD_PRIME_STATE_T state = PRIME_WAIT_FOR_AIR_TRAP_FILL_STATE; + + if ( AIR_TRAP_LEVEL_FLUID == getLevelSensorState( H16_LEVL ) ) + { + setPrimeStateTransition( PRIME_BC2_FORWARD_RECIRC_STATE ); + state = PRIME_BC2_FORWARD_RECIRC_STATE; + } + return state; +} + +/*********************************************************************//** + * @brief + * The handleBC2ForwardRecircState function handles the prime forward recirc + * state of prime service. Runs BP forward at maximum rate, cycling the + * venous pinch valve against pressure limits for the first 15s, then holding + * it open for 10s. + * @details \b Inputs: stateEntryTimerCtr, revRecircVisited + * @details \b Outputs: none + * @return next Prime state + *************************************************************************/ +static TD_PRIME_STATE_T handleBC2ForwardRecircState( void ) +{ + TD_PRIME_STATE_T state = PRIME_BC2_FORWARD_RECIRC_STATE; + F32 venPres = getFilteredVenousPressure(); + + if ( TRUE == didTimeout( stateEntryTimerCtr, BC2_FWD_RECIRC_INTERVAL ) ) + { + if ( FALSE == revRecircVisited ) + { + setPrimeStateTransition( PRIME_BC2_PAUSE_TO_ROTATE_OPP_DIR_STATE ); + state = PRIME_BC2_PAUSE_TO_ROTATE_OPP_DIR_STATE; + } + else + { + setPrimeStateTransition( PRIME_DC_DISCARD_AND_REVERSE_PRIME_STATE ); + state = PRIME_DC_DISCARD_AND_REVERSE_PRIME_STATE; + } + } + //First 15 sec + else if ( FALSE == didTimeout( stateEntryTimerCtr, BC2_PINCH_CYCLE_INTERVAL ) ) + { + if ( venPres >= BC2_MAX_VEN_PRES_LIMIT_MMHG ) + { + setValvePosition( H19_VALV, VALVE_POSITION_B_OPEN ); + } + else if ( venPres <= BC2_STABLE_VEN_PRES_LIMIT_MMHG ) + { + setValvePosition( H19_VALV, VALVE_POSITION_C_CLOSE ); + } + else + { + // No action required + } + } + // Remaining 10 sec, open + else + { + setValvePosition( H19_VALV, VALVE_POSITION_B_OPEN ); + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleBC2PauseToRotateOppDirState function handles the Pause to rotate + * opp direction state of prime service. Pauses 1s between forward and + * reverse passes of the blood pump reversal sequence. + * @details \b Inputs: stateEntryTimerCtr, revRecircVisited + * @details \b Outputs: none + * @return next Prime state + *************************************************************************/ +static TD_PRIME_STATE_T handleBC2PauseToRotateOppDirState( void ) +{ + TD_PRIME_STATE_T state = PRIME_BC2_PAUSE_TO_ROTATE_OPP_DIR_STATE; + + if ( TRUE == didTimeout( stateEntryTimerCtr, BC2_PAUSE_INTERVAL ) ) + { + if ( FALSE == revRecircVisited ) + { + setPrimeStateTransition( PRIME_BC2_REVERSE_RECIRC_STATE ); + state = PRIME_BC2_REVERSE_RECIRC_STATE; + } + else + { + setPrimeStateTransition( PRIME_BC2_FORWARD_RECIRC_STATE ); + state = PRIME_BC2_FORWARD_RECIRC_STATE; + } + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleBC2ReverserRecircState function handles the prime forward recirc + * state of prime service. Rotates BP in reverse at maximum rate for 10s + * before pausing. + * @details \b Inputs: stateEntryTimerCtr + * @details \b Outputs: none + * @return next Prime state + *************************************************************************/ +static TD_PRIME_STATE_T handleBC2ReverserRecircState( void ) +{ + TD_PRIME_STATE_T state = PRIME_BC2_REVERSE_RECIRC_STATE; + + if ( TRUE == didTimeout( stateEntryTimerCtr, BC2_REV_RECIRC_INTERVAL ) ) + { + setPrimeStateTransition( PRIME_BC2_PAUSE_TO_ROTATE_OPP_DIR_STATE ); + state = PRIME_BC2_PAUSE_TO_ROTATE_OPP_DIR_STATE; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handlePrimeDiscardAndReversePrimeState function handles the priming + * fluid discard and dialyzer reverse prime state of prime service. Waits + * for DD to confirm prime fluid discard is active, then runs for the + * greater of the discard or reverse prime duration. + * @details \b Inputs: stateEntryTimerCtr, dcDiscardAndRevPrimeInterval + * @details \b Outputs: none + * @return next Prime state + *************************************************************************/ +static TD_PRIME_STATE_T handlePrimeDiscardAndReversePrimeState( void ) +{ + TD_PRIME_STATE_T state = PRIME_DC_DISCARD_AND_REVERSE_PRIME_STATE; + + if ( DD_GEND_PRIME_FLUID_DISCARD_STATE == getCurrentGenDState() ) + { + if ( TRUE == didTimeout( stateEntryTimerCtr, dcInitialPrimeInterval ) ) + { + //cmdChangeQuf( 0.0F ); + setPrimeStateTransition( PRIME_COMPLETE_STATE ); + state = PRIME_COMPLETE_STATE; + } + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handlePrimePauseState function handles the prime pause state of prime + * service. + * @details \b Inputs: prevPrimeState + * @details \b Outputs: primeStartTime + * @return next Prime state + *************************************************************************/ +static TD_PRIME_STATE_T handlePrimePauseState( void ) +{ + TD_PRIME_STATE_T state = PRIME_PAUSE_STATE; + + if ( TRUE == signalPreTxResumeRequest() ) + { + setPrimeStateTransition( prevPrimeState ); + state = prevPrimeState; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The publishPrimeData function broadcasts prime data during priming. + * @details \b Message \b Sent: MSG_ID_TD_PRIME_PROGRESS_DATA + * @details \b Inputs: primePublishTimerCtr, currentPrimeState, primeStartTime, + * primeElapsedAtPauseMs, primePauseStartTime + * @details \b Outputs: primePublishTimerCtr + * @return none + *************************************************************************/ +static void publishPrimeData( void ) +{ + if ( ++primePublishTimerCtr >= PRIME_DATA_PUB_INTERVAL ) + { + PRIMING_DATA_PAYLOAD_T data; + U32 elapsedMs; + U32 remainingMs; + U32 pauseElapsedMs; + U32 pauseRemainingMs = 0; + + if ( PRIME_PAUSE_STATE == currentPrimeState ) + { + elapsedMs = primeElapsedAtPauseMs; + pauseElapsedMs = calcTimeSince( primePauseStartTime ); + pauseRemainingMs = ( pauseElapsedMs < PRIME_PAUSE_TIMEOUT_INTERVAL ) ? + ( PRIME_PAUSE_TIMEOUT_INTERVAL - pauseElapsedMs ) : 0; + } + else + { + elapsedMs = calcTimeSince( primeStartTime ); + } + + remainingMs = ( elapsedMs < PRIME_TOTAL_DURATION_INTERVAL ) ? + ( PRIME_TOTAL_DURATION_INTERVAL - elapsedMs ) : 0; + + data.primeState = (U32)currentPrimeState; + data.totalDurationSec = PRIME_TOTAL_DURATION_INTERVAL / MS_PER_SECOND; + data.countDownSec = remainingMs / MS_PER_SECOND; + data.pauseCountdownSec = pauseRemainingMs / MS_PER_SECOND; + + broadcastData( MSG_ID_TD_PRIME_PROGRESS_DATA, COMM_BUFFER_OUT_CAN_TD_BROADCAST, (U08*)&data, sizeof( PRIMING_DATA_PAYLOAD_T ) ); + primePublishTimerCtr = 0; + } +} + +/**@}*/ Index: firmware/App/Services/StateServices/Prime.h =================================================================== diff -u --- firmware/App/Services/StateServices/Prime.h (revision 0) +++ firmware/App/Services/StateServices/Prime.h (revision ee84e20f729b0aace2b1728c16de9a89e06eee38) @@ -0,0 +1,54 @@ +/************************************************************************** +* +* Copyright (c) 2026-2026 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 Prime.h +* +* @author (last) Praneeth Bunne +* @date (last) 16-Jul-2026 +* +* @author (original) Praneeth Bunne +* @date (original) 16-Jul-2026 +* +***************************************************************************/ + +#ifndef __PRIME_H__ +#define __PRIME_H__ + +#include "TDCommon.h" +#include "TDDefs.h" + +/** + * @defgroup Prime Prime + * @brief Prime provides blood circuit and dialysate circuit priming + * service to Pre-Treatment and Treatment modes. + * + * @addtogroup Prime + * @{ + */ + +// ********** public definitions ********** + +/// Payload record structure for a priming status data broadcast message. +typedef struct +{ + U32 primeState; ///< Current Prime state + U32 totalDurationSec; ///< Total allowed prime duration + U32 countDownSec; ///< Remaining time before total duration + U32 pauseCountdownSec; ///< Remaining time before pause timeout +} PRIMING_DATA_PAYLOAD_T; + +// ********** public function prototypes ********** + +void initPrime( void ); // Initialize prime sub-mode (of pre-treatment mode). +void execPrime( void ); // Execute the prime state machine. +TD_PRIME_STATE_T getCurrentPrimeState( void ); // Get the current state of the prime state machine. + +void signalResumePrime( void ); // User has requested to resume prime + +/**@}*/ + +#endif