Index: firmware/App/Modes/Prime.c =================================================================== diff -u -r8e2cfecc47bb3912078b29513f1717c1567f0071 -r174c9ba02da6790f01ea9141ab1cc1d28388f2f8 --- firmware/App/Modes/Prime.c (.../Prime.c) (revision 8e2cfecc47bb3912078b29513f1717c1567f0071) +++ firmware/App/Modes/Prime.c (.../Prime.c) (revision 174c9ba02da6790f01ea9141ab1cc1d28388f2f8) @@ -5,7 +5,7 @@ * 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 +* @file Prime.c * * @author (last) Quang Nguyen * @date (last) 08-Dec-2020 @@ -22,6 +22,7 @@ #include "DialOutFlow.h" #include "DGInterface.h" #include "Prime.h" +#include "SelfTests.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "Timers.h" @@ -45,9 +46,12 @@ #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 PRIME_CONSUMED_DIALYSATE_VOLUME_ML 100 ///< Volume of dialysate consumed during prime. +/// Fill reservoir 1 to this volume (in mL) during prime. +#define PRIME_FILL_RESERVOIR_ONE_VOLUME_ML ( FILL_RESERVOIR_TO_VOLUME_ML - PRIME_CONSUMED_DIALYSATE_VOLUME_ML ) +#define PRIME_FILL_RESERVOIR_TWO_VOLUME_ML 500 ///< Fill reservoir 2 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. @@ -75,15 +79,15 @@ 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 primeCompleted; ///< Prime complete status. 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 BOOL primeStartRequested; ///< Flag indicates user requesting to start prime. +static BOOL primeStopRequested; ///< Flag indicates alarm requesting to stop prime. +static BOOL primeResumeRequested; ///< Flag indicates user requesting prime resume. +static BOOL reservoirFilledStatus[ NUM_OF_DG_RESERVOIRS ]; ///< Flag indicates a reservoir has been filled. static U32 noAirDetectedStartTime; ///< starting time when detecting no air. static U32 purgeAirTimeOutStartTime; ///< Starting time for purge air state time out. @@ -94,11 +98,13 @@ // ********** private function prototypes ********** +static void resetPrimeFlags(); static void handlePrimePauseRequest( void ); static void broadcastPrimingStatus( void ); static void execPrimeReservoirMgmt( void ); static void purgeAirValvesBloodPumpControl( void ); +static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeWaitForUserStartState( 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 ); @@ -135,21 +141,19 @@ currentPrimeState = HD_PRIME_START_STATE; currentReservoirMgmtState = PRIME_RESERVOIR_MGMT_START_STATE; - wetSelfTestsResult = FALSE; + primeCompleted = FALSE; primeStartTime = getMSTimerCount(); primePauseStartTime = 0; primeStatusBroadcastTimerCounter = 0; - // TODO: set to false after integration with UI - primeStartReqReceived = TRUE; - 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 ); + setAlarmUserActionEnabled( ALARM_USER_ACTION_END_TREATMENT, TRUE ); + + resetPrimeFlags(); } /*********************************************************************//** @@ -166,9 +170,17 @@ { case HD_PRIME_START_STATE: cmdSetDGActiveReservoir( DG_RESERVOIR_2 ); - currentPrimeState = HD_PRIME_SALINE_SETUP_STATE; +#ifdef SKIP_PRIMING + currentPrimeState = HD_PRIME_RESERVOIR_ONE_FILL_COMPLETE_STATE; +#else + currentPrimeState = HD_PRIME_WAIT_FOR_USER_START_STATE; +#endif break; + case HD_PRIME_WAIT_FOR_USER_START_STATE: + currentPrimeState = handlePrimeWaitForUserStartState(); + break; + case HD_PRIME_SALINE_SETUP_STATE: currentPrimeState = handlePrimeSalineSetupState(); break; @@ -201,6 +213,10 @@ currentPrimeState = handlePrimeWetSelfTestsState(); break; + case HD_PRIME_COMPLETE: + primeCompleted = TRUE; + break; + case HD_PRIME_PAUSE: currentPrimeState = handlePrimePause(); break; @@ -211,6 +227,9 @@ break; } + // Prime flags should be handled by now + resetPrimeFlags(); + // Handle prime pause request handlePrimePauseRequest(); @@ -223,46 +242,55 @@ /*********************************************************************//** * @brief - * The isWetSelfTestsPassed function returns the status of wet self-tests - * after priming. + * The isPrimeCompleted function returns the status of prime. * @details Inputs: none * @details Outputs: none - * @return TRUE if wet self-tests passed, otherwise FALSE + * @return TRUE if prime has completed succesfully, otherwise FALSE *************************************************************************/ -BOOL isWetSelfTestsPassed( void ) +BOOL isPrimeCompleted( void ) { - return wetSelfTestsResult; + return primeCompleted; } /*********************************************************************//** * @brief - * The signalAlarmActionToPrimeMode function executes the given alarm action - * as appropriate while in Prime Mode. + * The signalResumePrime function signals the prime sub-mode to resume + * previous operation. * @details Inputs: none - * @details Outputs: given alarm action executed - * @param action ID of alarm action to execute + * @details Outputs: primeResumeRequested * @return none *************************************************************************/ -void signalAlarmActionToPrimeMode( ALARM_ACTION_T action ) +void signalResumePrime( void ) { - switch ( action ) - { - case ALARM_ACTION_STOP: - primePauseReqReceived = TRUE; - break; + primeResumeRequested = TRUE; +} - case ALARM_ACTION_RESUME: - primeResumeReqReceived = TRUE; - break; +/*********************************************************************//** + * @brief + * The signalStopPrime function signals the prime sub-mode to stop when an + * alarm with stop property has been triggered. + * @details Inputs: none + * @details Outputs: primeStopRequested + * @return none + *************************************************************************/ +void signalStopPrime( void ) +{ + primeStopRequested = TRUE; +} - 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 resetPrimeFlags function resets all prime signal flags. + * @details Inputs: none + * @details Outputs: signal flags set to FALSE + * @return none + *************************************************************************/ +static void resetPrimeFlags( void ) +{ + // TODO: set to false after integration with UI + primeStartRequested = TRUE; + primeResumeRequested = FALSE; + primeStopRequested = FALSE; } /*********************************************************************//** @@ -274,16 +302,16 @@ *************************************************************************/ static void handlePrimePauseRequest( void ) { - if ( ( TRUE == primePauseReqReceived ) && ( HD_PRIME_PAUSE != currentPrimeState ) ) + if ( ( TRUE == primeStopRequested ) && ( HD_PRIME_PAUSE != currentPrimeState ) ) { signalDialOutPumpHardStop(); signalDialInPumpHardStop(); signalBloodPumpHardStop(); - primePauseReqReceived = FALSE; - primePauseStartTime = getMSTimerCount(); - previousPrimeState = currentPrimeState; - currentPrimeState = HD_PRIME_PAUSE; + primeStopRequested = FALSE; + primePauseStartTime = getMSTimerCount(); + previousPrimeState = currentPrimeState; + currentPrimeState = HD_PRIME_PAUSE; } } @@ -327,12 +355,9 @@ 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 ) { @@ -356,17 +381,15 @@ break; case PRIME_RESERVOIR_MGMT_WAIT_FOR_DRAIN_CMD_RESP: - if ( DG_CMD_START_DRAIN == dgCmdResp.commandID ) + if ( ( TRUE == getDGCommandResponse( DG_CMD_START_DRAIN, &dgCmdResp ) ) && ( DG_CMD_REQUEST_REJECT_REASON_INVALID_MODE == dgCmdResp.rejected ) ) { - 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; - } + 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: @@ -380,24 +403,30 @@ 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 ); - } - break; - case PRIME_RESERVOIR_MGMT_WAIT_FOR_FILL_CMD_RESP: - if ( DG_CMD_START_FILL == dgCmdResp.commandID ) - { - if ( FALSE == dgCmdResp.rejected ) + if ( DG_RESERVOIR_1 == getDGInactiveReservoir() ) { - currentReservoirMgmtState = PRIME_RESERVOIR_MGMT_FILL_STATE; + cmdStartDGFill( PRIME_FILL_RESERVOIR_ONE_VOLUME_ML ); } - else if ( DG_CMD_REQUEST_REJECT_REASON_INVALID_MODE == dgCmdResp.rejected ) + else { - currentReservoirMgmtState = PRIME_RESERVOIR_MGMT_START_FILL_STATE; + cmdStartDGFill( PRIME_FILL_RESERVOIR_TWO_VOLUME_ML ); } } break; + case PRIME_RESERVOIR_MGMT_WAIT_FOR_FILL_CMD_RESP: + if ( ( TRUE == getDGCommandResponse( DG_CMD_START_FILL, &dgCmdResp ) ) && ( DG_CMD_REQUEST_REJECT_REASON_INVALID_MODE == dgCmdResp.rejected ) ) + { + currentReservoirMgmtState = PRIME_RESERVOIR_MGMT_START_FILL_STATE; + } + + if ( DG_MODE_FILL == dgOpMode ) + { + currentReservoirMgmtState = PRIME_RESERVOIR_MGMT_FILL_STATE; + } + break; + case PRIME_RESERVOIR_MGMT_FILL_STATE: if ( DG_MODE_CIRC == dgOpMode ) { @@ -462,23 +491,37 @@ * @details Outputs: control valves to purge air * @return current state *************************************************************************/ -static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeSalineSetupState( void ) +static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeWaitForUserStartState( void ) { - HD_PRE_TREATMENT_PRIME_STATE_T state = HD_PRIME_SALINE_SETUP_STATE; + HD_PRE_TREATMENT_PRIME_STATE_T state = HD_PRIME_WAIT_FOR_USER_START_STATE; - if ( TRUE == primeStartReqReceived ) + if ( TRUE == primeStartRequested ) { - purgeAirValvesBloodPumpControl(); - purgeAirTimeOutStartTime = getMSTimerCount(); - primeStartReqReceived = FALSE; - state = HD_PRIME_SALINE_PURGE_AIR_STATE; + primeStartRequested = FALSE; + state = HD_PRIME_SALINE_SETUP_STATE; } return state; } /*********************************************************************//** * @brief + * The handlePrimeSalineSetupState function checks user's request to start + * priming. + * @details Inputs: primeStartReqReceived + * @details Outputs: control valves to purge air + * @return current state + *************************************************************************/ +static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeSalineSetupState( void ) +{ + purgeAirValvesBloodPumpControl(); + purgeAirTimeOutStartTime = getMSTimerCount(); + + return HD_PRIME_SALINE_PURGE_AIR_STATE; +} + +/*********************************************************************//** + * @brief * The handlePrimePurgeAirState function checks for air trap level and moves * to blood circuit circulation state if fluid is detected at upper sensor. * @details Inputs: air trap levels @@ -567,7 +610,12 @@ previousLoadCellReading = 0; loadcellSteadyVolumeStartTime = getMSTimerCount(); primeDialysateDialyzerStartTime = getMSTimerCount(); + +#ifdef SKIP_PRIMING + state = HD_PRIME_WET_SELF_TESTS_STATE; +#else state = HD_PRIME_DIALYSATE_DIALYZER_STATE; +#endif } return state; @@ -585,7 +633,7 @@ { HD_PRE_TREATMENT_PRIME_STATE_T state = HD_PRIME_DIALYSATE_DIALYZER_STATE; - F32 const loadcellWeight = getReservoirWeightSmallFilter( DG_RESERVOIR_1 ); + F32 const loadcellWeight = getLoadCellWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); F32 const weightChange = fabs( 1.0 - ( previousLoadCellReading / loadcellWeight ) ); if ( weightChange < LOAD_CELL_VOLUME_NOISE_TOLERANCE ) @@ -623,6 +671,7 @@ if ( TRUE == reservoirFilledStatus[ DG_RESERVOIR_2 ] ) { + cmdSetDGActiveReservoir( DG_RESERVOIR_2 ); signalDialOutPumpHardStop(); setDialInPumpTargetFlowRate( DIALYSATE_PUMP_PRIME_FLOW_RATE, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); @@ -652,13 +701,14 @@ 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 loadcellWeight = getLoadCellWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); 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 ) ) { + transitionToWetSelfTests(); state = HD_PRIME_WET_SELF_TESTS_STATE; } } @@ -686,9 +736,26 @@ *************************************************************************/ static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeWetSelfTestsState( void ) { - // TODO Perform wet self-tests and collect result - wetSelfTestsResult = TRUE; - return HD_PRIME_WET_SELF_TESTS_STATE; + HD_PRE_TREATMENT_PRIME_STATE_T state = HD_PRIME_WET_SELF_TESTS_STATE; + + if ( TRUE == primeStopRequested ) + { + signalResumeSelfTests(); + } + + if ( TRUE == primeResumeRequested ) + { + signalStopSelfTests(); + } + + execWetSelfTests(); + + if ( TRUE == isWetSelfTestsPassed() ) + { + state = HD_PRIME_COMPLETE; + } + + return state; } /*********************************************************************//** @@ -702,17 +769,16 @@ { HD_PRE_TREATMENT_PRIME_STATE_T state = HD_PRIME_PAUSE; - if ( TRUE == primeResumeReqReceived ) + if ( TRUE == primeResumeRequested ) { - primeResumeReqReceived = FALSE; + primeResumeRequested = 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; @@ -727,6 +793,7 @@ break; case HD_PRIME_WET_SELF_TESTS_STATE: + signalResumeSelfTests(); state = HD_PRIME_WET_SELF_TESTS_STATE; break;