Index: firmware/App/Modes/ModeGenIdle.c =================================================================== diff -u -re77916f2c497a4475d0c442067782614931e43a1 -r7d0fd5ed6b9db0479af90477e5108f6d3fa8df17 --- firmware/App/Modes/ModeGenIdle.c (.../ModeGenIdle.c) (revision e77916f2c497a4475d0c442067782614931e43a1) +++ firmware/App/Modes/ModeGenIdle.c (.../ModeGenIdle.c) (revision 7d0fd5ed6b9db0479af90477e5108f6d3fa8df17) @@ -1,15 +1,15 @@ /************************************************************************** * -* Copyright (c) 2021-2023 Diality Inc. - All Rights Reserved. +* Copyright (c) 2021-2024 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 ModeGenIdle.c * * @author (last) Dara Navaei -* @date (last) 20-Apr-2023 +* @date (last) 09-Apr-2024 * * @author (original) Quang Nguyen * @date (original) 06-Aug-2021 @@ -39,15 +39,15 @@ #include "Valves.h" /** - * @addtogroup DGRecirculateMode + * @addtogroup DGGenIdleMode * @{ */ // ********** private definitions ********** #define TARGET_RO_PRESSURE_PSI 130 ///< Target pressure for RO pump. -#define TARGET_RO_FLOW_RATE_L 0.4F ///< Target flow rate for RO pump. -#define BAD_FLUSH_FILL_TARGET_VOLUME_ML 1000 ///< Target fill volume in the bad flush fill state. +#define TARGET_RO_FLOW_RATE_L 0.8F ///< Target flow rate for RO pump. +#define MAX_IDLE_RSVR_WEIGHT_GAIN_ML 200.0F ///< Maximum fluid gain of inactive reservoir in Gen Idle mode (mL) #define HD_LOST_COMM_TIMEOUT_MS (5 * SEC_PER_MIN * MS_PER_SECOND ) ///< The time of HD lost comm before DG transition back to standby. #define BAD_FILL_SUBSTATES_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the bad fill sub-states is published on the CAN bus. #define DATA_PUBLISH_COUNTER_START_COUNT 61 ///< Data publish counter start count. @@ -59,12 +59,16 @@ // NOTE: the bad fill state must be initialized here and not in the transition function since in case of a bad fill, the transition function is called // several times to drain and fill and handle a bad fill. static DG_GEN_IDLE_MODE_BAD_FILL_STATE_T badFillState = DG_HANDLE_BAD_FILL_STATE_START; ///< Initialize bad fill sub-state. +// NOTE: the empty bottle flag must be initialized here and not in transition function since this flag must be set to false once the empty bottle +// fill is finished. +static BOOL handleEmptyBottleFlag = FALSE; ///< Internal siganl flag to handle empty bottle flag. static U32 hdLostCommStartTime_ms; ///< Lost communication with HD start time in ms. -static U32 targetFillVolumeML; ///< Save the target fill volume before calling startFillCmd(). static BOOL handleBadFillFlag; ///< Internal signal flag to handle bad fill. static OVERRIDE_U32_T genIdleDataPublicationInterval = { BAD_FILL_SUBSTATES_PUB_INTERVAL, BAD_FILL_SUBSTATES_PUB_INTERVAL, 0, 0 }; ///< Interval (in ms) at which to publish bad fill sub-states to CAN bus. +static F32 initialReservoirWeight; ///< Initial weight of inactive reservoir in Gen Idle mode. +static DG_RESERVOIR_ID_T inactiveReservoir; ///< Inactive reservoir // ********** private function prototypes ********** @@ -76,9 +80,10 @@ static DG_GEN_IDLE_MODE_BAD_FILL_STATE_T handleFirstDrainState( void ); static DG_GEN_IDLE_MODE_BAD_FILL_STATE_T handleFlushFillState( void ); static DG_GEN_IDLE_MODE_BAD_FILL_STATE_T handleSecondDrainState( void ); -static DG_GEN_IDLE_MODE_BAD_FILL_STATE_T handleRefillState( void ); +static DG_GEN_IDLE_MODE_BAD_FILL_STATE_T handleRefillState( DG_GEN_IDLE_MODE_STATE_T* idleState ); -static void publishGenIdleSubstates(); +static void checkInvalidReservoirFill( void ); +static void publishGenIdleSubstates( void ); /*********************************************************************//** * @brief @@ -102,9 +107,12 @@ *************************************************************************/ U32 transitionToGenIdleMode( void ) { + BOOL cp1parkStatus = ( getConcPumpIsParked( CONCENTRATEPUMPS_CP1_ACID ) != TRUE ? PARK_CONC_PUMPS : NO_PARK_CONC_PUMPS ); + BOOL cp2parkStatus = ( getConcPumpIsParked( CONCENTRATEPUMPS_CP2_BICARB ) != TRUE ? PARK_CONC_PUMPS : NO_PARK_CONC_PUMPS ); + // Re-initialize each time we transition to generation idle mode initGenIdleMode(); - + setCurrentSubState( NO_SUB_STATE ); // Set initial actuator states setValveState( VSP, VALVE_STATE_CLOSED ); setValveState( VPI, VALVE_STATE_OPEN ); @@ -115,9 +123,12 @@ setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + // Set back the conductivity of CD2 calibration table to the normal calibration table + setCondcutivitySensorCalTable( CONDUCTIVITYSENSORS_CD2_SENSOR, CAL_DATA_CD2_COND_SENSOR ); + signalDrainPumpHardStop(); - requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID, NO_PARK_CONC_PUMPS ); - requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB, NO_PARK_CONC_PUMPS ); + requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID, cp1parkStatus ); + requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB, cp2parkStatus ); // UV reactors on turnOnUVReactor( INLET_UV_REACTOR ); @@ -136,6 +147,9 @@ setCPLDCleanLEDColor( CPLD_CLEAN_LED_OFF ); + inactiveReservoir = getInactiveReservoir(); + initialReservoirWeight = getReservoirWeight( inactiveReservoir ); + return genIdleState; } @@ -154,6 +168,19 @@ /*********************************************************************//** * @brief + * The getCurrentGenIdleBadFillState function returns the current state of the + * generation idle mode bad fill. + * @details Inputs: badFillState + * @details Outputs: none + * @return the current state of generation idle mode bad fill + *************************************************************************/ +DG_GEN_IDLE_MODE_BAD_FILL_STATE_T getCurrentGenIdleBadFillState( void ) +{ + return badFillState; +} + +/*********************************************************************//** + * @brief * The requestDGStop function handles an HD request to stop (return to standby mode). * @details Inputs: none * @details Outputs: DG standby mode requested @@ -173,13 +200,13 @@ * The setBadAvgConductivityDetectedFlag function sets a flag to indicate * that bad average conductivity is detected. * @details Inputs: none - * @details Outputs: none + * @details Outputs: handleBadFillFlag, badFillState * @param flag to TRUE if bad avg conductivity otherwise FALSE *************************************************************************/ void setBadAvgConductivityDetectedFlag( BOOL badAvgConducitivyflag ) { handleBadFillFlag = badAvgConducitivyflag; - badFillState = DG_HANDLE_BAD_FILL_STATE_START; // Reset bad fill state too so we start at beginning + badFillState = DG_HANDLE_BAD_FILL_STATE_START; // Reset bad fill state too so we start at beginning } /*********************************************************************//** @@ -230,6 +257,7 @@ break; } + checkInvalidReservoirFill(); publishGenIdleSubstates(); return (U32)genIdleState; @@ -239,8 +267,8 @@ * @brief * The handleIdleStartState function executes the start state of the * generation idle mode state machine. - * @details Inputs: none - * @details Outputs: none + * @details Inputs: handleEmptyBottleFlag + * @details Outputs: handleEmptyBottleFlag, handleBadFillFlag, badFillState * @return the next state *************************************************************************/ static DG_GEN_IDLE_MODE_STATE_T handleIdleStartState( void ) @@ -255,6 +283,14 @@ { badFillState = DG_HANDLE_BAD_FILL_STATE_START; result = DG_GEN_IDLE_MODE_STATE_FLUSH_WATER; + + if ( ( TRUE == handleEmptyBottleFlag ) && ( DG_MODE_FILL == getPreviousOperationMode() ) ) + { + // If the previous mode was fill and the empty bottle flag was TRUE, set it to FALSE and clear the informative alarm + // Done with the empty bottle handling + handleEmptyBottleFlag = FALSE; + clearAlarmCondition( ALARM_ID_DG_CREATING_DIALYSATE_PLEASE_WAIT ); + } } return result; @@ -264,14 +300,28 @@ * @brief * The handleFlushWaterState function executes the flush water state * generation idle mode state machine. - * @details Inputs: none - * @details Outputs: none + * @details Inputs: handleEmptyBottleFlag + * @details Outputs: handleEmptyBottleFlag * @return the next state *************************************************************************/ static DG_GEN_IDLE_MODE_STATE_T handleFlushWaterState( void ) { DG_GEN_IDLE_MODE_STATE_T result = DG_GEN_IDLE_MODE_STATE_FLUSH_WATER; + if ( ( TRUE == isAlarmActive( ALARM_ID_DG_ACID_BOTTLE_LOW_VOLUME ) ) || ( TRUE == isAlarmActive( ALARM_ID_DG_BICARB_BOTTLE_LOW_VOLUME ) ) ) + { + // The empty bottle alarms are active set the empty bottle alarm to TRUE. + handleEmptyBottleFlag = TRUE; + } + + if ( ( TRUE == handleEmptyBottleFlag ) && + ( isAlarmActive( ALARM_ID_DG_ACID_BOTTLE_LOW_VOLUME ) != TRUE ) && + ( isAlarmActive( ALARM_ID_DG_BICARB_BOTTLE_LOW_VOLUME ) != TRUE ) ) + { + // User acknowledged empty conc bottle alarm(s) and so time to start a fill + startFillCmd( getTargetFillVolumeML(), getTargetFillFlowRateLPM() ); + } + return result; } @@ -280,12 +330,13 @@ * The handleBadFillState function executes the bad fill state of the * generation idle mode state machine. * @details Inputs: none - * @details Outputs: badFillState + * @details Outputs: badFillState, genIdleState * @return the next state *************************************************************************/ static DG_GEN_IDLE_MODE_STATE_T handleBadFillState( void ) { DG_GEN_IDLE_MODE_STATE_T result = DG_GEN_IDLE_MODE_STATE_HANDLE_BAD_FILL; + U32 priorSubState = badFillState; // Execute current bad fill state switch ( badFillState ) @@ -307,7 +358,7 @@ break; case DG_HANDLE_BAD_FILL_STATE_REFILL: - badFillState = handleRefillState(); + badFillState = handleRefillState( &result ); break; default: @@ -316,6 +367,10 @@ break; } + if ( priorSubState != badFillState ) + { + setCurrentSubState( badFillState ); + } return result; } @@ -352,13 +407,13 @@ // Check if the alarm has been cleared by the user and if yes, continue with the fill if ( FALSE == isAlarmActive( ALARM_ID_DG_FILL_CONDUCTIVITY_OUT_OF_RANGE ) ) { - // Save the HD target fill volume before command 1000 mL fill volume - targetFillVolumeML = getTargetFillVolumeML(); + state = DG_HANDLE_BAD_FILL_STATE_FLUSH_FILL; - state = DG_HANDLE_BAD_FILL_STATE_FLUSH_FILL; - - // Start the flush fill - startFillCmd( BAD_FLUSH_FILL_TARGET_VOLUME_ML, getTargetFillFlowRateLPM() ); + // Start the flush fill. + // NOTE: the actual target fill from HD is sent here but at this stage the fill target is 1000 mL. + // The other functions that check against the fill target know to check for 1000 mL. This is to make sure + // the actual fill target from HD is not overridden in case multiple bad fills occurred back to back. + startFillCmd( getTargetFillVolumeML(), getTargetFillFlowRateLPM() ); } return state; @@ -394,7 +449,7 @@ DG_GEN_IDLE_MODE_BAD_FILL_STATE_T state = DG_HANDLE_BAD_FILL_STATE_REFILL; // Refill to the saved target fill volume (~1500 mL) - startFillCmd( targetFillVolumeML, getTargetFillFlowRateLPM() ); + startFillCmd( getTargetFillVolumeML(), getTargetFillFlowRateLPM() ); return state; } @@ -404,24 +459,52 @@ * The handleRefillState function executes refill state of the handle bad * fill state machine. * @details Inputs: none - * @details Outputs: none + * @details Outputs: handleBadFillFlag + * @param idleState reference variable for the next idle state * @return the next state *************************************************************************/ -static DG_GEN_IDLE_MODE_BAD_FILL_STATE_T handleRefillState( void ) +static DG_GEN_IDLE_MODE_BAD_FILL_STATE_T handleRefillState( DG_GEN_IDLE_MODE_STATE_T* idleState ) { DG_GEN_IDLE_MODE_BAD_FILL_STATE_T state = DG_HANDLE_BAD_FILL_STATE_START; // Clear wait for dialysate alarm condition to allow resume clearAlarmCondition( ALARM_ID_DG_CREATING_DIALYSATE_PLEASE_WAIT ); // resume option will appear // Set flag to FALSE here so next call to idle exec will move to normal flush water state handleBadFillFlag = FALSE; - genIdleState = DG_GEN_IDLE_MODE_STATE_START; + *idleState = DG_GEN_IDLE_MODE_STATE_START; return state; } /*********************************************************************//** * @brief + * The checkInvalidReservoirFill function checks for reservoir filling in + * generation idle mode when it should be constant. + * @details Inputs: inactiveReservoir, initialReservoirWeight + * @details Outputs: inactiveReservoir, initialReservoirWeight + * @return the next state + *************************************************************************/ +static void checkInvalidReservoirFill( void ) +{ + DG_RESERVOIR_ID_T currentInactiveReservoir = getInactiveReservoir(); + F32 reservoirWeight = getReservoirWeight( currentInactiveReservoir ); + + if ( currentInactiveReservoir != inactiveReservoir ) + { + // Inactive Reservoir changed, update the start value + inactiveReservoir = currentInactiveReservoir; + initialReservoirWeight = getReservoirWeight( inactiveReservoir ); + } + + // Check for unwanted filling unless a transfer is in progress + if ( ( FALSE == isReservoirTransferInProgress() ) && ( reservoirWeight > ( initialReservoirWeight + MAX_IDLE_RSVR_WEIGHT_GAIN_ML ) ) ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DG_INACTIVE_RESERVOIR_WEIGHT_OUT_OF_RANGE, initialReservoirWeight, reservoirWeight ); + } +} + +/*********************************************************************//** + * @brief * The publishGenIdleSubstates function publishes gen idle * sub-states at the set interval. * @details Inputs: handleBadFillFlag, badFillState, targetFillVolumeML, @@ -440,15 +523,28 @@ data.badFillSignal = (U32)handleBadFillFlag; data.badFillState = (U32)badFillState; data.genIdleState = (U32)getCurrentGenIdleState(); - data.targetFillVolumemL = targetFillVolumeML; + data.targetFillVolumemL = getTargetFillVolumeML(); broadcastData( MSG_ID_DG_GEN_IDLE_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&data, sizeof( DG_GEN_IDLE_DATA_T ) ); dataPublishCounter = 0; } } +/*********************************************************************//** + * @brief + * The getCurrentBadFillSignal function returns the current + * generation idle mode bad fill flag. + * @details Inputs: handleBadFillFlag + * @details Outputs: none + * @return the current generation idle mode bad fill flag + *************************************************************************/ +BOOL getCurrentBadFillSignal( void ) +{ + return handleBadFillFlag; +} + /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ @@ -460,7 +556,7 @@ * bad fill sub-states publish interval. * @details Inputs: badFillSubstatesPublishInterval * @details Outputs: badFillSubstatesPublishInterval - * @param: value override bad fill sub-states publish interval with (in ms) + * @param value override bad fill sub-states publish interval with (in ms) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetGenIdleSubstatesPublishIntervalOverride( U32 value )