/************************************************************************** * * Copyright (c) 2025-2025 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 FlushConcentrate.c * * @author (last) “rkallala” * @date (last) 24-Oct-2025 * * @author (original) Michael Garthwaite * @date (original) 08-Sep-2025 * ***************************************************************************/ #include "Conductivity.h" #include "BoostPump.h" #include "FlowSensor.h" #include "FlushConcentrate.h" #include "FPOperationModes.h" #include "Level.h" #include "MessageSupport.h" #include "Messaging.h" #include "PermeateTank.h" #include "Pressure.h" #include "ROPump.h" #include "TaskGeneral.h" #include "Timers.h" #include "Valves.h" /** * @addtogroup FPConcentrateFlush * @{ */ // ********** private definitions ********** #define CONCENTRATE_FLUSH_MAX_TIMEOUT ( 600 * MS_PER_SECOND ) ///< Max override timeout for 10 minutes #define CONCENTRATE_FLUSH_DATA_PUBLISH_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the gen water mode data published. #define CONCENTRATE_FLUSH_TIMEOUT ( 30 * MS_PER_SECOND ) ///< Concentrate flush timer (in ms) #define CONCENTRATE_FLUSH_RO_PUMP_TGT_PWM 0.75F ///< target in PWM % for the RO pump during concentrate flush. #define CONCENTRATE_FLUSH_BOOST_PUMP_TGT_PSI 25 ///< Pressure target in PSI for the boost pump during concentrate flush. #define CONCENTRATE_FLUSH_VOLUME_THRESHOLD_ML 1000.0F ///< Integrated volume threshold in ml #define CONCENTRATE_FLUSH_VOLUME_THRESHOLD_PCT 0.9F ///< Integrated volume threshold percentage #define CONCENTRATE_FLUSH_VOLUME_THRESHOLD CONCENTRATE_FLUSH_VOLUME_THRESHOLD_ML * CONCENTRATE_FLUSH_VOLUME_THRESHOLD_PCT ///< alarm threshold for integrated volume #define CONCENTRATE_FLUSH_WAIT_FOR_TANK_FULL_TIMEOUT ( 60 * MS_PER_SECOND ) ///< Concentrate flush wait for tank full timer (in ms) #define CONCENTRATE_FLUSH_WAIT_FOR_TANK_FULL_TGT_FLOW 700 ///< target flow rate for waiting for tank state #define CONCENTRATE_FLUSH_BOOST_PUMP_TGT_PSI 25 ///< Pressure target in PSI for the boost pump during concentrate flush. #define MIN_BOOST_PUMP_DUTY_CYCLE_PCT 0.5F ///< Minimum duty cycle value for boost pump during open loop control // ********** private data ********** static FP_CONC_FLUSH_STATE_T concentrateFlushState; ///< Currently active Concentrate flush state. static U32 concentrateFlushDataPublicationTimerCounter; ///< Used to schedule Concentrate flush data publication to CAN bus. static OVERRIDE_U32_T concentrateFlushDataPublishInterval; ///< Concentrate Flush mode data publish interval. static OVERRIDE_U32_T concentrateFlushTimeout; ///< Concentrate Flush timeout value static U32 concentrateFlushTimer; ///< Concentrate Flush timeout timer static BOOL pendingStartConcentrateFlushRequest; ///< signal to start flushing. static BOOL isFlushComplete; ///< Concentrate Flush complete BOOL static BOOL isTankFilled; ///< Concentrate tank filled in permeate flush state // ********** private function prototypes ********** static void publishConcentrateFlushData( void ); static FP_CONC_FLUSH_STATE_T handleConcentrateFlushProgressState( void ); static FP_CONC_FLUSH_STATE_T handleConcentrateFlushPausedState( void ); static void setConcentrateFlushTransition( FP_CONC_FLUSH_STATE_T state ); static U32 getConcentrateFlushTimeout( void ); static U32 getConcentrateFlushPublishInterval( void ); /*********************************************************************//** * @brief * The initConcentrateFlush function initializes the Concentrate flush unit. * @details \b Inputs: none * @details \b Outputs: Concentrate flush unit initialized * @return none *************************************************************************/ void initConcentrateFlush( void ) { concentrateFlushState = CONC_FLUSH_PAUSED; concentrateFlushDataPublishInterval.data = CONCENTRATE_FLUSH_DATA_PUBLISH_INTERVAL; concentrateFlushDataPublishInterval.ovData = CONCENTRATE_FLUSH_DATA_PUBLISH_INTERVAL; concentrateFlushDataPublishInterval.ovInitData = 0; concentrateFlushDataPublishInterval.override = OVERRIDE_RESET; concentrateFlushTimeout.data = CONCENTRATE_FLUSH_TIMEOUT; concentrateFlushTimeout.ovData = CONCENTRATE_FLUSH_TIMEOUT; concentrateFlushTimeout.ovInitData = 0; concentrateFlushTimeout.override = OVERRIDE_RESET; concentrateFlushDataPublicationTimerCounter = 0; concentrateFlushTimer = 0; isFlushComplete = FALSE; pendingStartConcentrateFlushRequest = FALSE; isTankFilled = FALSE; } /*********************************************************************//** * @brief * The execConcentrateFlush function executes the Concentrate flush state machine * and publishes Concentrate flush data. * @details \b Inputs: concentrateFlushState * @details \b Outputs: concentrateFlushState * @details \b Alarm: ALARM_ID_FP_SOFTWARE_FAULT if in invalid flush state * @return none *************************************************************************/ void execConcentrateFlush( void ) { FP_CONC_FLUSH_STATE_T prevState = concentrateFlushState; switch ( concentrateFlushState ) { case CONC_FLUSH_IN_PROGRESS: concentrateFlushState = handleConcentrateFlushProgressState(); break; case CONC_FLUSH_PAUSED: concentrateFlushState = handleConcentrateFlushPausedState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FP_INVALID_CONCENTRATE_FLUSH_STATE, (U32)concentrateFlushState ) concentrateFlushState = CONC_FLUSH_PAUSED; break; } if ( prevState != concentrateFlushState ) { setConcentrateFlushTransition( concentrateFlushState ); } // publish Concentrate flush data on interval publishConcentrateFlushData(); } /*********************************************************************//** * @brief * The handleConcentrateFlushProgressState handles the in progress state of Concentrate flush * @details \b Inputs: concentrateFlushTimer * @details \b Outputs: isFlushComplete * @return the next state of Concentrate flush state *************************************************************************/ static FP_CONC_FLUSH_STATE_T handleConcentrateFlushProgressState( void ) { FP_CONC_FLUSH_STATE_T state = CONC_FLUSH_IN_PROGRESS; LEVEL_STATE_T level = getLevelStatus( P25_LEVL ); // if ( TRUE == 1 ) )// TODO Alarm and Stop State Rework // { // state = CONC_FLUSH_PAUSED; // } if ( TRUE == didTimeout( concentrateFlushTimer, getConcentrateFlushTimeout() ) ) { isFlushComplete = TRUE; state = CONC_FLUSH_PAUSED; } // Manual control of Permeate tank to prevent over fill. if ( LEVEL_STATE_HIGH == level ) { setValveState( M4_VALV, VALVE_STATE_CLOSED ); if ( TRUE == isBoostPumpInstalled() ) { F32 currentDutyCyclePct = getCurrentBoostPumpDutyCyclePCT() > MIN_BOOST_PUMP_DUTY_CYCLE_PCT ? getCurrentBoostPumpDutyCyclePCT(): MIN_BOOST_PUMP_DUTY_CYCLE_PCT; setBoostPumpTargetDutyCycle( currentDutyCyclePct ); isTankFilled = TRUE; } } else if ( LEVEL_STATE_LOW == level ) { setValveState( M4_VALV, VALVE_STATE_OPEN ); // set boost pump to closed loop when M4 closed. Added Tank fill check to avoid reset during initial transition if ( ( TRUE == isBoostPumpInstalled() ) && ( TRUE == isTankFilled ) ) { setBoostPumpTargetPressure( CONCENTRATE_FLUSH_BOOST_PUMP_TGT_PSI ); isTankFilled = FALSE; } } return state; } /*********************************************************************//** * @brief * The handleConcentrateFlushPausedState handles the paused state of Concentrate flush * @details \b Inputs: pendingStartConcentrateFlushRequest * @details \b Outputs: isFlushComplete, pendingStartConcentrateFlushRequest * @return the next state of Concentrate flush state *************************************************************************/ static FP_CONC_FLUSH_STATE_T handleConcentrateFlushPausedState( void ) { FP_CONC_FLUSH_STATE_T state = CONC_FLUSH_PAUSED; if ( TRUE == pendingStartConcentrateFlushRequest ) { isFlushComplete = FALSE; pendingStartConcentrateFlushRequest = FALSE; state = CONC_FLUSH_IN_PROGRESS; } return state; } /*********************************************************************//** * @brief * The setConcentrateFlushTransition function sets the actuators and variables * for the state transition in Concentrate flush mode. * @details Inputs: Valve states, Pump speed * @details Outputs: Actuate valves, pumps as desired. * @param state Concentrate flush state enum * @return none *************************************************************************/ static void setConcentrateFlushTransition( FP_CONC_FLUSH_STATE_T state ) { // Execute on running state switch( state ) { case CONC_FLUSH_IN_PROGRESS: setValveState( M4_VALV, VALVE_STATE_OPEN ); setValveState( M12_VALV, VALVE_STATE_OPEN ); setValveState( P6_VALV, VALVE_STATE_CLOSED ); setValveState( P11_VALV, VALVE_STATE_OPEN ); setValveState( P33_VALV, VALVE_STATE_CLOSED ); setValveState( P34_VALV, VALVE_STATE_CLOSED ); setValveState( P37_VALV, VALVE_STATE_OPEN ); setValveState( P39_VALV, VALVE_STATE_OPEN ); if ( TRUE == isBoostPumpInstalled() ) { setBoostPumpTargetPressure( CONCENTRATE_FLUSH_BOOST_PUMP_TGT_PSI ); } setROPumpTargetDutyCycle( CONCENTRATE_FLUSH_RO_PUMP_TGT_PWM, TRUE ); concentrateFlushTimer = getMSTimerCount(); break; case CONC_FLUSH_PAUSED: // Stop pumps and close only if we alarm ( pause ) during flush. if ( FALSE == isConcentrateFlushComplete() ) { setValveState( M4_VALV, VALVE_STATE_CLOSED ); setValveState( M12_VALV, VALVE_STATE_CLOSED ); setValveState( P6_VALV, VALVE_STATE_CLOSED ); setValveState( P11_VALV, VALVE_STATE_CLOSED ); setValveState( P33_VALV, VALVE_STATE_CLOSED ); setValveState( P34_VALV, VALVE_STATE_CLOSED ); setValveState( P37_VALV, VALVE_STATE_CLOSED ); setValveState( P39_VALV, VALVE_STATE_CLOSED ); if ( TRUE == isBoostPumpInstalled() ) { signalBoostPumpHardStop(); } signalROPumpHardStop(); } break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FP_INVALID_CONCENTRATE_FLUSH_STATE, state ) break; } } /*********************************************************************//** * @brief * The signalStartConcentrateFlush function signals the FP to start Concentrate flush. * @details \b Inputs: none * @details \b Outputs: pendingStartConcentrateFlushRequest * @return TRUE if the start signal is set, FALSE if not *************************************************************************/ BOOL signalStartConcentrateFlush( void ) { BOOL result = FALSE; if ( CONC_FLUSH_PAUSED == getCurrentConcentrateFlushState() ) { result = TRUE; pendingStartConcentrateFlushRequest = TRUE; } return result; } /*********************************************************************//** * @brief * The resetFilterFlushSignals function resets the signal values for * FP filter flush. * @details \b Inputs: none * @details \b Outputs: pendingStartFilterFlushRequest, isFlushComplete * @return none *************************************************************************/ void resetConcentrateFlushSignals( void ) { pendingStartConcentrateFlushRequest = FALSE; isFlushComplete = FALSE; } /*********************************************************************//** * @brief * The getCurrentConcentrateFlushState function returns the current state of * Concentrate flush. * @details \b Inputs: concentrateFlushState * @details \b Outputs: none * @return the current state of Concentrate flush *************************************************************************/ FP_CONC_FLUSH_STATE_T getCurrentConcentrateFlushState( void ) { return concentrateFlushState; } /*********************************************************************//** * @brief * The isConcentrateFlushComplete function returns isConcentrateFlushComplete. * @details \b Inputs: isFlushComplete * @details \b Outputs: none * @return TRUE if concentrate flush is complete, FALSE if not. *************************************************************************/ BOOL isConcentrateFlushComplete( void ) { return isFlushComplete; } /*********************************************************************//** * @brief * The getConcentrateFlushTimeout function gets the generate water * mode data publish interval. * @details \b Inputs: ConcentrateFlushTimeOut * @details \b Outputs: none * @return the concentrate flush timeout period in ms. *************************************************************************/ static U32 getConcentrateFlushTimeout( void ) { U32 result = getU32OverrideValue( &concentrateFlushTimeout ); return result; } /*********************************************************************//** * @brief * The getConcentrateFlushPublishInterval function gets the Concentrate flush * mode data publish interval. * @details \b Inputs: concentrateFlushDataPublishInterval * @details \b Outputs: none * @return the interval at Concentrate flush mode data being published. *************************************************************************/ static U32 getConcentrateFlushPublishInterval( void ) { U32 result = getU32OverrideValue( &concentrateFlushDataPublishInterval ); return result; } /*********************************************************************//** * @brief * The publishConcentrateFlushData function broadcasts the Concentrate flush * mode data at defined interval. * @details \b Inputs: concentrateFlushDataPublicationTimerCounter * @details \b Outputs: fp Concentrate flush data broadcast message sent * @details \b Message \b Sent: MSG_ID_FP_CONCENTRATE_FLUSH_DATA to publish the * Concentrate flush mode data. * @return none *************************************************************************/ static void publishConcentrateFlushData( void ) { if ( ++concentrateFlushDataPublicationTimerCounter >= getConcentrateFlushPublishInterval() ) { CONC_FLUSH_DATA_T data; data.concentrateFlushExecState = (U32)getCurrentConcentrateFlushState(); broadcastData( MSG_ID_FP_CONCENTRATE_FLUSH_DATA, COMM_BUFFER_OUT_CAN_FP_BROADCAST, (U08*)&data, sizeof( CONC_FLUSH_DATA_T ) ); concentrateFlushDataPublicationTimerCounter = 0; } } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testConcentrateFlushDataPublishIntervalOverride function overrides the * FP Concentrate flush mode data publish interval. * @details \b Inputs: concentrateFlushDataPublishInterval * @details \b Outputs: concentrateFlushDataPublishInterval * @param Override message from Dialin which includes the interval * (in ms) to override the FP Concentrate flush data publish interval to. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testConcentrateFlushDataPublishIntervalOverride( MESSAGE_T *message ) { BOOL result = u32BroadcastIntervalOverride( message, &concentrateFlushDataPublishInterval, TASK_GENERAL_INTERVAL ); return result; } /*********************************************************************//** * @brief * The testConcentrateFlushTimerOverride function overrides the * FP Concentrate flush timeout value. * @details \b Inputs: concentrateFlushTimeout * @details \b Outputs: concentrateFlushTimeout * @param Override message from Dialin which includes the interval * (in ms) to override the FP Concentrate flush timeout to. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testConcentrateFlushTimerOverride( MESSAGE_T *message ) { BOOL result = u32Override( message, &concentrateFlushTimeout, 0, CONCENTRATE_FLUSH_MAX_TIMEOUT ); return result; } /**@}*/