/************************************************************************** * * 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 WaterQualityMonitor.c * * @author (last) Sean Nash * @date (last) 21-Nov-2024 * * @author (original) Sean Nash * @date (original) 21-Nov-2024 * ***************************************************************************/ #include "Conductivity.h" #include "Flow.h" #include "ModeStandby.h" #include "OperationModes.h" #include "PersistentAlarm.h" #include "Pressure.h" #include "SystemCommFP.h" #include "TaskPriority.h" #include "Temperature.h" #include "WaterQualityMonitor.h" /** * @addtogroup WaterQualityMonitor * @{ */ // ********** private definitions ********** #define TEMP_SENSORS_DATA_PUBLISH_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Temperature sensors publish data time interval. #define DATA_PUBLISH_COUNTER_START_COUNT 30 ///< Data publish counter start count. #define INLET_TEMPERATURE_LOW_THRESHOLD_C 5.0F ///< Minimum allowed Inlet temperature in C. #define INLET_TEMPERATURE_HIGH_THRESHOLD_C 30.0F ///< Maximum allowed Inlet temperature in C. #define INLET_TEMPERATURE_PERSISTENCE_TIMER_MS ( 5 * MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Persistence timer to trigger alarm in ms. #define INLET_TEMPERATURE_PERSISTENCE_CLEAR_MS ( 5 * MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Persistence timer to clear alarm in ms. #define MAX_INLET_RO_PUMP_PRESSURE_WARNING_PSIG 120.0F ///< Maximum allowed Input pressure to the RO membrane. #define MIN_INLET_WATER_PRESSURE_WARNING_LOW_PSIG 30.0F ///< Minimum allowed Input low pressure value in psig without boost pump. #define MAX_INLET_WATER_PRESSURE_WARNING_HIGH_PSIG 80.0F ///< Maximum allowed Input high pressure value in psig without boost pump. #define MIN_INLET_WATER_PRESSURE_WARNING_BOOST_LOW_PSIG 10.0F ///< Minimum allowed Input low pressure value in psig with boost pump. #define MAX_INLET_WATER_PRESSURE_WARNING_BOOST_HIGH_PSIG 80.0F ///< Maximum allowed Input high pressure value in psig with boost pump. #define MIN_PRESSURE_RELIEF_WARNING_LOW_PSIG 13.0F ///< Minimum pressure relief warning in psi #define MAX_PRESSURE_RELIEF_WARNING_HIGH_PSIG 17.0F ///< Maximum pressure relief warning in psi #define INLET_WATER_PRES_OUT_OF_RANGE_TIMEOUT_MS ( 5 * MS_PER_SECOND ) ///< Persistence period for pressure out of range error in milliseconds. #define INLET_WATER_PRES_OUT_OF_RANGE_CLEAR_MS ( 5 * MS_PER_SECOND ) ///< Persistence period for pressure out of range clear in milliseconds. #define INLET_WATER_PRES_RELIEF_OUT_OF_RANGE_TIMEOUT_MS ( 5 * MS_PER_SECOND ) ///< Persistence period for pressure out of range error in milliseconds. #define INLET_WATER_PRES_RELIEF_OUT_OF_RANGE_CLEAR_MS ( 5 * MS_PER_SECOND ) ///< Persistence period for pressure out of range clear in milliseconds. #define OUTLET_CONDUCTIVITY_HIGH_THRESHOLD_US 200.0F ///< Minimum allowed inlet conductivity in uS/cm. #define INLET_WATER_COND_OUT_OF_RANGE_TIMEOUT_MS ( 5 * MS_PER_SECOND ) ///< Persistence period for conductivity out of range error in milliseconds. #define INLET_WATER_COND_OUT_OF_RANGE_CLEAR_MS ( 5 * MS_PER_SECOND ) ///< Persistence period for conductivity out of range clear in milliseconds. #define INLET_CONDUCTIVITY_HIGH_THRESHOLD_US 2000.0F ///< Maximum allowed outlet conductivity in uS/cm. // ********** private data ********** static OVERRIDE_U32_T tempSensorsPublishInterval; ///< Temperature sensor data publication counter. static U32 dataPublicationTimerCounter; ///< Timer counter used to schedule temp sensor data publication to CAN bus. // ********** private function prototypes ********** static void publishTemperatureSensorsData( void ); /*********************************************************************//** * @brief * The initWaterQualityMonitor function initializes the Water Quality Monitor unit. * @details \b Inputs: none * @details \b Outputs: Water Quality Monitor unit is initialized. * @return none *************************************************************************/ void initWaterQualityMonitor( void ) { dataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; tempSensorsPublishInterval.data = TEMP_SENSORS_DATA_PUBLISH_INTERVAL; tempSensorsPublishInterval.ovData = TEMP_SENSORS_DATA_PUBLISH_INTERVAL; tempSensorsPublishInterval.ovInitData = 0; tempSensorsPublishInterval.override = OVERRIDE_RESET; // Pressure alarms initPersistentAlarm( ALARM_ID_FP_INLET_PRESSURE_OUT_LOW_RANGE, INLET_WATER_PRES_OUT_OF_RANGE_CLEAR_MS, INLET_WATER_PRES_OUT_OF_RANGE_TIMEOUT_MS ); initPersistentAlarm( ALARM_ID_FP_INLET_PRESSURE_OUT_HIGH_RANGE, INLET_WATER_PRES_OUT_OF_RANGE_CLEAR_MS, INLET_WATER_PRES_OUT_OF_RANGE_TIMEOUT_MS ); initPersistentAlarm( ALARM_ID_FP_PRESSURE_RELIEF_OUT_LOW_RANGE, INLET_WATER_PRES_RELIEF_OUT_OF_RANGE_CLEAR_MS, INLET_WATER_PRES_RELIEF_OUT_OF_RANGE_TIMEOUT_MS ); initPersistentAlarm( ALARM_ID_FP_PRESSURE_RELIEF_OUT_HIGH_RANGE, INLET_WATER_PRES_RELIEF_OUT_OF_RANGE_CLEAR_MS, INLET_WATER_PRES_RELIEF_OUT_OF_RANGE_TIMEOUT_MS ); initPersistentAlarm( ALARM_ID_FP_INLET_PRESSURE_REGULATOR_OUT_OF_RANGE, INLET_WATER_PRES_OUT_OF_RANGE_CLEAR_MS, INLET_WATER_PRES_OUT_OF_RANGE_TIMEOUT_MS ); // Temperature Alarms initPersistentAlarm( ALARM_ID_FP_INLET_TEMPERATURE_OUT_LOW_RANGE, INLET_TEMPERATURE_PERSISTENCE_CLEAR_MS, INLET_TEMPERATURE_PERSISTENCE_TIMER_MS ); initPersistentAlarm( ALARM_ID_FP_INLET_TEMPERATURE_OUT_HIGH_RANGE, INLET_TEMPERATURE_PERSISTENCE_CLEAR_MS, INLET_TEMPERATURE_PERSISTENCE_TIMER_MS ); // Conductivity Alarms initPersistentAlarm( ALARM_ID_FP_INLET_CONDUCTIVITY_OUT_HIGH_RANGE, INLET_WATER_COND_OUT_OF_RANGE_CLEAR_MS, INLET_WATER_COND_OUT_OF_RANGE_TIMEOUT_MS ); initPersistentAlarm( ALARM_ID_FP_RO_OUTLET_CONDUCTIVITY_HIGH_RANGE, INLET_WATER_COND_OUT_OF_RANGE_CLEAR_MS, INLET_WATER_COND_OUT_OF_RANGE_TIMEOUT_MS ); } /*********************************************************************//** * @brief * The execWaterQualityMonitor function executes the water quality * state machine. * @details \b Inputs: none * @details \b Outputs: none * @return none *************************************************************************/ void execWaterQualityMonitor( void ) { publishTemperatureSensorsData(); } /*********************************************************************//** * @brief * The checkInletPressures function checks the inlet water pressure * against the pressure threshold and alarm if the pressure is out of range. * @details \b Inputs: pressureM1 * @details \b Outputs: none * @details \b Alarms: ALARM_ID_FP_INLET_PRESSURE_OUT_LOW_RANGE when * M1 pressure goes beyond low pressure limit. * @details \b Alarms: ALARM_ID_FP_INLET_PRESSURE_OUT_HIGH_RANGE when * M1 pressure goes beyond high pressure limit * @return none *************************************************************************/ void checkInletPressures( void ) { F32 pressureM1 = getFilteredPressure( M1_PRES ); BOOL isPresOutOfLowRange = FALSE; BOOL isPresOutOfHighRange = FALSE; if ( TRUE == isBoostPumpInstalled() ) { isPresOutOfLowRange = ( ( pressureM1 < MIN_INLET_WATER_PRESSURE_WARNING_BOOST_LOW_PSIG ) ? TRUE : FALSE); isPresOutOfHighRange = ( ( pressureM1 > MAX_INLET_WATER_PRESSURE_WARNING_BOOST_HIGH_PSIG ) ? TRUE : FALSE); checkPersistentAlarm( ALARM_ID_FP_INLET_PRESSURE_OUT_LOW_RANGE, isPresOutOfLowRange, pressureM1, MIN_INLET_WATER_PRESSURE_WARNING_BOOST_LOW_PSIG ); checkPersistentAlarm( ALARM_ID_FP_INLET_PRESSURE_OUT_HIGH_RANGE, isPresOutOfHighRange, pressureM1, MAX_INLET_WATER_PRESSURE_WARNING_BOOST_HIGH_PSIG ); } else { isPresOutOfLowRange = ( ( pressureM1 < MIN_INLET_WATER_PRESSURE_WARNING_LOW_PSIG ) ? TRUE : FALSE); isPresOutOfHighRange = ( ( pressureM1 > MAX_INLET_WATER_PRESSURE_WARNING_HIGH_PSIG ) ? TRUE : FALSE); checkPersistentAlarm( ALARM_ID_FP_INLET_PRESSURE_OUT_LOW_RANGE, isPresOutOfLowRange, pressureM1, MIN_INLET_WATER_PRESSURE_WARNING_LOW_PSIG ); checkPersistentAlarm( ALARM_ID_FP_INLET_PRESSURE_OUT_HIGH_RANGE, isPresOutOfHighRange, pressureM1, MAX_INLET_WATER_PRESSURE_WARNING_HIGH_PSIG ); } } /*********************************************************************//** * @brief * The checkROPressures function checks the RO membrane pressure * against the pressure threshold and alarm if the pressure is out of range. * @details \b Inputs: pressureP13 * @details \b Outputs: none * @details \b Alarms: ALARM_ID_FP_RO_INLET_PRESSURE_OUT_HIGH_RANGE when * P13 pressure goes beyond high pressure limit. * @return none *************************************************************************/ void checkROPressures( void ) { F32 pressureP13 = getPressure( P13_PRES ); if ( pressureP13 > MAX_INLET_RO_PUMP_PRESSURE_WARNING_PSIG ) { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_RO_INLET_PRESSURE_OUT_HIGH_RANGE, pressureP13, MAX_INLET_RO_PUMP_PRESSURE_WARNING_PSIG ) } } /*********************************************************************//** * @brief * The checkROPressures function checks the RO membrane outlet pressure * against the pressure threshold and alarm if the pressure is out of range. * @details \b Inputs: pressureP17 * @details \b Outputs: none * @details \b Alarms: ALARM_ID_FP_PRESSURE_RELIEF_OUT_LOW_RANGE when * P17 pressure goes beyond low pressure limit. * @details \b Alarms: ALARM_ID_FP_PRESSURE_RELIEF_OUT_HIGH_RANGE when * P17 pressure goes beyond high pressure limit. * @return none *************************************************************************/ void checkPressureRelief( void ) { F32 pressureP17 = getFilteredPressure( P17_PRES ); BOOL isPresReliefOutOfLowRange = FALSE; BOOL isPresReliefOutOfHighRange = FALSE; isPresReliefOutOfLowRange = ( ( pressureP17 < MIN_PRESSURE_RELIEF_WARNING_LOW_PSIG ) ? TRUE : FALSE); isPresReliefOutOfHighRange = ( ( pressureP17 > MAX_PRESSURE_RELIEF_WARNING_HIGH_PSIG ) ? TRUE : FALSE); checkPersistentAlarm( ALARM_ID_FP_PRESSURE_RELIEF_OUT_LOW_RANGE, isPresReliefOutOfLowRange, pressureP17, MIN_PRESSURE_RELIEF_WARNING_LOW_PSIG ); checkPersistentAlarm( ALARM_ID_FP_PRESSURE_RELIEF_OUT_HIGH_RANGE, isPresReliefOutOfHighRange, pressureP17, MAX_PRESSURE_RELIEF_WARNING_HIGH_PSIG ); } /*********************************************************************//** * @brief * The checkInletTemperatures function checks the inlet water temperature * against the temperature threshold and alarm if the temperature is out of range. * @details \b Inputs: temperatureP10, temperatureM1 * @details \b Outputs: none * @details \b Alarms: ALARM_ID_FP_INLET_TEMPERATURE_OUT_LOW_RANGE when * P10 or M1 temperature goes beyond low temperature limit. * @details \b Alarms: ALARM_ID_FP_INLET_TEMPERATURE_OUT_HIGH_RANGE when * P10 or M1 temperature goes beyond high temperature limit * @return none *************************************************************************/ void checkInletTemperatures( void ) { F32 temperatureP10 = getTemperatureValue( P10_TEMP ); F32 temperatureM1 = getFilteredPressureSensorTemperature( M1_PRES ); BOOL isTempOutOfLowRange = FALSE; BOOL isTempOutOfHighRange = FALSE; isTempOutOfLowRange = ( ( temperatureP10 < INLET_TEMPERATURE_LOW_THRESHOLD_C ) ? TRUE : FALSE); isTempOutOfHighRange = ( ( temperatureP10 > INLET_TEMPERATURE_HIGH_THRESHOLD_C ) ? TRUE : FALSE); checkPersistentAlarm( ALARM_ID_FP_INLET_TEMPERATURE_OUT_LOW_RANGE, isTempOutOfLowRange, temperatureP10, INLET_TEMPERATURE_LOW_THRESHOLD_C ); checkPersistentAlarm( ALARM_ID_FP_INLET_TEMPERATURE_OUT_HIGH_RANGE, isTempOutOfHighRange, temperatureP10, INLET_TEMPERATURE_HIGH_THRESHOLD_C ); isTempOutOfLowRange = ( ( temperatureM1 < INLET_TEMPERATURE_LOW_THRESHOLD_C ) ? TRUE : FALSE); isTempOutOfHighRange = ( ( temperatureM1 > INLET_TEMPERATURE_HIGH_THRESHOLD_C ) ? TRUE : FALSE); checkPersistentAlarm( ALARM_ID_FP_INLET_TEMPERATURE_OUT_LOW_RANGE, isTempOutOfLowRange, temperatureM1, INLET_TEMPERATURE_LOW_THRESHOLD_C ); checkPersistentAlarm( ALARM_ID_FP_INLET_TEMPERATURE_OUT_HIGH_RANGE, isTempOutOfHighRange, temperatureM1, INLET_TEMPERATURE_HIGH_THRESHOLD_C ); } /*********************************************************************//** * @brief * The checkInletConductivity function checks the inlet conductivity * against the conductivity threshold and alarm if the conductivity is out of range. * @details \b Inputs: conductivityP9 * @details \b Outputs: none * @details \b Alarms: ALARM_ID_FP_INLET_CONDUCTIVITY_OUT_HIGH_RANGE when * P9 pressure goes beyond high conductivity limit. * @return none *************************************************************************/ void checkInletConductivity( void ) { F32 conductivityP9 = getFilteredConductivity( P9_COND ); BOOL isConductivtyOutOfLowRange = FALSE; isConductivtyOutOfLowRange = ( ( conductivityP9 > INLET_CONDUCTIVITY_HIGH_THRESHOLD_US ) ? TRUE : FALSE); checkPersistentAlarm( ALARM_ID_FP_INLET_CONDUCTIVITY_OUT_HIGH_RANGE, isConductivtyOutOfLowRange, conductivityP9, INLET_CONDUCTIVITY_HIGH_THRESHOLD_US ); } /*********************************************************************//** * @brief * The checkInletConductivity function checks the inlet conductivity * against the conductivity threshold and alarm if the conductivity is out of range. * @details \b Inputs: conductivityP18 * @details \b Outputs: none * @details \b Alarms: ALARM_ID_FP_RO_OUTLET_CONDUCTIVITY_HIGH_RANGE when * P9 pressure goes beyond high conductivity limit. * @return none *************************************************************************/ void checkOutletConductivity( void ) { F32 conductivityP18 = getFilteredConductivity( P18_COND ); BOOL isConductivityOutOfLowRange = FALSE; isConductivityOutOfLowRange = ( ( conductivityP18 > OUTLET_CONDUCTIVITY_HIGH_THRESHOLD_US ) ? TRUE : FALSE); checkPersistentAlarm( ALARM_ID_FP_RO_OUTLET_CONDUCTIVITY_HIGH_RANGE, isConductivityOutOfLowRange, conductivityP18, OUTLET_CONDUCTIVITY_HIGH_THRESHOLD_US ); } /*********************************************************************//** * @brief * The publishTemperatureSensorsData function broadcasts the temperature * sensors data at the publication interval. * @details \b Inputs: dataPublicationTimerCounter, tempSensorsPublishInterval * @details \b Outputs: dataPublicationTimerCounter * @details \b Message \b Sent: MSG_ID_FP_TEMPERATURE_DATA publishes the temperature * data in a periodic interval. * @return none *************************************************************************/ static void publishTemperatureSensorsData( void ) { if ( ++dataPublicationTimerCounter >= getU32OverrideValue( &tempSensorsPublishInterval ) ) { TEMPERATURE_SENSORS_DATA_T data; data.p10Temp = getFilteredConductivitySensorTemperature( P9_COND ); data.p19Temp = getFilteredConductivitySensorTemperature( P18_COND ); data.m1Temp = getFilteredPressureSensorTemperature( M1_PRES ); data.m3Temp = getFilteredPressureSensorTemperature( M3_PRES ); data.p8Temp = getFilteredPressureSensorTemperature( P8_PRES ); data.p13Temp = getFilteredPressureSensorTemperature( P13_PRES ); data.p17Temp = getFilteredPressureSensorTemperature( P17_PRES ); data.x1Temp = getFilteredPressureSensorTemperature( X1_PRES ); data.x2Temp = getFilteredPressureSensorTemperature( X2_PRES ); data.x3Temp = getFilteredPressureSensorTemperature( X3_PRES ); data.x4Temp = getFilteredPressureSensorTemperature( X4_PRES ); data.p7Temp = getFilteredFlowSensorTemperature( P7_FLOW ); data.p16Temp = getFilteredFlowSensorTemperature( P16_FLOW ); broadcastData( MSG_ID_FP_TEMPERATURE_DATA, COMM_BUFFER_OUT_CAN_FP_BROADCAST, (U08*)&data, sizeof( TEMPERATURE_SENSORS_DATA_T ) ); dataPublicationTimerCounter = 0; } } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testTemperatureSensorsDataPublishIntervalOverride function overrides the * temperature sensors data publish interval. * @details \b Inputs: none * @details \b Outputs: tempSensorsPublishInterval * @param Override message from Dialin which includes the interval * (in ms) to override the temperature sensor data broadcast interval to. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testTemperatureSensorsDataPublishIntervalOverride( MESSAGE_T *message ) { BOOL result = u32BroadcastIntervalOverride( message, &tempSensorsPublishInterval, TASK_PRIORITY_INTERVAL ); return result; } /**@}*/