Index: firmware/App/Modes/Prime.c =================================================================== diff -u -rc7ffa13e306681a647ad25513a89250c6918e6a4 -r8e2cfecc47bb3912078b29513f1717c1567f0071 --- firmware/App/Modes/Prime.c (.../Prime.c) (revision c7ffa13e306681a647ad25513a89250c6918e6a4) +++ firmware/App/Modes/Prime.c (.../Prime.c) (revision 8e2cfecc47bb3912078b29513f1717c1567f0071) @@ -18,9 +18,13 @@ #include "AirTrap.h" #include "AlarmMgmt.h" #include "BloodFlow.h" +#include "DialInFlow.h" +#include "DialOutFlow.h" #include "DGInterface.h" #include "Prime.h" +#include "SystemCommMessages.h" #include "TaskGeneral.h" +#include "Timers.h" #include "Valves.h" /** @@ -30,47 +34,80 @@ // ********** private definitions ********** +#define MAX_PRIME_TIME ( 10 * SEC_PER_MIN ) ///< Maximum prime time (in seconds). +#define PRIME_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the prime data is published on the CAN bus. + #define BLOOD_PUMP_FLOW_RATE_PURGE_AIR 100 ///< Blood pump flow rate during prime purge air state. #define BLOOD_PUMP_FLOW_RATE_CIRC_BLOOD_CIRCUIT 300 ///< Blood pump flow rate during prime recirculate blood circuit state. -#define NO_AIR_DETECTED_COUNT ( 10 * MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< No air detected time period count. -#define PURGE_AIR_TIME_OUT_COUNT ( 30 * MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Time period count for purge air time out. -#define PRIME_DRAIN_RESERVOIR_TO_VOLUME_ML 100 ///< Drain reservoir to this volume (in mL) during prime. -#define PRIME_FILL_RESERVOIR_TO_VOLUME_ML 1700 ///< Fill reservoir to this volume (in mL) during prime. +#define DIALYSATE_PUMP_PRIME_FLOW_RATE 300 ///< Dialysate pump flow rate during priming fluid path. +#define LOAD_CELL_VOLUME_NOISE_TOLERANCE 0.05 ///< Allow 5% tolerance on load cell readings. +#define PRIME_DRAIN_RESERVOIR_TO_VOLUME_ML 0 ///< Drain reservoir to this volume (in mL) during prime. + +// TODO: Determine the appropriate fill volume for each reservoir during prime state +#define PRIME_FILL_RESERVOIR_TO_VOLUME_ML ( FILL_RESERVOIR_TO_VOLUME_ML / 2 ) ///< Fill reservoir to this volume (in mL) during prime. + +#define NO_AIR_DETECTED_COUNT ( 10 * MS_PER_SECOND ) ///< No air detected time period count. +#define PURGE_AIR_TIME_OUT_COUNT ( 30 * MS_PER_SECOND ) ///< Time period count for purge air time out. +#define MIN_LOAD_CELL_STEADY_VOLUME_TIME ( 10 * MS_PER_SECOND ) ///< Minimum time load cell reading need to remain steady in ms. +#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. + /// States of the treatment reservoir management state machine. typedef enum PrimeReservoirMgmt_States { PRIME_RESERVOIR_MGMT_START_STATE = 0, ///< If DG not already in re-circ mode, try to get it there. PRIME_RESERVOIR_MGMT_FLUSH_DG_LINES_STATE, ///< In DG re-circ, wait for lines to flush - then start draining inactive reservoir. + PRIME_RESERVOIR_MGMT_WAIT_FOR_DRAIN_CMD_RESP, ///< After sending drain command, wait for DG to response back. PRIME_RESERVOIR_MGMT_DRAIN_STATE, ///< Wait for drain to complete. PRIME_RESERVOIR_MGMT_START_FILL_STATE, ///< Command DG to start filling reservoir. + PRIME_RESERVOIR_MGMT_WAIT_FOR_FILL_CMD_RESP, ///< After sending fill command, wait for DG to response back. PRIME_RESERVOIR_MGMT_FILL_STATE, ///< Wait for fill to complete. PRIME_RESERVOIR_MGMT_FILL_COMPLETE_STATE, ///< Reservoir fill has completed. + PRIME_RESERVOIR_MGMT_WAIT_RESERVOIR_TWO_INACTIVE, ///< Wait for reservoir 2 become inactive. NUM_OF_PRIME_RESERVOIR_MGMT_STATES ///< Number of prime reservoir mgmt. states. } PRIME_RESERVOIR_MGMT_STATE_T; // ********** private data ********** -static PRE_TREATMENT_PRIME_STATE_T currentPrimeState; ///< Current state of the prime sub-mode state machine. +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. -static BOOL isPrimeCompleted; ///< Status if prime sequence has been completed. +static U32 primeStartTime; ///< Starting time of priming (in ms). +static U32 primePauseStartTime; ///< Priming pause start time (in ms). +static U32 primeStatusBroadcastTimerCounter; ///< Prime status data broadcast timer counter used to schedule when to transmit data. + +static BOOL wetSelfTestsResult; ///< Result of wet self-tests. static BOOL primeStartReqReceived; ///< Flag to indicate if a request to start priming has been received. +static BOOL primePauseReqReceived; ///< Flag to indicate if a request to pause priming has been received. +static BOOL primeResumeReqReceived; ///< Flag to indicate if a request to resume priming has been received. static BOOL reservoirFilledStatus[ NUM_OF_DG_RESERVOIRS ]; ///< Flag to indicate if a reservoir has been filled. -static U32 noAirDetectedTimerCounter; ///< No air detected timer counter. -static U32 purgeAirTimeOutTimerCount; ///< Timer counter for purse air state time out. +static U32 noAirDetectedStartTime; ///< starting time when detecting no air. +static U32 purgeAirTimeOutStartTime; ///< Starting time for purge air state time out. +static U32 primeDialysateDialyzerStartTime; ///< Starting time of priming dialysate dialyzer circuit. +static U32 primeDialysateBypassStartTime; ///< Starting time of priming dialysate bypass circuit. +static U32 previousLoadCellReading; ///< Previous load cell reading. +static U32 loadcellSteadyVolumeStartTime; ///< Load cell steady volume starting time. + // ********** private function prototypes ********** -static void execPreTreatmentReservoirMgmt( void ); +static void handlePrimePauseRequest( void ); +static void broadcastPrimingStatus( void ); +static void execPrimeReservoirMgmt( void ); static void purgeAirValvesBloodPumpControl( void ); -static PRE_TREATMENT_PRIME_STATE_T handlePrimeSalineSetupState( void ); -static PRE_TREATMENT_PRIME_STATE_T handlePrimePurgeAirState( void ); -static PRE_TREATMENT_PRIME_STATE_T handlePrimeCircBloodCircuitState( void ); -static PRE_TREATMENT_PRIME_STATE_T handlePrimeReservoirOneFillCompleteState( void ); -static PRE_TREATMENT_PRIME_STATE_T handlePrimeDialysateDialyzerState( 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 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 ); /*********************************************************************//** * @brief @@ -90,20 +127,29 @@ * The transitionToPrime function prepares for transition to prime sub-mode. * This function will reset anything required before the start of priming sequence. * @details Inputs: none - * @details Outputs: currentPrimeState, isPrimeCompleted, primeStartReqReceived, reservoirFilledStatus[] + * @details Outputs: currentPrimeState, wetSelfTestsResult, primeStartReqReceived, reservoirFilledStatus[] * @return none *************************************************************************/ void transitionToPrime( void ) { - currentPrimeState = PRIME_START_STATE; + currentPrimeState = HD_PRIME_START_STATE; currentReservoirMgmtState = PRIME_RESERVOIR_MGMT_START_STATE; - isPrimeCompleted = FALSE; + + wetSelfTestsResult = FALSE; + primeStartTime = getMSTimerCount(); + primePauseStartTime = 0; + primeStatusBroadcastTimerCounter = 0; // TODO: set to false after integration with UI primeStartReqReceived = TRUE; - purgeAirTimeOutTimerCount = 0; + primeResumeReqReceived = FALSE; + primePauseReqReceived = FALSE; reservoirFilledStatus[ DG_RESERVOIR_1 ] = FALSE; reservoirFilledStatus[ DG_RESERVOIR_2 ] = FALSE; + + setAlarmUserActionEnabled( ALARM_USER_ACTION_RESUME, TRUE ); + setAlarmUserActionEnabled( ALARM_USER_ACTION_RINSEBACK, FALSE ); + setAlarmUserActionEnabled( ALARM_USER_ACTION_END_TREATMENT, FALSE ); } /*********************************************************************//** @@ -118,89 +164,209 @@ // execute prime sub-mode state machine switch ( currentPrimeState ) { - case PRIME_START_STATE: + case HD_PRIME_START_STATE: cmdSetDGActiveReservoir( DG_RESERVOIR_2 ); - currentPrimeState = PRIME_SALINE_SETUP_STATE; + currentPrimeState = HD_PRIME_SALINE_SETUP_STATE; break; - case PRIME_SALINE_SETUP_STATE: + case HD_PRIME_SALINE_SETUP_STATE: currentPrimeState = handlePrimeSalineSetupState(); break; - case PRIME_SALINE_PURGE_AIR_STATE: + case HD_PRIME_SALINE_PURGE_AIR_STATE: currentPrimeState = handlePrimePurgeAirState(); break; - case PRIME_SALINE_CIRC_BLOOD_CIRCUIT_STATE: + case HD_PRIME_SALINE_CIRC_BLOOD_CIRCUIT_STATE: currentPrimeState = handlePrimeCircBloodCircuitState(); break; - case PRIME_RESERVOIR_ONE_FILL_COMPLETE_STATE: + case HD_PRIME_RESERVOIR_ONE_FILL_COMPLETE_STATE: currentPrimeState = handlePrimeReservoirOneFillCompleteState(); break; - case PRIME_DIALYSATE_DIALYZER_STATE: + case HD_PRIME_DIALYSATE_DIALYZER_STATE: currentPrimeState = handlePrimeDialysateDialyzerState(); break; + case HD_PRIME_RESERVOIR_TWO_FILL_COMPLETE_STATE: + currentPrimeState = handlePrimeReservoirTwoFillCompleteState(); + break; + + case HD_PRIME_DIALYSATE_BYPASS_STATE: + currentPrimeState = handlePrimeDialysateBypassState(); + break; + + case HD_PRIME_WET_SELF_TESTS_STATE: + currentPrimeState = handlePrimeWetSelfTestsState(); + break; + + case HD_PRIME_PAUSE: + currentPrimeState = handlePrimePause(); + break; + default: - currentPrimeState = PRIME_START_STATE; + currentPrimeState = HD_PRIME_START_STATE; SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_PRE_TREATMENT_PRIME_INVALID_STATE, (U32)currentReservoirMgmtState ); break; } - execPreTreatmentReservoirMgmt(); + // Handle prime pause request + handlePrimePauseRequest(); + + // Broadcast priming data + broadcastPrimingStatus(); + + // Exec reservoir management for priming + execPrimeReservoirMgmt(); } /*********************************************************************//** * @brief - * The isPrimingPassed function returns the status of prime mode. + * The isWetSelfTestsPassed function returns the status of wet self-tests + * after priming. * @details Inputs: none * @details Outputs: none - * @return TRUE if prime has completed, otherwise FALSE + * @return TRUE if wet self-tests passed, otherwise FALSE *************************************************************************/ -BOOL isPrimingPassed( void ) +BOOL isWetSelfTestsPassed( void ) { - return isPrimeCompleted; + return wetSelfTestsResult; } /*********************************************************************//** * @brief - * The execPreTreatmentReservoirMgmt function executes the state machine for the - * reservoir management during pre-treatment mode. + * The signalAlarmActionToPrimeMode function executes the given alarm action + * as appropriate while in Prime Mode. + * @details Inputs: none + * @details Outputs: given alarm action executed + * @param action ID of alarm action to execute + * @return none + *************************************************************************/ +void signalAlarmActionToPrimeMode( ALARM_ACTION_T action ) +{ + switch ( action ) + { + case ALARM_ACTION_STOP: + primePauseReqReceived = TRUE; + break; + + case ALARM_ACTION_RESUME: + primeResumeReqReceived = TRUE; + break; + + case ALARM_ACTION_ACK: + // Nothing to be done here + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_PRIME_INVALID_ALARM_ACTION, (U32)action ) + break; + } +} + +/*********************************************************************//** + * @brief + * The handlePrimePauseRequest function handles prime pause request. + * @details Inputs: none + * @details Outputs: stop all pumps, switch to prime pause state. + * @return none + *************************************************************************/ +static void handlePrimePauseRequest( void ) +{ + if ( ( TRUE == primePauseReqReceived ) && ( HD_PRIME_PAUSE != currentPrimeState ) ) + { + signalDialOutPumpHardStop(); + signalDialInPumpHardStop(); + signalBloodPumpHardStop(); + + primePauseReqReceived = FALSE; + primePauseStartTime = getMSTimerCount(); + previousPrimeState = currentPrimeState; + currentPrimeState = HD_PRIME_PAUSE; + } +} + +/*********************************************************************//** + * @brief + * The broadcastPrimeTimeAndStatus function broadcasts prime status + * data during priming. + * @details Inputs: pre-treatment time and state data + * @details Outputs: pre-treatment time and state messages sent on interval + * @return none + *************************************************************************/ +static void broadcastPrimingStatus( void ) +{ + U32 const elapsedPrimeTimeInSecs = calcTimeSince( primeStartTime ) / MS_PER_SECOND; + + if ( elapsedPrimeTimeInSecs > MAX_PRIME_TIME ) + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_PRIME_OUT_OF_TIME, elapsedPrimeTimeInSecs, MAX_PRIME_TIME ); + } + + if ( ++primeStatusBroadcastTimerCounter >= PRIME_DATA_PUB_INTERVAL ) + { + PRIMING_DATA_PAYLOAD_T primeData; + primeData.currentPrimeState = currentPrimeState; + primeData.totalTime = MAX_PRIME_TIME; + primeData.remainingTime = MAX_PRIME_TIME - elapsedPrimeTimeInSecs; + + broadcastPrimeData( &primeData ); + primeStatusBroadcastTimerCounter = 0; + } +} + +/*********************************************************************//** + * @brief + * The execPrimeReservoirMgmt function executes the state machine for the + * reservoir management during pre-treatment prime sub-mode. * @details Inputs: currentReservoirMgmtState * @details Outputs: DG reservoirs' fills managed. * @return none *************************************************************************/ -static void execPreTreatmentReservoirMgmt( void ) +static void execPrimeReservoirMgmt( void ) { + DG_CMD_RESPONSE_T dgCmdResp; + + getDGCommandResponse( &dgCmdResp ); DG_OP_MODE_T dgOpMode = getDGOpMode(); U32 dgSubMode = getDGSubMode(); + // treatment reservoir mgmt. state machine switch ( currentReservoirMgmtState ) { case PRIME_RESERVOIR_MGMT_START_STATE: + currentReservoirMgmtState = PRIME_RESERVOIR_MGMT_FLUSH_DG_LINES_STATE; + break; + + case PRIME_RESERVOIR_MGMT_FLUSH_DG_LINES_STATE: if ( DG_MODE_CIRC == dgOpMode ) { - currentReservoirMgmtState = PRIME_RESERVOIR_MGMT_FLUSH_DG_LINES_STATE; + if ( DG_RECIRCULATE_MODE_STATE_RECIRC_WATER == dgSubMode ) + { + currentReservoirMgmtState = PRIME_RESERVOIR_MGMT_WAIT_FOR_DRAIN_CMD_RESP; + cmdStartDGDrain( PRIME_DRAIN_RESERVOIR_TO_VOLUME_ML, TRUE ); + } } else { - cmdStartDG(); + // TODO Handle when DG mode is out of sync } break; - case PRIME_RESERVOIR_MGMT_FLUSH_DG_LINES_STATE: - if ( ( DG_MODE_CIRC == dgOpMode ) && ( DG_RECIRCULATE_MODE_STATE_RECIRC_WATER == dgSubMode ) ) + case PRIME_RESERVOIR_MGMT_WAIT_FOR_DRAIN_CMD_RESP: + if ( DG_CMD_START_DRAIN == dgCmdResp.commandID ) { - cmdStartDGDrain( PRIME_DRAIN_RESERVOIR_TO_VOLUME_ML, TRUE ); + if ( FALSE == dgCmdResp.rejected ) + { + currentReservoirMgmtState = PRIME_RESERVOIR_MGMT_DRAIN_STATE; + } + else if ( DG_CMD_REQUEST_REJECT_REASON_INVALID_MODE == dgCmdResp.rejected ) + { + currentReservoirMgmtState = PRIME_RESERVOIR_MGMT_FLUSH_DG_LINES_STATE; + } } - - if ( DG_MODE_DRAI == dgOpMode ) - { - currentReservoirMgmtState = PRIME_RESERVOIR_MGMT_DRAIN_STATE; - } break; case PRIME_RESERVOIR_MGMT_DRAIN_STATE: @@ -213,11 +379,22 @@ case PRIME_RESERVOIR_MGMT_START_FILL_STATE: if ( ( DG_MODE_CIRC == dgOpMode ) && ( DG_RECIRCULATE_MODE_STATE_RECIRC_WATER == dgSubMode ) ) { + currentReservoirMgmtState = PRIME_RESERVOIR_MGMT_WAIT_FOR_FILL_CMD_RESP; cmdStartDGFill( PRIME_FILL_RESERVOIR_TO_VOLUME_ML ); } - if ( DG_MODE_FILL == dgOpMode ) + break; + + case PRIME_RESERVOIR_MGMT_WAIT_FOR_FILL_CMD_RESP: + if ( DG_CMD_START_FILL == dgCmdResp.commandID ) { - currentReservoirMgmtState = PRIME_RESERVOIR_MGMT_FILL_STATE; + if ( FALSE == dgCmdResp.rejected ) + { + currentReservoirMgmtState = PRIME_RESERVOIR_MGMT_FILL_STATE; + } + else if ( DG_CMD_REQUEST_REJECT_REASON_INVALID_MODE == dgCmdResp.rejected ) + { + currentReservoirMgmtState = PRIME_RESERVOIR_MGMT_START_FILL_STATE; + } } break; @@ -234,15 +411,23 @@ if ( FALSE == reservoirFilledStatus[ DG_RESERVOIR_1 ] ) { reservoirFilledStatus[ DG_RESERVOIR_1 ] = TRUE; - cmdSetDGActiveReservoir( DG_RESERVOIR_1 ); - currentReservoirMgmtState = PRIME_RESERVOIR_MGMT_FLUSH_DG_LINES_STATE; + currentReservoirMgmtState = PRIME_RESERVOIR_MGMT_WAIT_RESERVOIR_TWO_INACTIVE; } else if ( ( TRUE == reservoirFilledStatus[ DG_RESERVOIR_1 ] ) && ( FALSE == reservoirFilledStatus[ DG_RESERVOIR_2 ] ) ) { reservoirFilledStatus[ DG_RESERVOIR_2 ] = TRUE; } break; + case PRIME_RESERVOIR_MGMT_WAIT_RESERVOIR_TWO_INACTIVE: + currentReservoirMgmtState = PRIME_RESERVOIR_MGMT_WAIT_RESERVOIR_TWO_INACTIVE; + + if ( DG_RESERVOIR_2 == getDGInactiveReservoir() ) + { + currentReservoirMgmtState = PRIME_RESERVOIR_MGMT_FLUSH_DG_LINES_STATE; + } + break; + default: currentReservoirMgmtState = PRIME_RESERVOIR_MGMT_START_STATE; SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_PRIME_RESERVOIR_MGMT_INVALID_STATE, (U32)currentReservoirMgmtState ); @@ -277,15 +462,16 @@ * @details Outputs: control valves to purge air * @return current state *************************************************************************/ -static PRE_TREATMENT_PRIME_STATE_T handlePrimeSalineSetupState( void ) +static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeSalineSetupState( void ) { - PRE_TREATMENT_PRIME_STATE_T state = PRIME_SALINE_SETUP_STATE; + HD_PRE_TREATMENT_PRIME_STATE_T state = HD_PRIME_SALINE_SETUP_STATE; if ( TRUE == primeStartReqReceived ) { purgeAirValvesBloodPumpControl(); - purgeAirTimeOutTimerCount = 0; - state = PRIME_SALINE_PURGE_AIR_STATE; + purgeAirTimeOutStartTime = getMSTimerCount(); + primeStartReqReceived = FALSE; + state = HD_PRIME_SALINE_PURGE_AIR_STATE; } return state; @@ -299,11 +485,11 @@ * @details Outputs: runs blood pump, control valves to trap air * @return current state *************************************************************************/ -static PRE_TREATMENT_PRIME_STATE_T handlePrimePurgeAirState( void ) +static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimePurgeAirState( void ) { - PRE_TREATMENT_PRIME_STATE_T state = PRIME_SALINE_PURGE_AIR_STATE; + HD_PRE_TREATMENT_PRIME_STATE_T state = HD_PRIME_SALINE_PURGE_AIR_STATE; - if ( ++purgeAirTimeOutTimerCount > PURGE_AIR_TIME_OUT_COUNT ) + if ( TRUE == didTimeout( purgeAirTimeOutStartTime, PURGE_AIR_TIME_OUT_COUNT ) ) { activateAlarmNoData( ALARM_ID_HD_PRIME_PURGE_AIR_TIME_OUT ); } @@ -317,8 +503,8 @@ setValveAirTrap( STATE_CLOSED ); setBloodPumpTargetFlowRate( BLOOD_PUMP_FLOW_RATE_CIRC_BLOOD_CIRCUIT, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); - noAirDetectedTimerCounter = 0; - state = PRIME_SALINE_CIRC_BLOOD_CIRCUIT_STATE; + noAirDetectedStartTime = getMSTimerCount(); + state = HD_PRIME_SALINE_CIRC_BLOOD_CIRCUIT_STATE; } return state; @@ -333,21 +519,21 @@ * @details Outputs: stop blood pump, control valves to purge air * @return current state *************************************************************************/ -static PRE_TREATMENT_PRIME_STATE_T handlePrimeCircBloodCircuitState( void ) +static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeCircBloodCircuitState( void ) { - PRE_TREATMENT_PRIME_STATE_T state = PRIME_SALINE_CIRC_BLOOD_CIRCUIT_STATE; + HD_PRE_TREATMENT_PRIME_STATE_T state = HD_PRIME_SALINE_CIRC_BLOOD_CIRCUIT_STATE; if ( AIR_TRAP_LEVEL_AIR == getAirTrapLevel( AIR_TRAP_LEVEL_SENSOR_LOWER ) ) { purgeAirValvesBloodPumpControl(); - purgeAirTimeOutTimerCount = 0; - state = PRIME_SALINE_PURGE_AIR_STATE; + purgeAirTimeOutStartTime = getMSTimerCount(); + state = HD_PRIME_SALINE_PURGE_AIR_STATE; } - if ( ++noAirDetectedTimerCounter > NO_AIR_DETECTED_COUNT ) + if ( TRUE == didTimeout( noAirDetectedStartTime, NO_AIR_DETECTED_COUNT ) ) { signalBloodPumpHardStop(); - state = PRIME_RESERVOIR_ONE_FILL_COMPLETE_STATE; + state = HD_PRIME_RESERVOIR_ONE_FILL_COMPLETE_STATE; } return state; @@ -358,16 +544,30 @@ * The handlePrimeReservoirOneFillCompleteState function waits for DG to finish * filling reservoir 1 before moving to priming dialyzer. * @details Inputs: reservoirFilledStatus[] - * @details Outputs: none + * @details Outputs: update valves and pumps configuration on state change * @return current state *************************************************************************/ -static PRE_TREATMENT_PRIME_STATE_T handlePrimeReservoirOneFillCompleteState( void ) +static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeReservoirOneFillCompleteState( void ) { - PRE_TREATMENT_PRIME_STATE_T state = PRIME_RESERVOIR_ONE_FILL_COMPLETE_STATE; + HD_PRE_TREATMENT_PRIME_STATE_T state = HD_PRIME_RESERVOIR_ONE_FILL_COMPLETE_STATE; if ( TRUE == reservoirFilledStatus[ DG_RESERVOIR_1 ] ) { - state = PRIME_DIALYSATE_DIALYZER_STATE; + cmdSetDGActiveReservoir( DG_RESERVOIR_1 ); + + 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 ); + + setDialInPumpTargetFlowRate( DIALYSATE_PUMP_PRIME_FLOW_RATE, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + setDialOutPumpTargetRate( DIALYSATE_PUMP_PRIME_FLOW_RATE, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + + previousLoadCellReading = 0; + loadcellSteadyVolumeStartTime = getMSTimerCount(); + primeDialysateDialyzerStartTime = getMSTimerCount(); + state = HD_PRIME_DIALYSATE_DIALYZER_STATE; } return state; @@ -377,15 +577,166 @@ * @brief * The handlePrimeDialysateDialyzerState function handles priming for * dialysate dialyzer fluid path. + * @details Inputs: reservoir 1 filtered weight + * @details Outputs: primed dialysate dialyzer fluid path + * @return current state + *************************************************************************/ +static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeDialysateDialyzerState( void ) +{ + HD_PRE_TREATMENT_PRIME_STATE_T state = HD_PRIME_DIALYSATE_DIALYZER_STATE; + + F32 const loadcellWeight = getReservoirWeightSmallFilter( DG_RESERVOIR_1 ); + F32 const weightChange = fabs( 1.0 - ( previousLoadCellReading / loadcellWeight ) ); + + if ( weightChange < LOAD_CELL_VOLUME_NOISE_TOLERANCE ) + { + if ( TRUE == didTimeout( loadcellSteadyVolumeStartTime, MIN_LOAD_CELL_STEADY_VOLUME_TIME ) ) + { + state = HD_PRIME_RESERVOIR_TWO_FILL_COMPLETE_STATE; + } + } + else + { + previousLoadCellReading = loadcellWeight; + loadcellSteadyVolumeStartTime = getMSTimerCount(); + } + + if ( TRUE == didTimeout( primeDialysateDialyzerStartTime, PRIME_DIALYSATE_DIALYZER_TIME_LIMIT ) ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_PRIME_DIALYSATE_DIALYZER_TIME_OUT, PRIME_DIALYSATE_DIALYZER_TIME_LIMIT ); + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handlePrimeReservoirTwoFillCompleteState function waits for DG to finish + * 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 + *************************************************************************/ +static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeReservoirTwoFillCompleteState( void ) +{ + HD_PRE_TREATMENT_PRIME_STATE_T state = HD_PRIME_RESERVOIR_TWO_FILL_COMPLETE_STATE; + + if ( TRUE == reservoirFilledStatus[ DG_RESERVOIR_2 ] ) + { + signalDialOutPumpHardStop(); + setDialInPumpTargetFlowRate( DIALYSATE_PUMP_PRIME_FLOW_RATE, 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 ); + + previousLoadCellReading = 0; + primeDialysateBypassStartTime = getMSTimerCount(); + loadcellSteadyVolumeStartTime = getMSTimerCount(); + state = HD_PRIME_DIALYSATE_BYPASS_STATE; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handlePrimeDialysateDialyzerState function handles priming for + * dialysate dialyzer fluid path. + * @details Inputs: reservoir 2 filtered weight + * @details Outputs: primed dialysate bypass fluid path + * @return current state + *************************************************************************/ +static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeDialysateBypassState( void ) +{ + HD_PRE_TREATMENT_PRIME_STATE_T state = HD_PRIME_DIALYSATE_BYPASS_STATE; + F32 const loadcellWeight = getReservoirWeightSmallFilter( DG_RESERVOIR_2 ); + F32 const weightChange = fabs( 1.0 - ( previousLoadCellReading / loadcellWeight ) ); + + if ( weightChange < LOAD_CELL_VOLUME_NOISE_TOLERANCE ) + { + if ( TRUE == didTimeout( loadcellSteadyVolumeStartTime, MIN_LOAD_CELL_STEADY_VOLUME_TIME ) ) + { + state = HD_PRIME_WET_SELF_TESTS_STATE; + } + } + else + { + previousLoadCellReading = loadcellWeight; + loadcellSteadyVolumeStartTime = getMSTimerCount(); + } + + if ( TRUE == didTimeout( primeDialysateBypassStartTime, PRIME_DIALYSATE_BYPASS_TIME_LIMIT ) ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_PRIME_DIALYSATE_BYPASS_TIME_OUT, PRIME_DIALYSATE_BYPASS_TIME_LIMIT ); + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handlePrimeWetSelfTestsState function perform wet self-tests after + * priming is completed and collect the result. * @details Inputs: none - * @details Outputs: isPrimeCompleted + * @details Outputs: isWetSelfTestsPassed * @return current state *************************************************************************/ -static PRE_TREATMENT_PRIME_STATE_T handlePrimeDialysateDialyzerState( void ) +static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeWetSelfTestsState( void ) { - // TODO: Add priming for dialysate circuit - isPrimeCompleted = TRUE; - return PRIME_DIALYSATE_DIALYZER_STATE; + // TODO Perform wet self-tests and collect result + wetSelfTestsResult = TRUE; + return HD_PRIME_WET_SELF_TESTS_STATE; } +/*********************************************************************//** + * @brief + * The handlePrimePause function handles prime pause state. + * @details Inputs: previousPrimeState + * @details Outputs: primeStartTime, primeResumeReqReceived + * @return current state + *************************************************************************/ +static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimePause( void ) +{ + HD_PRE_TREATMENT_PRIME_STATE_T state = HD_PRIME_PAUSE; + + if ( TRUE == primeResumeReqReceived ) + { + primeResumeReqReceived = FALSE; + primeStartTime += calcTimeSince( primePauseStartTime ); + + switch ( previousPrimeState ) + { + case HD_PRIME_SALINE_SETUP_STATE: + case HD_PRIME_SALINE_PURGE_AIR_STATE: + case HD_PRIME_SALINE_CIRC_BLOOD_CIRCUIT_STATE: + primeStartReqReceived = TRUE; + state = HD_PRIME_SALINE_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_RESERVOIR_TWO_FILL_COMPLETE_STATE: + case HD_PRIME_DIALYSATE_BYPASS_STATE: + state = HD_PRIME_RESERVOIR_TWO_FILL_COMPLETE_STATE; + break; + + case HD_PRIME_WET_SELF_TESTS_STATE: + state = HD_PRIME_WET_SELF_TESTS_STATE; + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_PRE_TREATMENT_PRIME_INVALID_STATE, (U32)previousPrimeState ); + break; + } + } + + return state; +} + /**@}*/