Index: firmware/App/Modes/ModeGenIdle.c =================================================================== diff -u -r44222e803e04d057ab793ce6b72902b8bfe9b7d0 -reeaab2a9a685fb18845888d91040d3aa01977f6d --- firmware/App/Modes/ModeGenIdle.c (.../ModeGenIdle.c) (revision 44222e803e04d057ab793ce6b72902b8bfe9b7d0) +++ firmware/App/Modes/ModeGenIdle.c (.../ModeGenIdle.c) (revision eeaab2a9a685fb18845888d91040d3aa01977f6d) @@ -1,15 +1,15 @@ /************************************************************************** * -* Copyright (c) 2019-2022 Diality Inc. - All Rights Reserved. +* Copyright (c) 2021-2023 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) 10-Dec-2021 +* @author (last) Michael Garthwaite +* @date (last) 16-May-2023 * * @author (original) Quang Nguyen * @date (original) 06-Aug-2021 @@ -20,14 +20,18 @@ #include "ConductivitySensors.h" #include "DrainPump.h" #include "FPGA.h" +#include "CPLD.h" +#include "HDDefs.h" #include "Heaters.h" +#include "ModeFill.h" #include "ModeGenIdle.h" #include "NVDataMgmt.h" #include "OperationModes.h" #include "Pressures.h" #include "Reservoirs.h" #include "ROPump.h" #include "SystemComm.h" +#include "SystemCommMessages.h" #include "TaskGeneral.h" #include "TemperatureSensors.h" #include "Timers.h" @@ -41,25 +45,41 @@ // ********** private definitions ********** -#define TARGET_RO_PRESSURE_PSI 130 ///< Target pressure for RO pump. -#define TARGET_RO_FLOW_RATE_L 0.3 ///< Target flow rate for RO pump. +#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 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. -#define TARGET_FLUSH_LINES_RO_FLOW_RATE_L 0.3 ///< Target flow rate for RO pump. - -/// The time of HD lost comm before DG transition back to standby. -#define HD_LOST_COMM_TIMEOUT_MS (5 * SEC_PER_MIN * MS_PER_SECOND ) - // ********** private data ********** -static DG_GEN_IDLE_MODE_STATE_T genIdleState; ///< Currently active generation idle state. -static F32 flushLinesVolumeL = 0.0; ///< Volume of water pumped by RO pump during flush lines state. -static U32 hdLostCommStartTime_ms = 0; ///< Lost communication with HD start time in ms. +static U32 dataPublishCounter; ///< Used to schedule gen idle data publication to CAN bus. +static DG_GEN_IDLE_MODE_STATE_T genIdleState; ///< Currently active generation idle state. +// 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. +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. // ********** private function prototypes ********** -static DG_GEN_IDLE_MODE_STATE_T handleFlushLinesState( void ); +static DG_GEN_IDLE_MODE_STATE_T handleIdleStartState( void ); static DG_GEN_IDLE_MODE_STATE_T handleFlushWaterState( void ); +static DG_GEN_IDLE_MODE_STATE_T handleBadFillState( void ); +static DG_GEN_IDLE_MODE_BAD_FILL_STATE_T handleStartState( void ); +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( DG_GEN_IDLE_MODE_STATE_T* idleState ); + +static void publishGenIdleSubstates(); + /*********************************************************************//** * @brief * The initGenIdleMode function initializes the generation idle mode module. @@ -69,8 +89,7 @@ *************************************************************************/ void initGenIdleMode( void ) { - genIdleState = DG_GEN_IDLE_MODE_STATE_START; - flushLinesVolumeL = 0.0; + genIdleState = DG_GEN_IDLE_MODE_STATE_START; hdLostCommStartTime_ms = 0; } @@ -85,7 +104,7 @@ { // 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 ); @@ -96,9 +115,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 ); - requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB ); + requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID, NO_PARK_CONC_PUMPS ); + requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB, NO_PARK_CONC_PUMPS ); // UV reactors on turnOnUVReactor( INLET_UV_REACTOR ); @@ -107,17 +129,64 @@ // NOTE: The target flow rate should be set prior to setting the start primary heater // because the initial guess in the heaters driver needs the target flow to calculate // the new PWMs for the main and small primary heaters -#ifndef DISABLE_FLOW_CONTROL_TREATMENT - setROPumpTargetFlowRateLPM( TARGET_FLUSH_LINES_RO_FLOW_RATE_L, TARGET_RO_PRESSURE_PSI ); - setHeaterTargetTemperature( DG_PRIMARY_HEATER, getPrimaryHeaterTargetTemperature() ); - startHeater( DG_PRIMARY_HEATER ); -#endif + setROPumpTargetFlowRateLPM( TARGET_RO_FLOW_RATE_L, TARGET_RO_PRESSURE_PSI ); + if ( FALSE == isHeaterOn( DG_PRIMARY_HEATER ) ) + { + setHeaterTargetTemperature( DG_PRIMARY_HEATER, getPrimaryHeaterTargetTemperature() ); + startHeater( DG_PRIMARY_HEATER ); + } + + setCPLDCleanLEDColor( CPLD_CLEAN_LED_OFF ); + return genIdleState; } /*********************************************************************//** * @brief + * The getCurrentGenIdleState function returns the current state of the + * generation idle mode. + * @details Inputs: genIdleState + * @details Outputs: none + * @return the current state of generation idle mode + *************************************************************************/ +DG_GEN_IDLE_MODE_STATE_T getCurrentGenIdleState( void ) +{ + return genIdleState; +} + +/*********************************************************************//** + * @brief + * The requestDGStop function handles an HD request to stop (return to standby mode). + * @details Inputs: none + * @details Outputs: DG standby mode requested + * @return TRUE if request accepted, FALSE if not. + *************************************************************************/ +BOOL requestDGStop( void ) +{ + BOOL result = TRUE; + + requestNewOperationMode( DG_MODE_STAN ); + + return result; +} + +/*********************************************************************//** + * @brief + * The setBadAvgConductivityDetectedFlag function sets a flag to indicate + * that bad average conductivity is detected. + * @details Inputs: none + * @details Outputs: none + * @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 +} + +/*********************************************************************//** + * @brief * The execGenIdleMode function executes the generation idle mode state machine. * @details Inputs: genIdleState * @details Outputs: Check water quality, generation idle mode state machine executed @@ -128,8 +197,7 @@ // Check inlet water conductivity, temperature, pressure, and RO rejection ratio checkInletWaterConductivity(); checkInletWaterTemperature(); - checkInletPressure(); - checkRORejectionRatio(); + checkInletWaterPressure(); // Transition to standby mode when HD is not communicating if ( TRUE == isHDCommunicating() ) @@ -148,95 +216,297 @@ switch ( genIdleState ) { case DG_GEN_IDLE_MODE_STATE_START: - genIdleState = DG_GEN_IDLE_MODE_STATE_FLUSH_LINES; + genIdleState = handleIdleStartState(); break; - case DG_GEN_IDLE_MODE_STATE_FLUSH_LINES: - genIdleState = handleFlushLinesState(); - break; - case DG_GEN_IDLE_MODE_STATE_FLUSH_WATER: genIdleState = handleFlushWaterState(); break; + case DG_GEN_IDLE_MODE_STATE_HANDLE_BAD_FILL: + genIdleState = handleBadFillState(); + break; + default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_GEN_IDLE_MODE_INVALID_EXEC_STATE, genIdleState ) genIdleState = DG_GEN_IDLE_MODE_STATE_START; break; } + publishGenIdleSubstates(); + return (U32)genIdleState; } /*********************************************************************//** * @brief - * The getCurrentGenIdleState function returns the current state of the - * generation idle mode. - * @details Inputs: genIdleState + * The handleIdleStartState function executes the start state of the + * generation idle mode state machine. + * @details Inputs: none * @details Outputs: none - * @return the current state of generation idle mode + * @return the next state *************************************************************************/ -DG_GEN_IDLE_MODE_STATE_T getCurrentGenIdleState( void ) +static DG_GEN_IDLE_MODE_STATE_T handleIdleStartState( void ) { - return genIdleState; + DG_GEN_IDLE_MODE_STATE_T result = DG_GEN_IDLE_MODE_STATE_START; + + if ( TRUE == handleBadFillFlag ) + { + result = DG_GEN_IDLE_MODE_STATE_HANDLE_BAD_FILL; + } + else + { + badFillState = DG_HANDLE_BAD_FILL_STATE_START; + result = DG_GEN_IDLE_MODE_STATE_FLUSH_WATER; + } + + return result; } /*********************************************************************//** * @brief - * The requestDGStop function handles an HD request to stop (return to standby mode). + * The handleFlushWaterState function executes the flush water state + * generation idle mode state machine. * @details Inputs: none - * @details Outputs: DG standby mode requested - * @return TRUE if request accepted, FALSE if not. + * @details Outputs: none + * @return the next state *************************************************************************/ -BOOL requestDGStop( void ) +static DG_GEN_IDLE_MODE_STATE_T handleFlushWaterState( void ) { - BOOL result = TRUE; + DG_GEN_IDLE_MODE_STATE_T result = DG_GEN_IDLE_MODE_STATE_FLUSH_WATER; - requestNewOperationMode( DG_MODE_STAN ); - return result; } /*********************************************************************//** * @brief - * The handleFlushLinesState function executes the flush lines state of the + * The handleBadFillState function executes the bad fill state of the * generation idle mode state machine. - * @details Inputs: flushLinesVolumeL - * @details Outputs: Integrate volume of water moved through line + * @details Inputs: none + * @details Outputs: badFillState, genIdleState * @return the next state *************************************************************************/ -static DG_GEN_IDLE_MODE_STATE_T handleFlushLinesState( void ) +static DG_GEN_IDLE_MODE_STATE_T handleBadFillState( void ) { - DG_GEN_IDLE_MODE_STATE_T result = DG_GEN_IDLE_MODE_STATE_FLUSH_LINES; - F32 waterFlowRate = getMeasuredROFlowRateLPM(); - F32 waterVolume = ( ( waterFlowRate / SEC_PER_MIN ) / ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ); + DG_GEN_IDLE_MODE_STATE_T result = DG_GEN_IDLE_MODE_STATE_HANDLE_BAD_FILL; + U32 priorSubState = badFillState; - // Integrate volume of water moved through line - flushLinesVolumeL += waterVolume; - - // When enough water volume has flowed to flush the lines, transition to flush water state - if ( flushLinesVolumeL >= getFlushLineVolumeL() ) + // Execute current bad fill state + switch ( badFillState ) { -#ifndef DISABLE_FLOW_CONTROL_TREATMENT - setROPumpTargetFlowRateLPM( TARGET_RO_FLOW_RATE_L, TARGET_RO_PRESSURE_PSI ); -#endif - result = DG_GEN_IDLE_MODE_STATE_FLUSH_WATER; + case DG_HANDLE_BAD_FILL_STATE_START: + badFillState = handleStartState(); + break; + + case DG_HANDLE_BAD_FILL_STATE_FIRST_DRAIN: + badFillState = handleFirstDrainState(); + break; + + case DG_HANDLE_BAD_FILL_STATE_FLUSH_FILL: + badFillState = handleFlushFillState(); + break; + + case DG_HANDLE_BAD_FILL_STATE_SECOND_DRAIN: + badFillState = handleSecondDrainState(); + break; + + case DG_HANDLE_BAD_FILL_STATE_REFILL: + badFillState = handleRefillState( &result ); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_GEN_IDLE_MODE_INVALID_EXEC_STATE, genIdleState ) + badFillState = DG_HANDLE_BAD_FILL_STATE_START; + break; } + if ( priorSubState != badFillState ) + { + setCurrentSubState( badFillState ); + } return result; } /*********************************************************************//** * @brief - * The handleFlushWaterState function executes the flush water state - * of the generation idle mode state machine. + * The handleStartState function executes the start state of the handle bad + * fill state machine. * @details Inputs: none * @details Outputs: none * @return the next state *************************************************************************/ -static DG_GEN_IDLE_MODE_STATE_T handleFlushWaterState( void ) +static DG_GEN_IDLE_MODE_BAD_FILL_STATE_T handleStartState( void ) { - return DG_GEN_IDLE_MODE_STATE_FLUSH_WATER; + DG_GEN_IDLE_MODE_BAD_FILL_STATE_T state = DG_HANDLE_BAD_FILL_STATE_FIRST_DRAIN; + + // Drain the bad filled reservoir first + requestNewOperationMode( DG_MODE_DRAI ); + + return state; } +/*********************************************************************//** + * @brief + * The handleFirstDrainState function executes the first drain state of the + * handle bad fill state machine. + * @details Inputs: none + * @details Outputs: none + * @return the next state + *************************************************************************/ +static DG_GEN_IDLE_MODE_BAD_FILL_STATE_T handleFirstDrainState( void ) +{ + DG_GEN_IDLE_MODE_BAD_FILL_STATE_T state = DG_HANDLE_BAD_FILL_STATE_FIRST_DRAIN; + + // 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; + + // Start the flush fill + startFillCmd( BAD_FLUSH_FILL_TARGET_VOLUME_ML, getTargetFillFlowRateLPM() ); + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleFlushFillState function executes the flush fill state of the + * handle bad fill state machine. + * @details Inputs: none + * @details Outputs: none + * @return the next state + *************************************************************************/ +static DG_GEN_IDLE_MODE_BAD_FILL_STATE_T handleFlushFillState( void ) +{ + DG_GEN_IDLE_MODE_BAD_FILL_STATE_T state = DG_HANDLE_BAD_FILL_STATE_SECOND_DRAIN; + + requestNewOperationMode( DG_MODE_DRAI ); + + return state; +} + +/*********************************************************************//** + * @brief + * The handleSecondDrainState function executes the second drain state of the + * handle bad fill state machine. + * @details Inputs: none + * @details Outputs: none + * @return the next state + *************************************************************************/ +static DG_GEN_IDLE_MODE_BAD_FILL_STATE_T handleSecondDrainState( void ) +{ + 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() ); + + return state; +} + +/*********************************************************************//** + * @brief + * The handleRefillState function executes refill state of the handle bad + * fill state machine. + * @details Inputs: 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( 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; + *idleState = DG_GEN_IDLE_MODE_STATE_START; + + return state; +} + +/*********************************************************************//** + * @brief + * The publishGenIdleSubstates function publishes gen idle + * sub-states at the set interval. + * @details Inputs: handleBadFillFlag, badFillState, targetFillVolumeML, + * dataPublishCounter + * @details Outputs: dataPublishCounter + * @return none + *************************************************************************/ +static void publishGenIdleSubstates( void ) +{ + // publish Gen Idle pump data on interval + if ( ++dataPublishCounter >= getU32OverrideValue( &genIdleDataPublicationInterval ) ) + { + DG_GEN_IDLE_DATA_T data; + + // Populate the data structure for publication + data.badFillSignal = (U32)handleBadFillFlag; + data.badFillState = (U32)badFillState; + data.genIdleState = (U32)getCurrentGenIdleState(); + data.targetFillVolumemL = targetFillVolumeML; + + broadcastData( MSG_ID_DG_GEN_IDLE_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&data, sizeof( DG_GEN_IDLE_DATA_T ) ); + + dataPublishCounter = 0; + } +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testSetBadFillSubstatesPublishIntervalOverride function overrides the + * bad fill sub-states publish interval. + * @details Inputs: badFillSubstatesPublishInterval + * @details Outputs: badFillSubstatesPublishInterval + * @param: value override bad fill sub-states publish interval with (in ms) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetGenIdleSubstatesPublishIntervalOverride( U32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + U32 intvl = value / TASK_GENERAL_INTERVAL; + genIdleDataPublicationInterval.ovData = intvl; + genIdleDataPublicationInterval.override = OVERRIDE_KEY; + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetBadFillSubstatesPublishIntervalOverride function resets the + * override of the bad fill sub-states publish interval. + * @details Inputs: badFillSubstatesPublishInterval + * @details Outputs: badFillSubstatesPublishInterval + * @return TRUE if override reset successful, FALSE if not + *************************************************************************/ +BOOL testResetGenIdleSubstatesPublishIntervalOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + genIdleDataPublicationInterval.override = OVERRIDE_RESET; + genIdleDataPublicationInterval.ovData = genIdleDataPublicationInterval.ovInitData; + result = TRUE; + } + + return result; +} + /**@}*/