Index: firmware/App/Modes/Prime.c =================================================================== diff -u -r11d3b6b7d4ae9f5822998abd4f94792f2d9e1714 -r76a5589f5a6d68bcb35379c9977a50a57056b299 --- firmware/App/Modes/Prime.c (.../Prime.c) (revision 11d3b6b7d4ae9f5822998abd4f94792f2d9e1714) +++ firmware/App/Modes/Prime.c (.../Prime.c) (revision 76a5589f5a6d68bcb35379c9977a50a57056b299) @@ -21,6 +21,7 @@ #include "DialInFlow.h" #include "DialOutFlow.h" #include "DGInterface.h" +#include "ModeTreatmentParams.h" #include "Prime.h" #include "SelfTests.h" #include "SystemCommMessages.h" @@ -42,22 +43,20 @@ #define BLOOD_PUMP_SLOW_FLOW_RATE_PURGE_AIR_ML_MIN 150 ///< Blood pump slow flow rate after fluid reach lower level of air trap sensor. #define BLOOD_PUMP_SALINE_FLOW_RATE_PURGE_AIR_ML_MIN 200 ///< Blood pump very slow flow rate during prime saline dialyzer state #define BLOOD_PUMP_FLOW_RATE_CIRC_BLOOD_CIRCUIT_ML_MIN 300 ///< Blood pump flow rate during prime recirculate blood circuit state. +#define BLOOD_PUMP_FLOW_RATE_SALINE_DIALYZER_ML_MIN 300 ///< Blood pump flow rate during prime the saline dialyzer dialysate state. +#define DIALYSATE_DIALYZER_TUBE_VOLUME_ML 115 ///< This total tube volume is used to calculate the Dpi & Dpo time out in the dialysate dialyzer state. +#define DIALYSATE_DIALYZER_BYPASS_TUBE_VOLUME_ML 30 ///< This volume is used to calculate the DPi pump time out in the dialyzer bypass state + #define DIALYSATE_PUMP_PRIME_FLOW_RATE_ML_MIN 300 ///< Dialysate pump flow rate during priming fluid path. #define LOAD_CELL_VOLUME_NOISE_TOLERANCE 5.00 ///< Allow 5 mL tolerance on load cell readings. -#define PRIME_SALINE_DIALYZER_STOP_WEIGHT 50.0 ///< Load cell readings of 10 grams ( 10 mL ) used in prime saline dialyzer state - ///< Currently, we use 50.0 mL for testing. Remove this comment and replace 50.0 with 10.0 before merge to develop branch + #define NO_AIR_DETECTED_COUNT ( 20 * MS_PER_SECOND ) ///< No air detected time period count. #define PURGE_AIR_TIME_OUT_COUNT ( 60 * MS_PER_SECOND ) ///< Time period count for purge air time out. #define LOAD_CELL_STEADY_VOLUME_SAMPLING_TIME ( 1 * MS_PER_SECOND ) ///< Time load cell reading steady state detection sampling time in seconds. -#define PRIME_DIALYSATE_DIALYZER_TIME_LIMIT ( 120 * MS_PER_SECOND ) ///< Time limit for priming dialysate dialyzer circuit. -#define PRIME_DIALYSATE_BYPASS_TIME_LIMIT ( 120 * MS_PER_SECOND ) ///< Time limit for priming dialysate bypass circuit. -#define PRIME_SALINE_DIALYZER_TIME_LIMIT ( 300 * MS_PER_SECOND ) ///< Five minutes time limit for priming saline dialyzer path. -#define CIRC_BUF_SIZE 10 ///< Size of the circular buffer. Note: the size is not 2^N where N = 1, 2 , 3, 4, 5 ... -#define MAX_BUF_INDEX ( CIRC_BUF_SIZE - 1 ) ///< Use to calculate write index of the circular buffer. -#define PRIME_DIALYZER_BYPASS_EXPECTED_VOLUME 1000.0 ///< Prime dialysate dialyzer bypass state expected steady state volume in mL. -#define PRIME_DIALYZER_EXPECTED_VOLUME 1200.0 ///< Prime dialysate dialyzer state expected steady state volume in mL. -#define PRIME_EXPECTED_VOLUME_TOLERANCE 50.0 ///< Prime expected steady state volume tolerance in mL. +//#define PRIME_DIALYSATE_DIALYZER_TIME_LIMIT ( 120 * MS_PER_SECOND ) ///< Time limit for priming dialysate dialyzer circuit. +#define PRIME_DIALYSATE_BYPASS_TIME_LIMIT ( 6 * MS_PER_SECOND ) ///< Time limit for priming dialysate bypass circuit. +//#define PRIME_SALINE_DIALYZER_TIME_LIMIT ( 120 * MS_PER_SECOND ) ///< Two minutes time limit for priming saline dialyzer path. /// States of the treatment reservoir management state machine. typedef enum PrimeReservoirMgmt_States @@ -74,8 +73,24 @@ NUM_OF_PRIME_RESERVOIR_MGMT_STATES ///< Number of prime reservoir mgmt. states. } PRIME_RESERVOIR_MGMT_STATE_T; +typedef struct { + U32 bloodVolume; ///< Blood volume of the dialyzer in mL. + U32 dialysateVolume; ///< Dialysate volume of the dialyzer in mL. +} DIALYZER_VOLUME_DATA_T; + // ********** private data ********** +static DIALYZER_VOLUME_DATA_T dialyzerVolumeTable[ ] = { { 82, 170 }, ///< Dialyzer volume table in mL of five types of dialyzer + { 100, 200 }, + { 120, 257 }, + { 87, 233 }, + { 102, 280 } }; + +static U32 primeSalineDialyzerTimeLimit; ///< Time limit for priming saline dialyzer air valve path. +static U32 primeDialysateDialyzerTimeLimit; ///< Time limit for priming dialysate dialyzer path. +static U32 primeSalineDialyzerDialysateTimeLimit; ///< Time limit for priming saline dialyzer dialysate path. +static U32 primeDialysateBypassTimeLimit; ///< Time limit for priming dialysate bypass path. + static HD_PRE_TREATMENT_PRIME_STATE_T currentPrimeState; ///< Current state of the prime sub-mode state machine. static HD_PRE_TREATMENT_PRIME_STATE_T previousPrimeState; ///< Previous state of the prime sub-mode, to use when resuming from pause. static PRIME_RESERVOIR_MGMT_STATE_T currentReservoirMgmtState; ///< Current reservoir management state. @@ -92,11 +107,11 @@ static U32 primeSalineDialyzerStartTime; ///< Starting time of priming saline dialyzer circuit. static U32 primeDialysateDialyzerStartTime; ///< Starting time of priming dialysate dialyzer circuit. static U32 primeDialysateBypassStartTime; ///< Starting time of priming dialysate bypass circuit. -static U32 primeSalineDializerInitialLoadCellReading; ///< Initial load cell reading in the prime saline dialyzer state. static U32 loadcellSteadyVolumeStartTime; ///< Load cell steady volume starting time. static BOOL runBloodCircuitPrimeAgain; ///< Flag indicates HD should run blood circuit prime once more time. -static F32 loadcellReadings[ CIRC_BUF_SIZE ]; ///< Storage for 10 seconds of load cell weight readings. -static U32 currentBufIndex; ///< Use to calculate the write and the read index of the circular buffer. +static F32 previousReservoirVolume; ///< Use to calculate the delta volume in steady state detection. +static F32 minimumReservoirVolume; ///< Minimum reservoir volume in mL. +static U32 steadyVolumeCount; ///< Use to keep track the number of dVolume/dt < Threshold // ********** private function prototypes ********** @@ -105,17 +120,19 @@ static void broadcastPrimingStatus( void ); static void purgeAirDialyzerBloodPumpControl( void ); static void purgeAirValvesBloodPumpControl( void ); +static F32 getDialyzerBloodVolume( void ); +static F32 getDialyzerDialysateVolume( void ); static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeWaitForUserStartState( void ); static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeSalineDialyzerSetupState( void ); static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeSalineDialyzerState( void ); static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeSalineSetupState( void ); static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimePurgeAirState( void ); static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeCircBloodCircuitState( void ); -static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeReservoirTwoFillCompleteState( void ); -static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeDialysateBypassState( void ); static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeReservoirOneFillCompleteState( void ); static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeDialysateDialyzerState( void ); +static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeReservoirTwoFillCompleteState( void ); +static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeDialysateBypassState( void ); static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeWetSelfTestsState( void ); static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimePause( void ); @@ -181,14 +198,6 @@ currentPrimeState = handlePrimeWaitForUserStartState(); break; - case HD_PRIME_SALINE_DIALYZER_SETUP_STATE: - currentPrimeState = handlePrimeSalineDialyzerSetupState(); - break; - - case HD_PRIME_SALINE_DIALYZER_STATE: - currentPrimeState = handlePrimeSalineDialyzerState(); - break; - case HD_PRIME_SALINE_SETUP_STATE: currentPrimeState = handlePrimeSalineSetupState(); break; @@ -205,16 +214,24 @@ currentPrimeState = handlePrimeReservoirOneFillCompleteState(); break; - case HD_PRIME_DIALYSATE_BYPASS_STATE: - currentPrimeState = handlePrimeDialysateBypassState(); + case HD_PRIME_DIALYSATE_DIALYZER_STATE: + currentPrimeState = handlePrimeDialysateDialyzerState(); break; + case HD_PRIME_SALINE_DIALYZER_SETUP_STATE: + currentPrimeState = handlePrimeSalineDialyzerSetupState(); + break; + + case HD_PRIME_SALINE_DIALYZER_STATE: + currentPrimeState = handlePrimeSalineDialyzerState(); + break; + case HD_PRIME_RESERVOIR_TWO_FILL_COMPLETE_STATE: currentPrimeState = handlePrimeReservoirTwoFillCompleteState(); break; - case HD_PRIME_DIALYSATE_DIALYZER_STATE: - currentPrimeState = handlePrimeDialysateDialyzerState(); + case HD_PRIME_DIALYSATE_BYPASS_STATE: + currentPrimeState = handlePrimeDialysateBypassState(); break; case HD_PRIME_WET_SELF_TESTS_STATE: @@ -254,6 +271,34 @@ /*********************************************************************//** * @brief + * The getDialyzerBloodVolume function returns the blood volume of + * the selected dialyzer. + * @details Inputs: dialyzer volume table + * @details Outputs: none + * @return blood volume capacity of the dialyzer in mL + *************************************************************************/ +F32 getDialyzerBloodVolume( void ) +{ + U32 dialyzerType = getTreatmentParameterU32( TREATMENT_PARAM_DIALYZER_TYPE ); + return dialyzerVolumeTable[ dialyzerType ].bloodVolume; +} + +/*********************************************************************//** + * @brief + * The getDialyzerDialysateVolume function returns the dialysate volume + * of the selected dialyzer. + * @details Inputs: dialyzer volume table + * @details Outputs: none + * @return dialysate volume capacity of the dialyzer in mL + *************************************************************************/ +F32 getDialyzerDialysateVolume( void ) +{ + U32 dialyzerType = getTreatmentParameterU32( TREATMENT_PARAM_DIALYZER_TYPE ); + return dialyzerVolumeTable[ dialyzerType ].dialysateVolume; +} + +/*********************************************************************//** + * @brief * The signalStartPrime function signals the prime sub-mode the user requested * to start priming operation. * @details Inputs: none @@ -262,22 +307,14 @@ *************************************************************************/ void signalStartPrime( void ) { - BOOL accepted = TRUE; - REQUEST_REJECT_REASON_CODE_T rejReason = REQUEST_REJECT_REASON_NONE; + BOOL accepted = FALSE; + REQUEST_REJECT_REASON_CODE_T rejReason = REQUEST_REJECT_REASON_NOT_ALLOWED_IN_CURRENT_MODE; - if ( currentPrimeState != HD_PRIME_WAIT_FOR_USER_START_STATE ) + if ( HD_PRIME_WAIT_FOR_USER_START_STATE == currentPrimeState ) { - accepted = FALSE; - rejReason = REQUEST_REJECT_REASON_NOT_ALLOWED_IN_CURRENT_MODE; - } - else if ( getReservoirFillStatus( DG_RESERVOIR_1 ) != TRUE ) - { - accepted = FALSE; - rejReason = REQUEST_REJECT_REASON_RESERVOIR_ONE_IS_NOT_READY; - } - else - { primeStartRequested = TRUE; + accepted = TRUE; + rejReason = REQUEST_REJECT_REASON_NONE; } sendStartPrimeCmdResponse( accepted, rejReason ); @@ -356,44 +393,44 @@ /*********************************************************************//** * @brief - * The purgeAirDialyzerBloodPumpControl function controls valves and blood pump - * to purge air by priming the saline dialyzer fluid path. + * The purgeAirValvesBloodPumpControl function controls valves and blood pump + * to purge air. * @details Inputs: none * @details Outputs: run blood pump, close VDI, VDO, VBA and VBV valves, open VBT valve * @return current state (sub-mode) *************************************************************************/ -static void purgeAirDialyzerBloodPumpControl( void ) +static void purgeAirValvesBloodPumpControl( void ) { - setValvePosition( VDI, VALVE_POSITION_A_INSERT_EJECT ); + setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); setValvePosition( VBA, VALVE_POSITION_C_CLOSE ); setValvePosition( VBV, VALVE_POSITION_C_CLOSE ); - setValveAirTrap( STATE_CLOSED ); + setValveAirTrap( STATE_OPEN ); signalDialOutPumpHardStop(); signalDialInPumpHardStop(); - setBloodPumpTargetFlowRate( BLOOD_PUMP_SALINE_FLOW_RATE_PURGE_AIR_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + setBloodPumpTargetFlowRate( BLOOD_PUMP_FAST_FLOW_RATE_PURGE_AIR_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); } /*********************************************************************//** * @brief - * The purgeAirValvesBloodPumpControl function controls valves and blood pump - * to purge air. + * The purgeAirDialyzerBloodPumpControl function controls valves and blood pump + * to purge air by priming the saline dialyzer fluid path. * @details Inputs: none * @details Outputs: run blood pump, close VDI, VDO, VBA and VBV valves, open VBT valve * @return current state (sub-mode) *************************************************************************/ -static void purgeAirValvesBloodPumpControl( void ) +static void purgeAirDialyzerBloodPumpControl( void ) { - setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); + setValvePosition( VDI, VALVE_POSITION_A_INSERT_EJECT ); setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); setValvePosition( VBA, VALVE_POSITION_C_CLOSE ); setValvePosition( VBV, VALVE_POSITION_C_CLOSE ); - setValveAirTrap( STATE_OPEN ); + setValveAirTrap( STATE_CLOSED ); signalDialOutPumpHardStop(); signalDialInPumpHardStop(); - setBloodPumpTargetFlowRate( BLOOD_PUMP_FAST_FLOW_RATE_PURGE_AIR_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + setBloodPumpTargetFlowRate( BLOOD_PUMP_SALINE_FLOW_RATE_PURGE_AIR_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); } /*********************************************************************//** @@ -417,75 +454,18 @@ if ( TRUE == primeStartRequested ) { primeStartRequested = FALSE; - state = HD_PRIME_SALINE_DIALYZER_SETUP_STATE; - } - - return state; -} - -/*********************************************************************//** - * @brief - * The handlePrimeSalineDialyzerSetupState function implements the setup - * prior to transition to the prime the saline dialyzer state. - * @details Inputs: primeStartReqReceived - * @details Outputs: primeSalineDializerInitialLoadCellReading, primeSalineDialyzerStartTime - * @return current state - *************************************************************************/ -static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeSalineDialyzerSetupState( void ) -{ - HD_PRE_TREATMENT_PRIME_STATE_T state = HD_PRIME_SALINE_DIALYZER_STATE; - - primeSalineDializerInitialLoadCellReading = getLoadCellWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); - primeSalineDialyzerStartTime = getMSTimerCount(); - purgeAirDialyzerBloodPumpControl(); - - if ( TRUE == doesAlarmStatusIndicateStop() ) - { - setupForPrimePause(); - state = HD_PRIME_PAUSE; - } - - return state; -} - -/*********************************************************************//** - * @brief - * The handlePrimeSalineDialyzerState function handles priming for saline - * dialyzer fluid path. - * @details Inputs: reservoir 2 filtered weight - * @details Outputs: primed saline dialyzer fluid path - * @return current state - *************************************************************************/ -static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeSalineDialyzerState( void ) -{ - HD_PRE_TREATMENT_PRIME_STATE_T state = HD_PRIME_SALINE_DIALYZER_STATE; - - F32 const loadcellWeight = getLoadCellWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); - - if ( (loadcellWeight - primeSalineDializerInitialLoadCellReading) > PRIME_SALINE_DIALYZER_STOP_WEIGHT ) - { state = HD_PRIME_SALINE_SETUP_STATE; } - if ( TRUE == didTimeout( primeSalineDialyzerStartTime, PRIME_SALINE_DIALYZER_TIME_LIMIT ) ) - { - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_PRIME_SALINE_DIALYZER_TIME_OUT, PRIME_SALINE_DIALYZER_TIME_LIMIT ); - } - - if ( TRUE == doesAlarmStatusIndicateStop() ) - { - setupForPrimePause(); - state = HD_PRIME_PAUSE; - } - return state; } /*********************************************************************//** * @brief - * The handlePrimeSalineSetupState function setups the Pre-Treatment Prime - * Saline Purge Air state. - * @details Inputs: state + * The handlePrimeSalineSetupState function prepares the entry conditions + * before start priming the saline dialyzer fluid path. + * priming. + * @details Inputs: primeStartReqReceived * @details Outputs: control valves to purge air * @return current state *************************************************************************/ @@ -602,28 +582,28 @@ if ( TRUE == hasDGCompletedReservoirSwitch() ) { - setDialInPumpTargetFlowRate( DIALYSATE_PUMP_PRIME_FLOW_RATE_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); - - setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); - setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); + setValvePosition( VDI, VALVE_POSITION_B_OPEN ); + setValvePosition( VDO, VALVE_POSITION_B_OPEN ); setValvePosition( VBA, VALVE_POSITION_C_CLOSE ); setValvePosition( VBV, VALVE_POSITION_C_CLOSE ); setValveAirTrap( STATE_CLOSED ); - U32 bufIndex; - for ( bufIndex = 0; bufIndex < CIRC_BUF_SIZE; bufIndex++ ) - { - loadcellReadings[ bufIndex ] = getLoadCellWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); - } + signalBloodPumpHardStop(); + setDialInPumpTargetFlowRate( DIALYSATE_PUMP_PRIME_FLOW_RATE_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + setDialOutPumpTargetRate( DIALYSATE_PUMP_PRIME_FLOW_RATE_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); - currentBufIndex = 0; // initialize circular buffer read/write index - primeDialysateBypassStartTime = getMSTimerCount(); + U32 dialyzerDialysateVolume = getDialyzerDialysateVolume(); + // Calculate the time out value that must passed prior to checking for the steady state volume in the reservoir + primeDialysateDialyzerTimeLimit = ( ( DIALYSATE_DIALYZER_TUBE_VOLUME_ML + dialyzerDialysateVolume ) * 60 ) / DIALYSATE_PUMP_PRIME_FLOW_RATE_ML_MIN; + previousReservoirVolume = 0.0;. + steadyVolumeCount = 0; loadcellSteadyVolumeStartTime = getMSTimerCount(); + primeDialysateDialyzerStartTime = getMSTimerCount(); #ifdef SKIP_PRIMING state = HD_PRIME_WET_SELF_TESTS_STATE; #else - state = HD_PRIME_DIALYSATE_BYPASS_STATE; + state = HD_PRIME_DIALYSATE_DIALYZER_STATE; #endif } } @@ -642,48 +622,85 @@ * The handlePrimeDialysateDialyzerState function handles priming for * dialysate dialyzer fluid path. * @details Inputs: reservoir 1 filtered weight - * @details Outputs: primed dialysate bypass fluid path + * @details Outputs: primed dialysate dialyzer fluid path * @return current state *************************************************************************/ -static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeDialysateBypassState( void ) +static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeDialysateDialyzerState( void ) { - HD_PRE_TREATMENT_PRIME_STATE_T state = HD_PRIME_DIALYSATE_BYPASS_STATE; + HD_PRE_TREATMENT_PRIME_STATE_T state = HD_PRIME_DIALYSATE_DIALYZER_STATE; - if ( TRUE == didTimeout( loadcellSteadyVolumeStartTime, LOAD_CELL_STEADY_VOLUME_SAMPLING_TIME ) ) + if ( TRUE == didTimeout( primeDialysateDialyzerStartTime, primeDialysateDialyzerTimeLimit ) ) { - F32 const currentLoadCellValue = getLoadCellWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); - F32 const previousLoadCellValue = loadcellReadings[ currentBufIndex % CIRC_BUF_SIZE ]; - F32 const loadcellDelta = fabs( currentLoadCellValue - previousLoadCellValue ); // delta of the current (now) and the previous (10 seconds ago) - loadcellReadings[ currentBufIndex % CIRC_BUF_SIZE ] = currentLoadCellValue; - currentBufIndex++; - - if ( ( loadcellDelta < LOAD_CELL_VOLUME_NOISE_TOLERANCE ) && - ( currentLoadCellValue < ( PRIME_DIALYZER_BYPASS_EXPECTED_VOLUME + PRIME_EXPECTED_VOLUME_TOLERANCE ) ) && // check the steady state volume of R1 - ( currentLoadCellValue > ( PRIME_DIALYZER_BYPASS_EXPECTED_VOLUME - PRIME_EXPECTED_VOLUME_TOLERANCE ) ) ) + // check for volume steady state every second after the DVi and DVo pumps have been on for primeDialysateDialyzerTimeLimit seconds + if ( TRUE == didTimeout( loadcellSteadyVolumeStartTime, LOAD_CELL_STEADY_VOLUME_SAMPLING_TIME ) ) { -#ifdef RUN_BLOOD_CIRCUIT_PRIME_AGAIN - if ( TRUE == runBloodCircuitPrimeAgain ) + F32 const currentReservoirVolume = getLoadCellWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); + F32 const deltaVolume = fabs( currentReservoirVolume - previousReservoirVolume ); + previousReservoirVolume = currentReservoirVolume; + + if ( deltaVolume < LOAD_CELL_VOLUME_NOISE_TOLERANCE ) { - runBloodCircuitPrimeAgain = FALSE; - state = HD_PRIME_SALINE_SETUP_STATE; + if ( ++steadyVolumeCount >= 10 ) + { +#ifdef RUN_BLOOD_CIRCUIT_PRIME_AGAIN + if ( TRUE == runBloodCircuitPrimeAgain ) + { + runBloodCircuitPrimeAgain = FALSE; + state = HD_PRIME_SALINE_SETUP_STATE; + } + else + { + state = HD_PRIME_RESERVOIR_TWO_FILL_COMPLETE_STATE; + } +#else + state = HD_PRIME_RESERVOIR_TWO_FILL_COMPLETE_STATE; +#endif + } } else { - state = HD_PRIME_RESERVOIR_TWO_FILL_COMPLETE_STATE; + steadyVolumeCount = 0; // required 10 seconds continuous steady volume to transition to next state } -#else - state = HD_PRIME_RESERVOIR_TWO_FILL_COMPLETE_STATE; -#endif + + loadcellSteadyVolumeStartTime = getMSTimerCount(); // re-armed the timer for the next dVolume/dt check } + } + else + { + loadcellSteadyVolumeStartTime = getMSTimerCount(); // re-init this timer if 120 sec has not expired + } - loadcellSteadyVolumeStartTime = getMSTimerCount(); // re-armed the timer for the next iteration + if ( TRUE == didTimeout( primeDialysateDialyzerStartTime, primeDialysateDialyzerTimeLimit + 55 ) ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_PRIME_DIALYSATE_DIALYZER_TIME_OUT, primeDialysateDialyzerTimeLimit ); } - if ( TRUE == didTimeout( primeDialysateBypassStartTime, PRIME_DIALYSATE_BYPASS_TIME_LIMIT ) ) + if ( TRUE == doesAlarmStatusIndicateStop() ) { - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_PRIME_DIALYSATE_BYPASS_TIME_OUT, PRIME_DIALYSATE_BYPASS_TIME_LIMIT ); + setupForPrimePause(); + state = HD_PRIME_PAUSE; } + return state; +} + +/*********************************************************************//** + * @brief + * The handlePrimeSalineDialyzerSetupState function implements the setup + * prior to transition to the prime the saline dialyzer state. + * @details Inputs: primeStartReqReceived + * @details Outputs: primeSalineDializerInitialLoadCellReading, primeSalineDialyzerStartTime + * @return current state + *************************************************************************/ +static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeSalineDialyzerSetupState( void ) +{ + HD_PRE_TREATMENT_PRIME_STATE_T state = HD_PRIME_SALINE_DIALYZER_STATE; + + U32 dialyzerBloodVolume = getDialyzerBloodVolume(); // get the dialyzer blood channel volume from the table + primeSalineDialyzerDialysateTimeLimit = ( dialyzerBloodVolume * 60 ) / BLOOD_PUMP_FLOW_RATE_SALINE_DIALYZER_ML_MIN; + primeSalineDialyzerStartTime = getMSTimerCount(); + purgeAirDialyzerBloodPumpControl(); + if ( TRUE == doesAlarmStatusIndicateStop() ) { setupForPrimePause(); @@ -695,8 +712,34 @@ /*********************************************************************//** * @brief + * The handlePrimeSalineDialyzerState function handles priming for saline + * dialyzer fluid path. + * @details Inputs: reservoir 2 filtered weight + * @details Outputs: primed saline dialyzer fluid path + * @return current state + *************************************************************************/ +static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeSalineDialyzerState( void ) +{ + HD_PRE_TREATMENT_PRIME_STATE_T state = HD_PRIME_SALINE_DIALYZER_STATE; + + if ( TRUE == didTimeout( primeSalineDialyzerStartTime, primeSalineDialyzerDialysateTimeLimit ) ) + { + state = HD_PRIME_RESERVOIR_TWO_FILL_COMPLETE_STATE; + } + + if ( TRUE == doesAlarmStatusIndicateStop() ) + { + setupForPrimePause(); + state = HD_PRIME_PAUSE; + } + + return state; +} + +/*********************************************************************//** + * @brief * The handlePrimeReservoirTwoFillCompleteState function waits for DG to finish - * filling reservoir 2 before moving to pre-treatment dialysate dialyzer state. + * filling reservoir 2 before moving to pre-treatment re-circulation. * @details Inputs: reservoirFilledStatus[] * @details Outputs: update valves and pumps configuration on state change * @return current state @@ -711,26 +754,21 @@ if ( TRUE == hasDGCompletedReservoirSwitch() ) { - setValvePosition( VDI, VALVE_POSITION_B_OPEN ); - setValvePosition( VDO, VALVE_POSITION_B_OPEN ); + signalBloodPumpHardStop(); + setDialInPumpTargetFlowRate( DIALYSATE_PUMP_PRIME_FLOW_RATE_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + + setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); + setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); setValvePosition( VBA, VALVE_POSITION_C_CLOSE ); setValvePosition( VBV, VALVE_POSITION_C_CLOSE ); setValveAirTrap( STATE_CLOSED ); - setDialInPumpTargetFlowRate( DIALYSATE_PUMP_PRIME_FLOW_RATE_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); - setDialOutPumpTargetRate( DIALYSATE_PUMP_PRIME_FLOW_RATE_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); - - U32 bufIndex; - for ( bufIndex = 0; bufIndex < CIRC_BUF_SIZE; bufIndex++ ) - { - loadcellReadings[ bufIndex ] = getLoadCellWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); - } - - currentBufIndex = 0; // initialize circular buffer read/write index - - loadcellSteadyVolumeStartTime = getMSTimerCount(); - primeDialysateDialyzerStartTime = getMSTimerCount(); - state = HD_PRIME_DIALYSATE_DIALYZER_STATE; + //previousReservoirVolume = 0.0; + minimumReservoirVolume = getLoadCellWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); + steadyVolumeCount = 0; + primeDialysateBypassStartTime = getMSTimerCount(); + loadcellSteadyVolumeStartTime = getMSTimerCount(); + state = HD_PRIME_DIALYSATE_BYPASS_STATE; } } @@ -745,39 +783,63 @@ /*********************************************************************//** * @brief - * The handlePrimeDialysateDialyzerState function handles priming for - * dialysate dialyzer fluid path. + * The handlePrimeDialysateBypassState function handles priming for + * dialysate dialyzer bypass fluid path. * @details Inputs: reservoir 2 filtered weight - * @details Outputs: primed dialysate dialyzer fluid path + * @details Outputs: primed dialysate bypass fluid path * @return current state *************************************************************************/ -static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeDialysateDialyzerState( void ) +static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeDialysateBypassState( void ) { - HD_PRE_TREATMENT_PRIME_STATE_T state = HD_PRIME_DIALYSATE_DIALYZER_STATE; + HD_PRE_TREATMENT_PRIME_STATE_T state = HD_PRIME_DIALYSATE_BYPASS_STATE; - if ( TRUE == didTimeout( loadcellSteadyVolumeStartTime, LOAD_CELL_STEADY_VOLUME_SAMPLING_TIME ) ) + if ( TRUE == didTimeout( primeDialysateBypassStartTime, PRIME_DIALYSATE_BYPASS_TIME_LIMIT ) ) { - F32 const currentLoadCellValue = getLoadCellWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); - F32 const previousLoadCellValue = loadcellReadings[ currentBufIndex % CIRC_BUF_SIZE ]; - F32 const loadcellDelta = fabs( currentLoadCellValue - previousLoadCellValue ); - loadcellReadings[ currentBufIndex % CIRC_BUF_SIZE ] = currentLoadCellValue; - currentBufIndex++; - - if ( ( loadcellDelta < LOAD_CELL_VOLUME_NOISE_TOLERANCE ) && - ( currentLoadCellValue < ( PRIME_DIALYZER_EXPECTED_VOLUME + PRIME_EXPECTED_VOLUME_TOLERANCE ) ) && // check the steady state volume of R2 - ( currentLoadCellValue > ( PRIME_DIALYZER_EXPECTED_VOLUME - PRIME_EXPECTED_VOLUME_TOLERANCE ) ) ) + // check for steady volume every second after the DVi pump has been on for PRIME_DIALYSATE_BYPASS_TIME_LIMIT seconds + if ( TRUE == didTimeout( loadcellSteadyVolumeStartTime, LOAD_CELL_STEADY_VOLUME_SAMPLING_TIME ) ) { - signalDialOutPumpHardStop(); - transitionToWetSelfTests(); - state = HD_PRIME_WET_SELF_TESTS_STATE; - } + F32 const currentReservoirVolume = getLoadCellWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); + // F32 const deltaVolume = fabs( currentReservoirVolume - previousRevervoirVolume ); + // previousRevervoirVolume = currentReservoirVolume; - loadcellSteadyVolumeStartTime = getMSTimerCount(); // re-armed the timer for the next iteration + if ( currentReservoirVolume > minimumReservoirVolume ) // this may not work!!! + { + if ( ++steadyVolumeCount >= 10 ) + { + transitionToWetSelfTests(); + state = HD_PRIME_WET_SELF_TESTS_STATE; + } + } + else + { + minimumReservoirVolume = currentReservoirVolume; + steadyVolumeCount = 0; + } + + loadcellSteadyVolumeStartTime = getMSTimerCount(); // re-armed the timer for the next 1 second iteration + + /* if ( deltaVolume < LOAD_CELL_VOLUME_NOISE_TOLERANCE ) + { + if ( ++steadyVolumeCount >= 10 ) + { + transitionToWetSelfTests(); + state = HD_PRIME_WET_SELF_TESTS_STATE; + } + } + else + { + steadyVolumeCount = 0; // required 10 seconds continuous steady volume to transition to next state + } */ + } } + else + { + loadcellSteadyVolumeStartTime = getMSTimerCount(); // re-init this timer if 120 sec has not expired + } - if ( TRUE == didTimeout( primeDialysateDialyzerStartTime, PRIME_DIALYSATE_DIALYZER_TIME_LIMIT ) ) + if ( TRUE == didTimeout( primeDialysateBypassStartTime, PRIME_DIALYSATE_BYPASS_TIME_LIMIT + 55 ) ) // allocate 55 seconds for the steady state logic to do its job before timing out { - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_PRIME_DIALYSATE_DIALYZER_TIME_OUT, PRIME_DIALYSATE_DIALYZER_TIME_LIMIT ); + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_PRIME_DIALYSATE_BYPASS_TIME_OUT, PRIME_DIALYSATE_BYPASS_TIME_LIMIT ); } if ( TRUE == doesAlarmStatusIndicateStop() ) @@ -848,16 +910,16 @@ state = HD_PRIME_SALINE_SETUP_STATE; break; - case HD_PRIME_SALINE_DIALYZER_SETUP_STATE: - case HD_PRIME_SALINE_DIALYZER_STATE: - state = HD_PRIME_SALINE_DIALYZER_SETUP_STATE; - break; - case HD_PRIME_RESERVOIR_ONE_FILL_COMPLETE_STATE: case HD_PRIME_DIALYSATE_DIALYZER_STATE: state = HD_PRIME_RESERVOIR_ONE_FILL_COMPLETE_STATE; break; + case HD_PRIME_SALINE_DIALYZER_SETUP_STATE: + case HD_PRIME_SALINE_DIALYZER_STATE: + state = HD_PRIME_SALINE_DIALYZER_SETUP_STATE; + break; + case HD_PRIME_RESERVOIR_TWO_FILL_COMPLETE_STATE: case HD_PRIME_DIALYSATE_BYPASS_STATE: state = HD_PRIME_RESERVOIR_TWO_FILL_COMPLETE_STATE;