Index: firmware/App/Controllers/UVReactors.c =================================================================== diff -u -r86eec09ab556fbd970ddcae9dc622727928ee757 -r7f38146626e566ac94d97d785af7290529992fdd --- firmware/App/Controllers/UVReactors.c (.../UVReactors.c) (revision 86eec09ab556fbd970ddcae9dc622727928ee757) +++ firmware/App/Controllers/UVReactors.c (.../UVReactors.c) (revision 7f38146626e566ac94d97d785af7290529992fdd) @@ -1,9 +1,26 @@ +/************************************************************************** +* +* Copyright (c) 2020-2022 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 UVReactors.c +* +* @author (last) Bill Bracken +* @date (last) 18-Aug-2022 +* +* @author (original) Dara Navaei +* @date (original) 24-Nov-2020 +* +***************************************************************************/ #include "gio.h" #include "reg_het.h" #include "AlarmMgmt.h" #include "Common.h" +#include "MessageSupport.h" #include "PersistentAlarm.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" @@ -17,41 +34,46 @@ // ********** private definitions ********** -#define INLET_UV_REACTOR_ENABLE_PIN 0 ///< Inlet UV reactor GPIO pin number (enable pin). -#define OUTLET_UV_REACTOR_ENABLE_PIN 1 ///< Outlet UV reactor GPIO pin number (enable Pin). -#define INLET_UV_REACTOR_INDICATION_PIN 0x18 ///< Inlet UV reactor N2HET1 pin number (health check). -#define OUTLET_UV_REACTOR_INDICATION_PIN 0x0B ///< Outlet UV reactor N2HET1 pin number (health check). -#define UV_REACTORS_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< UV reactors data publication time interval. -/// Self test wait time after enabling the reactors and before checking for their health in ms. -#define SELF_TEST_DELAY_TIME 1000 -#define MAX_ALLOWED_UNHEALTHY_REACTOR_PERIOD MS_PER_SECOND ///< UV reactors unhealthy state period. +#define INLET_UV_REACTOR_ENABLE_PIN 0 ///< Inlet UV reactor GPIO pin number (enable pin). +#define OUTLET_UV_REACTOR_ENABLE_PIN 1 ///< Outlet UV reactor GPIO pin number (enable Pin). +#define INLET_UV_REACTOR_INDICATION_PIN 0x18 ///< Inlet UV reactor N2HET1 pin number (health check). +#define OUTLET_UV_REACTOR_INDICATION_PIN 0x0B ///< Outlet UV reactor N2HET1 pin number (health check). +#define UV_REACTORS_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< UV reactors data publication time interval. +#define SELF_TEST_DELAY_TIME 1000 ///< Self test wait time after enabling the reactors and before checking for their health in ms. +#define MAX_ALLOWED_UNHEALTHY_REACTOR_PERIOD MS_PER_SECOND ///< UV reactors unhealthy state period. +#define DATA_PUBLISH_COUNTER_START_COUNT 90 ///< Data publish counter start count. +#define UV_REACTORS_ON_NO_FLOW_TIMEOUT_MS ( 2 * MS_PER_SECOND ) ///< UV reactors on with no flow time out in milliseconds. +#define MIN_RO_UV_FLOWRATE_LPM 0.2F ///< Minimum target RO UV flow rate in L/min. + /// UV reactors self test states typedef enum self_tests { - UV_REACTORS_SELF_TEST_OFF = 0, ///< UV reactors self test state off - UV_REACTORS_SELF_TEST_CHECK_HEALTH, ///< UV reactors self test check health - UV_REACTORS_SELF_TEST_COMPLETE, ///< UV reactors self test complete - NUM_OF_UV_REACTORS_SELF_TEST_STATES, ///< Number of UV reactors self test states + UV_REACTORS_SELF_TEST_OFF = 0, ///< UV reactors self test state off. + UV_REACTORS_SELF_TEST_CHECK_HEALTH, ///< UV reactors self test check health. + UV_REACTORS_SELF_TEST_COMPLETE, ///< UV reactors self test complete. + NUM_OF_UV_REACTORS_SELF_TEST_STATES, ///< Number of UV reactors self test states. } UV_REACTORS_SELF_TEST_STATE_T; /// UV reactors exec states typedef enum exec_states { - UV_REACTOR_STATE_OFF = 0, ///< UV reactor state off - UV_REACTOR_STATE_ON, ///< UV reactor state on - NUM_OF_UV_REACTOR_STATES, ///< Number of UV reactor states + UV_REACTOR_STATE_OFF = 0, ///< UV reactor state off. + UV_REACTOR_STATE_ON, ///< UV reactor state on. + NUM_OF_UV_REACTOR_STATES, ///< Number of UV reactor states. } UV_REACTOR_STATE_T; /// UV reactor status typedef struct { - UV_REACTOR_STATE_T execState; ///< UV reactor executive state - PIN_SIGNAL_STATE_T pinSignalState; ///< UV reactor pin signal state - SWITCH_STATES_T switchState; ///< UV reactor turn on/turn off state - U32 reactorEnablePin; ///< UV reactor enable pin of GIO port A - U32 reactorHealthStatusPin; ///< UV reactor status pin of N2HET1 - OVERRIDE_U32_T healthStatus; ///< UV reactor current health status + UV_REACTOR_STATE_T execState; ///< UV reactor executive state. + PIN_SIGNAL_STATE_T pinSignalState; ///< UV reactor pin signal state. + UV_REACTOR_STATES_T switchState; ///< UV reactor turn on/turn off state. + U32 reactorEnablePin; ///< UV reactor enable pin of GIO port A. + U32 reactorHealthStatusPin; ///< UV reactor status pin of N2HET1. + OVERRIDE_U32_T healthStatus; ///< UV reactor current health status. + BOOL isFlowBelowMin; ///< UV reactor flag to indicate the flow is below minimum. + U32 reactorOnWithNoFlowTimer; ///< UV reactor on with no flow start time. } UV_REACTOR_STATUS_T; // ********** private data ********** @@ -63,8 +85,8 @@ static OVERRIDE_U32_T uvReactorsDataPublishInterval = { UV_REACTORS_DATA_PUB_INTERVAL, UV_REACTORS_DATA_PUB_INTERVAL, 0, 0 }; ///< UV reactors data publish interval. -static U32 dataPublishCounter = 0; ///< UV reactors data publish counter. -static U32 selfTestElapsedTime = 0; ///< UV reactors self test elapsed time. +static U32 dataPublishCounter; ///< UV reactors data publish counter. +static U32 selfTestElapsedTime; ///< UV reactors self test elapsed time. // Self test functions static UV_REACTORS_SELF_TEST_STATE_T handleUVReactorsSelfTestOff( void ); @@ -78,15 +100,14 @@ static U32 getReactorHealth( UV_REACTORS_T reactor ); static void setReactorEnableStatus( UV_REACTORS_T reactor, PIN_SIGNAL_STATE_T state ); static void publishUVReactorsData( void ); -static U32 getPublishUVReactorsDataInterval( void ); /*********************************************************************//** * @brief * The initUVReactors function initializes the UV reactors module. * @details Inputs: uvReactorsSelfTestResult, dataPublishCounter, * reactorsStatus, selfTestStates * @details Outputs: uvReactorsSelfTestResult, dataPublishCounter, - * reactorsStatus, selfTestStates + * reactorsStatus, selfTestStates, selfTestElapsedTime * @return none *************************************************************************/ void initUVReactors( void ) @@ -95,7 +116,8 @@ uvReactorsSelfTestResult = SELF_TEST_STATUS_IN_PROGRESS; uvReactorsSelfTestStates = UV_REACTORS_SELF_TEST_OFF; - dataPublishCounter = 0; + dataPublishCounter = DATA_PUBLISH_COUNTER_START_COUNT; + selfTestElapsedTime = 0; // Initialize the UV reactors. These values are specific to the inlet and outlet reactor // so they cannot be in a for loop @@ -111,6 +133,8 @@ reactorsStatus[ reactor ].pinSignalState = PIN_SIGNAL_LOW; reactorsStatus[ reactor ].execState = UV_REACTOR_STATE_OFF; reactorsStatus[ reactor ].switchState = TURN_OFF; + + setReactorEnableStatus( reactor, PIN_SIGNAL_LOW ); } initPersistentAlarm( ALARM_ID_UV_REACTOR_NOT_HEALTHY, MAX_ALLOWED_UNHEALTHY_REACTOR_PERIOD, MAX_ALLOWED_UNHEALTHY_REACTOR_PERIOD ); @@ -200,15 +224,7 @@ // Check if the reactor selected is in range if ( reactor < NUM_OF_UV_REACTORS ) { - // Check if the health is in override or not - if ( reactorsStatus[ reactor ].healthStatus.override == OVERRIDE_KEY ) - { - health = (UV_REACTORS_HEALTH_STATUS_T)reactorsStatus[ reactor ].healthStatus.ovData; - } - else - { - health = (UV_REACTORS_HEALTH_STATUS_T)reactorsStatus[ reactor ].healthStatus.data; - } + health = (UV_REACTORS_HEALTH_STATUS_T)getU32OverrideValue( &reactorsStatus[ reactor ].healthStatus ); } else { @@ -311,7 +327,7 @@ BOOL isOutletHealthy = (BOOL)getReactorHealth( OUTLET_UV_REACTOR ); // Check if both of them are healthy and if not, raise an alarm - if ( ( TRUE == isInletHealthy ) &&( TRUE == isOutletHealthy ) ) + if ( ( TRUE == isInletHealthy ) && ( TRUE == isOutletHealthy ) ) { uvReactorsSelfTestResult = SELF_TEST_STATUS_PASSED; } @@ -352,17 +368,22 @@ { UV_REACTOR_STATE_T state = UV_REACTOR_STATE_OFF; - // Set the health status to be off. When the reactor is off, it does not report - // its health status - reactorsStatus[reactor].healthStatus.data = (U32)UV_REACTOR_OFF; + // Set the health status to be off. When the reactor is off, it does not report its health status + reactorsStatus[ reactor ].healthStatus.data = (U32)UV_REACTOR_OFF; - // If the a reactor is requested to be on and it is off, turn it on - // and change the state - if( TURN_ON == reactorsStatus[ reactor ].switchState ) + // Check if the a reactor is requested to be on and it is off + if ( TURN_ON == reactorsStatus[ reactor ].switchState ) { - setReactorEnableStatus( reactor, PIN_SIGNAL_HIGH ); + // Check if the flow is below minimum + reactorsStatus[ reactor ].isFlowBelowMin = ( getMeasuredROFlowRateLPM() < MIN_RO_UV_FLOWRATE_LPM ? TRUE : FALSE ); - state = UV_REACTOR_STATE_ON; + // If the flow is no longer below minimum and the reactor is requested to be on, turn it back on + if ( FALSE == reactorsStatus[ reactor ].isFlowBelowMin ) + { + setReactorEnableStatus( reactor, PIN_SIGNAL_HIGH ); + + state = UV_REACTOR_STATE_ON; + } } return state; @@ -386,19 +407,41 @@ // Get the health of the reactor (override or non-override) and decide the status BOOL isReactorUnhealthy = ( UV_REACTOR_HEALTHY == getUVReactorHealth( reactor ) ? FALSE : TRUE ); - checkPersistentAlarm( ALARM_ID_UV_REACTOR_NOT_HEALTHY, isReactorUnhealthy, (U32)reactor, MAX_ALLOWED_UNHEALTHY_REACTOR_PERIOD ); +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_UV_REACTORS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + checkPersistentAlarm( ALARM_ID_UV_REACTOR_NOT_HEALTHY, isReactorUnhealthy, (U32)reactor, MAX_ALLOWED_UNHEALTHY_REACTOR_PERIOD ); + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_UV_REACTOR_NOT_HEALTHY, isReactorUnhealthy) ) + { + reactorsStatus[ reactor ].switchState = TURN_OFF; + } + } - // Check if the alarm has been active - if( isAlarmActive( ALARM_ID_UV_REACTOR_NOT_HEALTHY ) ) + // Check if the flow is below minimum + BOOL isFlowBelowMin = ( getMeasuredROFlowRateLPM() < MIN_RO_UV_FLOWRATE_LPM ? TRUE : FALSE ); + + if ( TRUE == isFlowBelowMin ) { - reactorsStatus[ reactor ].switchState = TURN_OFF; + // If the flow is below minimum for the first time, start the timer + if ( FALSE == reactorsStatus[ reactor ].isFlowBelowMin ) + { + reactorsStatus[ reactor ].isFlowBelowMin = TRUE; + reactorsStatus[ reactor ].reactorOnWithNoFlowTimer = getMSTimerCount(); + } + else if ( TRUE == didTimeout( reactorsStatus[ reactor ].reactorOnWithNoFlowTimer, UV_REACTORS_ON_NO_FLOW_TIMEOUT_MS ) ) + { + // If the flow is below minimum and the allowed time has elapsed, set the reactor's signal to be low and set its state + // to be off. + setReactorEnableStatus( reactor, PIN_SIGNAL_LOW ); + state = UV_REACTOR_STATE_OFF; + } } // Check if it has been requested to turn off a reactor - if( TURN_OFF == reactorsStatus[ reactor ].switchState ) + if ( TURN_OFF == reactorsStatus[ reactor ].switchState ) { setReactorEnableStatus( reactor, PIN_SIGNAL_LOW ); - state = UV_REACTOR_STATE_OFF; } @@ -439,42 +482,24 @@ /*********************************************************************//** * @brief - * The getPublishValvesDataInterval function gets the data publish interval - * @details Inputs: uvReactorsDataPublishInterval - * @details Outputs: none - * @return returns data publish interval - *************************************************************************/ -static U32 getPublishUVReactorsDataInterval( void ) -{ - U32 result = uvReactorsDataPublishInterval.data; - - if ( OVERRIDE_KEY == uvReactorsDataPublishInterval.override ) - { - result = uvReactorsDataPublishInterval.ovData; - } - - return result; -} - -/*********************************************************************//** - * @brief * The publishUVReactorsData function publishes the UV reactors data. * @details Inputs: dataPublishCounter, reactorsStatus * @details Outputs: dataPublishCounter * @return none *************************************************************************/ static void publishUVReactorsData( void ) { - if ( ++dataPublishCounter > getPublishUVReactorsDataInterval() ) + if ( ++dataPublishCounter > getU32OverrideValue( &uvReactorsDataPublishInterval ) ) { UV_REACTORS_DATA_T uvReactorsData; + // Publish the reactors health status uvReactorsData.inletUVReactorHealthStatus = (U32)getUVReactorHealth( INLET_UV_REACTOR ); uvReactorsData.outletUVReactorHealthStatus = (U32)getUVReactorHealth( OUTLET_UV_REACTOR ); uvReactorsData.inletUVReactorState = (U32)reactorsStatus[ INLET_UV_REACTOR ].execState; uvReactorsData.outletUVReactorState = (U32)reactorsStatus[ OUTLET_UV_REACTOR ].execState; - broadcastUVReactorsData( &uvReactorsData ); + broadcastData( MSG_ID_DG_UV_REACTORS_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&uvReactorsData, sizeof( UV_REACTORS_DATA_T ) ); dataPublishCounter = 0; }