/************************************************************************** * * Copyright (c) 2024-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 ModeWaterGen.c * * @author (last) Michael Garthwaite * @date (last) 28-Feb-2025 * * @author (original) Michael Garthwaite * @date (original) 28-Feb-2025 * ***************************************************************************/ #include "DDInterface.h" #include "Level.h" #include "ModeStandby.h" #include "ModeWaterGen.h" #include "ModeWaterPreGen.h" #include "MessageSupport.h" #include "Messaging.h" #include "OperationModes.h" #include "TaskGeneral.h" #include "Timers.h" #include "Valves.h" /** * @addtogroup FPGenWaterMode * @{ */ // ********** private definitions ********** #define GEN_WATER_DATA_PUBLISH_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the gen water mode data published. #define GEN_WATER_TIMEOUT_MS ( 6 * MS_PER_SECOND ) ///< state switch timeout (in ms) // ********** private data ********** static RO_GENW_MODE_STATE_T genWaterState; ///< Currently active generate water state. static U32 genWaterDataPublicationTimerCounter; ///< Used to schedule generate water data publication to CAN bus. static OVERRIDE_U32_T genWaterDataPublishInterval; ///< Generate water mode data publish interval. static U32 stateDelayTime; ///< Time stamp to track delay before valve switch. static U32 pendingStartGenRequest; ///< Flag indicating DD has requested RO start the generate permeate. // ********** private function prototypes ********** static void publishGenWModeData( void ); static RO_GENW_MODE_STATE_T handleGenWStartState( void ); static RO_GENW_MODE_STATE_T handleGenWTankFullState( void ); static RO_GENW_MODE_STATE_T handleGenWTankLowState( void ); static void setModeGenWTransition( RO_GENW_MODE_STATE_T state ); /*********************************************************************//** * @brief * The initGenWaterMode function initializes the water generation mode unit. * @details \b Inputs: none * @details \b Outputs: Gen water mode unit initialized * @return none *************************************************************************/ void initGenWaterMode( void ) { genWaterState = RO_GENW_STATE_START; genWaterDataPublishInterval.data = GEN_WATER_DATA_PUBLISH_INTERVAL; genWaterDataPublishInterval.ovData = GEN_WATER_DATA_PUBLISH_INTERVAL; genWaterDataPublishInterval.ovInitData = 0; genWaterDataPublishInterval.override = OVERRIDE_RESET; genWaterDataPublicationTimerCounter = 0; stateDelayTime = 0; pendingStartGenRequest = 0; } /*********************************************************************//** * @brief * The transitionToGenWaterMode function prepares for transition to gen * permeate mode. * @details \b Inputs: none * @details \b Outputs: none * @return initial state *************************************************************************/ U32 transitionToGenWaterMode( void ) { initGenWaterMode(); setCurrentSubState( genWaterState ); return genWaterState; } /*********************************************************************//** * @brief * The execGenWaterMode function executes the Gen water mode state machine. * @details \b Inputs: none * @details \b Outputs: Gen water mode state machine executed * @details \b Alarm: ALARM_ID_RO_SOFTWARE_FAULT when wrong gen water state invoked. * @return current state. *************************************************************************/ U32 execGenWaterMode( void ) { LEVEL_STATE_T level = getLevelStatus(); if ( LEVEL_STATE_ILLEGAL == level ) { // TODO: Raise illegal level alarm } // execute current gen water state switch ( genWaterState ) { case RO_GENW_STATE_START: genWaterState = handleGenWStartState(); break; case RO_GENW_TANK_LOW_STATE: genWaterState = handleGenWTankLowState(); break; case RO_GENW_TANK_FULL_STATE: genWaterState = handleGenWTankFullState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_RO_SOFTWARE_FAULT, SW_FAULT_ID_RO_INVALID_GENW_STATE, genWaterState ) break; } //Publish Gen water mode data publishGenWModeData(); return genWaterState; } /*********************************************************************//** * @brief * The setModeGenPWaterTransition function sets the actuators and variables * for the state transition in generate water mode. * @details Inputs: Valve states, Pump speed * @details Outputs: Actuate valves, pumps as desired. * @param state gen water state enum * @return none *************************************************************************/ static void setModeGenWTransition( RO_GENW_MODE_STATE_T state ) { // Execute on running state switch( state ) { case RO_GENW_STATE_START: // Do nothing break; case RO_GENW_TANK_LOW_STATE: setValveState( M4_VALV,VALVE_STATE_OPEN ); setValveState( M7_VALV,VALVE_STATE_CLOSED ); setValveState( P6_VALV,VALVE_STATE_CLOSED ); setValveState( P39_VALV,VALVE_STATE_OPEN ); setValveState( P11_VALV, VALVE_STATE_OPEN ); break; case RO_GENW_TANK_FULL_STATE: //set setValveState( M4_VALV,VALVE_STATE_CLOSED ); setValveState( M7_VALV,VALVE_STATE_CLOSED ); setValveState( P6_VALV,VALVE_STATE_CLOSED ); setValveState( P39_VALV,VALVE_STATE_OPEN ); setValveState( P11_VALV, VALVE_STATE_CLOSED ); stateDelayTime = getMSTimerCount(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_RO_SOFTWARE_FAULT, SW_FAULT_ID_RO_INVALID_GENW_STATE, state ) break; } } /*********************************************************************//** * @brief * The handleGenWStartState handles the initial state of gen water. * @details \b Inputs: none * @details \b Outputs: none * @return the next state of gen water mode *************************************************************************/ static RO_GENW_MODE_STATE_T handleGenWStartState( void ) { RO_GENW_MODE_STATE_T state = RO_GENW_STATE_START; LEVEL_STATE_T level = getLevelStatus(); if ( LEVEL_STATE_HIGH == level ) { setModeGenWTransition( RO_GENW_TANK_FULL_STATE ); state = RO_GENW_TANK_FULL_STATE; } else if ( ( LEVEL_STATE_MEDIUM == level ) || ( LEVEL_STATE_LOW == level ) ) { setModeGenWTransition( RO_GENW_TANK_LOW_STATE ); state = RO_GENW_TANK_LOW_STATE; } return state; } /*********************************************************************//** * @brief * The handleGenWTankLowState handles the low water state of gen water. * @details \b Inputs: none * @details \b Outputs: none * @return the next state of gen water mode *************************************************************************/ static RO_GENW_MODE_STATE_T handleGenWTankLowState( void ) { RO_GENW_MODE_STATE_T state = RO_GENW_TANK_LOW_STATE; LEVEL_STATE_T level = getLevelStatus(); if ( LEVEL_STATE_HIGH == level ) { setModeGenWTransition( RO_GENW_TANK_FULL_STATE ); state = RO_GENW_TANK_FULL_STATE; } else if ( level <= LEVEL_STATE_MEDIUM ) { // expected state. No action required. // If level is low we still want to fill. } return state; } /*********************************************************************//** * @brief * The handleGenWTankFullState handles the high water state of gen permeate. * @details \b Inputs: stateDelayTime * @details \b Outputs: none * @return the next state of gen permeate mode *************************************************************************/ static RO_GENW_MODE_STATE_T handleGenWTankFullState( void ) { RO_GENW_MODE_STATE_T state = RO_GENW_TANK_FULL_STATE; LEVEL_STATE_T level = getLevelStatus(); if ( LEVEL_STATE_LOW == level ) { // TODO: Turn off heater. } else if ( ( level >= LEVEL_STATE_MEDIUM ) && ( TRUE == didTimeout( stateDelayTime, GEN_WATER_TIMEOUT_MS ) ) ) { setModeGenWTransition( RO_GENW_TANK_LOW_STATE ); state = RO_GENW_TANK_LOW_STATE; } return state; } /** * *******************************************************************//** * @brief * The getCurrentGenWaterState function returns the current state of the * gen water mode. * @details \b Inputs: genWaterState * @details \b Outputs: genWaterState * @return the current state of gen water mode *************************************************************************/ RO_GENW_MODE_STATE_T getCurrentGenWaterState( void ) { return genWaterState; } /*********************************************************************//** * @brief * The getGenWaterDataPublishInterval function gets the generate water * mode data publish interval. * @details \b Inputs: genWaterDataPublishInterval * @details \b Outputs: none * @return the interval at generate water mode data being published. *************************************************************************/ static U32 getGenWaterDataPublishInterval( void ) { U32 result = getU32OverrideValue( &genWaterDataPublishInterval ); return result; } /*********************************************************************//** * @brief * The publishGenWModeData function broadcasts the generate water * mode data at defined interval. * @details \b Inputs: genDialysateDataPublicationTimerCounter * @details \b Outputs: DD generate water data broadcast message sent * @details \b Message \Sent: MSG_ID_RO_GEN_WATER_MODE_DATA to publish the * generate water mode data. * @return none *************************************************************************/ static void publishGenWModeData( void ) { if ( ++genWaterDataPublicationTimerCounter >= getGenWaterDataPublishInterval() ) { GEN_WATER_MODE_DATA_T data; data.genWaterExecState = (U32)getCurrentGenWaterState(); data.setFlowRate = (F32)getDDPermeateFlowRate(); broadcastData( MSG_ID_RO_GEN_WATER_MODE_DATA, COMM_BUFFER_OUT_CAN_RO_BROADCAST, (U08*)&data, sizeof( GEN_WATER_MODE_DATA_T ) ); genWaterDataPublicationTimerCounter = 0; } } /*********************************************************************//** * @brief * The requestGenWaterStart function handles an DD request to start (go to gen permeate mode). * @details \b Inputs: preGenWState * @details \b Outputs: pendingStartGenRequest * @return TRUE if request accepted, FALSE if not. *************************************************************************/ BOOL requestGenWaterStart( void ) { BOOL result = FALSE; if ( RO_PRE_GENW_STATE_COMPLETE == getCurrentPreGenWState() ) { result = TRUE; pendingStartGenRequest = TRUE; } return result; } /*********************************************************************//** * @brief * The requestGenWaterStop function handles an DD request to stop (go to standby mode). * @details \b Inputs: none * @details \b Outputs: pendingStartGenRequest * @return TRUE if request accepted, FALSE if not. *************************************************************************/ BOOL requestGenWaterStop( void ) { BOOL result = TRUE; pendingStartGenRequest = FALSE; requestNewOperationMode( RO_MODE_STAN ); return result; } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testROGenWaterDataPublishIntervalOverride function overrides the * DD generate water mode data publish interval. * @details \b Inputs: genWaterDataPublishInterval * @details \b Outputs: genWaterDataPublishInterval * @param Override message from Dialin which includes the interval * (in ms) to override the RO generate water data publish interval to. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testROGenWaterDataPublishIntervalOverride( MESSAGE_T *message ) { BOOL result = u32BroadcastIntervalOverride( message, &genWaterDataPublishInterval, TASK_GENERAL_INTERVAL ); return result; } /**@}*/