Index: firmware/App/Controllers/BoostPump.c =================================================================== diff -u -r228773fa681489a62db5c47807a4794e5761d4f5 -ra0c144ed9f72066d7a7b1d047b01fb76ca56d667 --- firmware/App/Controllers/BoostPump.c (.../BoostPump.c) (revision 228773fa681489a62db5c47807a4794e5761d4f5) +++ firmware/App/Controllers/BoostPump.c (.../BoostPump.c) (revision a0c144ed9f72066d7a7b1d047b01fb76ca56d667) @@ -167,7 +167,7 @@ break; default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, SW_FAULT_ID_FP_INVALID_PUMP_DUTY_CYCLE_SELECTED, boostPumpState ) + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FP_INVALID_PUMP_DUTY_CYCLE_SELECTED, boostPumpState ) boostPumpState = BOOST_PUMP_OFF_STATE; break; } @@ -360,7 +360,7 @@ BOOL result = FALSE; // First of all, the flow rate must be in range - if ( ( boostFlowRate <= MAX_BOOST_FLOWRATE_MLPM ) && ( boostFlowRate >= MIN_BOOST_FLOWRATE_MLPM ) ) + if ( boostFlowRate <= MAX_BOOST_FLOWRATE_MLPM ) { targetBoostPumpFlowRate.data = boostFlowRate; boostPumpControlMode = PUMP_CONTROL_MODE_CLOSED_LOOP; @@ -383,7 +383,7 @@ // Requested flow rate is out of range else { - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, SW_FAULT_ID_FP_PUMP_INVALID_FLOW_RATE_SET, boostFlowRate ) + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FP_PUMP_INVALID_FLOW_RATE_SET, boostFlowRate ) } return result; @@ -426,7 +426,7 @@ // Requested flow rate is out of range else { - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, SW_FAULT_ID_FP_PUMP_INVALID_PRESSURE_SELECTED, boostPressure ) + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FP_PUMP_INVALID_PRESSURE_SELECTED, boostPressure ) } return result; @@ -467,7 +467,7 @@ } else { - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, SW_FAULT_ID_FP_INVALID_PUMP_DUTY_CYCLE_SELECTED, dutyCycle ) + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FP_INVALID_PUMP_DUTY_CYCLE_SELECTED, dutyCycle ) } return status; Index: firmware/App/Controllers/PermeateTank.c =================================================================== diff -u --- firmware/App/Controllers/PermeateTank.c (revision 0) +++ firmware/App/Controllers/PermeateTank.c (revision a0c144ed9f72066d7a7b1d047b01fb76ca56d667) @@ -0,0 +1,401 @@ +/************************************************************************** +* +* Copyright (c) 2020-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 PermeateTank.c +* +* @author (last) Sean Nash +* @date (last) 12-Nov-2024 +* +* @author (original) Sean Nash +* @date (original) 12-Nov-2024 +* +***************************************************************************/ + +#include "FPOperationModes.h" +#include "Level.h" +#include "Messaging.h" +#include "PermeateTank.h" +#include "TaskGeneral.h" +#include "Timers.h" +#include "Utilities.h" +#include "Valves.h" + +/** + * @addtogroup FPPermeateTank + * @{ + */ + +// ********** private definitions ********** + +#define PERMEATE_TANK_PUMP_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) for permeate tank broadcast +#define PERMEATE_TANK_PUBLISH_COUNTER_START_COUNT 9 ///< Publishing counter offset +#define PERMEATE_TANK_FILL_SWITCH_MS ( 10 * MS_PER_SECOND ) ///< state switch timeout in fill state ( in ms ) +#define PERMEATE_TANK_FULL_SWITCH_MS ( 1 * MS_PER_SECOND ) ///< state switch timeout in full state (in ms) +#define PERMEATE_TANK_FULL_TIMEOUT_MS ( 60 * MS_PER_SECOND ) ///< timeout being in full state too long ( in ms ) + +// ********** private data ********** + +static PERMEATE_TANK_STATE_T permeateTankControllerState; ///< Current state of permeate controller state machine. +static U32 permeateTankDataPublicationTimerCounter; ///< Used to schedule permeate tank data publication to CAN bus. +static OVERRIDE_U32_T permeateTankPublishInterval; ///< Interval (in ms) at which to publish permeate tank data to CAN bus. +static BOOL pendingStartPermeateTankController; ///< Flag indicates an air trap controller start request is pending. +static BOOL pendingStopPermeateTankController; ///< Flag indicates an air trap controller stop request is pending. +static U32 tankFullAlarmTimeout; ///< Time stamp to track alarm timeout. +static U32 tankFullDelayTime; ///< Time stamp to track delay before valve switch. +static U32 tankFillDelayTime; ///< Time stamp to track fill timeout. + +// ********** private function prototypes ********** + +static PERMEATE_TANK_STATE_T handlePermeateTankManualControlState( void ); +static PERMEATE_TANK_STATE_T handlePermeateTankFillState( void ); +static PERMEATE_TANK_STATE_T handlePermeateTankFullState( void ); +static void setPermeateTankTransition( PERMEATE_TANK_STATE_T state ); +static void publishPermeateTankData( void ); + +/*********************************************************************//** + * @brief + * The initPermeateTank function initializes the permeate tank controller unit. + * @details \b Inputs: none + * @details \b Outputs: permeate tank controller unit initialized + * @return none + *************************************************************************/ +void initPermeateTank( void ) +{ + resetPermeateTank(); + permeateTankDataPublicationTimerCounter = PERMEATE_TANK_PUBLISH_COUNTER_START_COUNT; + permeateTankPublishInterval.data = PERMEATE_TANK_PUMP_DATA_PUB_INTERVAL; + permeateTankPublishInterval.ovData = PERMEATE_TANK_PUMP_DATA_PUB_INTERVAL; + permeateTankPublishInterval.ovInitData = PERMEATE_TANK_PUMP_DATA_PUB_INTERVAL; + permeateTankPublishInterval.override = OVERRIDE_RESET; + tankFillDelayTime = 0; + tankFullDelayTime = 0; + tankFullAlarmTimeout = 0; +} + +/*********************************************************************//** + * @brief + * The resetPermeateTank function resets certain parts of the permeate tank module + * between water generation. + * @details \b Inputs: none + * @details \b Outputs: Permeate Tank controller reset. + * @return none + *************************************************************************/ +void resetPermeateTank( void ) +{ + permeateTankControllerState = PERMEATE_TANK_INIT_STATE; + pendingStartPermeateTankController = FALSE; + pendingStopPermeateTankController = FALSE; +} + +/*********************************************************************//** + * @brief + * The startPermeateTankControl function requests a start to permeate tank control. + * @details \b Inputs: permeateTankControllerState + * @details \b Outputs: pendingStartPermeateTankController + * @return none + *************************************************************************/ +void startPermeateTankControl( void ) +{ + if ( FALSE == isPermeateTankControlling() ) + { + pendingStartPermeateTankController = TRUE; + } +} + +/*********************************************************************//** + * @brief + * The endPermeateTankControl function requests a stop to permeate tank control. + * @details \b Inputs: permeateTankControllerState + * @details \b Outputs: pendingStopPermeateTankController + * @return none + *************************************************************************/ +void endPermeateTankControl( void ) +{ + if ( TRUE == isPermeateTankControlling() ) + { + pendingStopPermeateTankController = TRUE; + } +} + +/*********************************************************************//** + * @brief + * The isPermeateTankControlling function determines whether the permeate tank is + * currently controlling. + * @details \b Inputs: permeateTankControllerState + * @details \b Outputs: none + * @return TRUE if air trap is currently controlling, FALSE if not. + *************************************************************************/ +BOOL isPermeateTankControlling( void ) +{ + BOOL result = FALSE; + + if ( permeateTankControllerState > PERMEATE_TANK_MANUAL_CONTROL_STATE ) + { + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getPermeateTankState function returns the current state of the + * permeate tank controller. + * @details \b Inputs: permeateTankControllerState + * @details \b Outputs: none + * @return the current state of permeate tank + *************************************************************************/ +PERMEATE_TANK_STATE_T getPermeateTankState( void ) +{ + return permeateTankControllerState; +} + +/*********************************************************************//** + * @brief + * The execPermeateTankController function executes the air trap control state machine. + * @details \b Alarm: ALARM_ID_FP_SOFTWARE_FAULT if current permeate tank control + * state is invalid. + * @details \b Message \b Sent: MSG_ID_TD_EVENT if air trap valve closed due to fault. + * @details \b Inputs: permeateTankControllerState + * @details \b Outputs: permeateTankControllerState + * @return none + *************************************************************************/ +void execPermeateTankController( void ) +{ + PERMEATE_TANK_STATE_T prevState = permeateTankControllerState; + // If we have faulted, close valve and go to manual control + if ( FP_MODE_FAUL == getCurrentFPOperationMode() ) + { + endPermeateTankControl(); + } + + // Execute air trap state machine + switch( permeateTankControllerState ) + { + case PERMEATE_TANK_INIT_STATE: + permeateTankControllerState = PERMEATE_TANK_MANUAL_CONTROL_STATE; + break; + + case PERMEATE_TANK_MANUAL_CONTROL_STATE: + permeateTankControllerState = handlePermeateTankManualControlState(); + break; + + case PERMEATE_TANK_FILL_STATE: + permeateTankControllerState = handlePermeateTankFillState(); + break; + + case PERMEATE_TANK_FULL_STATE: + permeateTankControllerState = handlePermeateTankFullState(); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, (U32)FP_FAULT_ID_FP_INVALID_PERMEATE_TANK_STATE, (U32)permeateTankControllerState ) + permeateTankControllerState = PERMEATE_TANK_INIT_STATE; + break; + } + + if ( prevState != permeateTankControllerState ) + { + setPermeateTankTransition( permeateTankControllerState ); + } + + // Publish permeate tank data if due + publishPermeateTankData(); +} + +/*********************************************************************//** + * @brief + * The handlePermeateTankManualControlState function handles the manual control + * state of the permeate tank. + * @details \b Inputs: pendingStartPermeateTankController + * @details \b Outputs: pendingStartPermeateTankController + * @return next state + *************************************************************************/ +static PERMEATE_TANK_STATE_T handlePermeateTankManualControlState( void ) +{ + PERMEATE_TANK_STATE_T state = PERMEATE_TANK_MANUAL_CONTROL_STATE; + + // Transition to valve control states when requested + if ( TRUE == pendingStartPermeateTankController ) + { + pendingStartPermeateTankController = FALSE; + state = PERMEATE_TANK_FILL_STATE; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleAirTrapRaiseLevelState function handles the raise level state + * of the permeate tank. + * @details \b Message \b Sent: MSG_ID_TD_EVENT if raising level completed + * @details \b Inputs: pendingStopPermeateTankController + * @details \b Outputs: pendingStopPermeateTankController + * @return next state + *************************************************************************/ +static PERMEATE_TANK_STATE_T handlePermeateTankFillState( void ) +{ + PERMEATE_TANK_STATE_T state = PERMEATE_TANK_FILL_STATE; + LEVEL_STATE_T level = getLevelStatus( P25_LEVL ); + + // Transition to manual valve control state when requested + if ( TRUE == pendingStopPermeateTankController ) + { + pendingStopPermeateTankController = FALSE; + state = PERMEATE_TANK_MANUAL_CONTROL_STATE; + } + + else if ( LEVEL_STATE_HIGH == level ) + { + state = PERMEATE_TANK_FULL_STATE; + } + else if ( level == LEVEL_STATE_LOW ) + { + if ( TRUE == didTimeout( tankFillDelayTime, PERMEATE_TANK_FILL_SWITCH_MS ) ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_FP_GEN_PERMEATE_TANK_FILL_TIMEOUT, level ) + } + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handlePermeateTankFullState function handles the lower level state + * of the permeate tank. + * @details \b Inputs: tankFullAlarmTimeout, pendingStopPermeateTankController, tankFullDelayTime + * @details \b Outputs: pendingStopPermeateTankController + * @return next state + *************************************************************************/ +static PERMEATE_TANK_STATE_T handlePermeateTankFullState( void ) +{ + PERMEATE_TANK_STATE_T state = PERMEATE_TANK_FULL_STATE; + LEVEL_STATE_T level = getLevelStatus( P25_LEVL ); + + if ( TRUE == didTimeout( tankFullAlarmTimeout, PERMEATE_TANK_FULL_TIMEOUT_MS ) ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_FP_GEN_PERMEATE_TANK_FULL_TIMEOUT, level ) + } + + // Transition to manual valve control state when requested + if ( TRUE == pendingStopPermeateTankController ) + { + pendingStopPermeateTankController = FALSE; + state = PERMEATE_TANK_MANUAL_CONTROL_STATE; + } + else if ( level == LEVEL_STATE_LOW ) + { + if ( TRUE == didTimeout( tankFullDelayTime, PERMEATE_TANK_FULL_SWITCH_MS ) ) + { + state = PERMEATE_TANK_FILL_STATE; + } + } + + return state; +} + +/*********************************************************************//** + * @brief + * The setPermeateTankTransition function sets the actuators and variables + * for the state transition in permeate tank controller. + * @details Inputs: Valve states + * @details Outputs: Actuate valves + * @param state permeate tank state enum + * @return none + *************************************************************************/ +static void setPermeateTankTransition( PERMEATE_TANK_STATE_T state ) +{ + // Execute on running state + switch( state ) + { + case PERMEATE_TANK_INIT_STATE: + case PERMEATE_TANK_MANUAL_CONTROL_STATE: + break; + + case PERMEATE_TANK_FILL_STATE: + setValveState( M4_VALV,VALVE_STATE_OPEN ); + setValveState( M7_VALV, VALVE_STATE_CLOSED ); + setValveState( P6_VALV, VALVE_STATE_CLOSED ); + setValveState( P11_VALV, VALVE_STATE_OPEN ); + setValveState( P33_VALV, VALVE_STATE_OPEN ); // TODO - Change valves to handle RO rejection config + setValveState( P34_VALV, VALVE_STATE_CLOSED ); // Current set to Medium recovery for alpha HW + setValveState( P37_VALV, VALVE_STATE_CLOSED ); + setValveState( P39_VALV, VALVE_STATE_OPEN ); + setValveState( P20_VALV, VALVE_STATE_CLOSED ); + setValveState( P43_VALV, VALVE_STATE_CLOSED ); + tankFillDelayTime = getMSTimerCount(); + break; + + case PERMEATE_TANK_FULL_STATE: + setValveState( M4_VALV, VALVE_STATE_CLOSED ); + setValveState( M7_VALV, VALVE_STATE_CLOSED ); + setValveState( P6_VALV, VALVE_STATE_CLOSED ); + setValveState( P11_VALV, VALVE_STATE_OPEN ); + setValveState( P33_VALV, VALVE_STATE_OPEN ); + setValveState( P34_VALV, VALVE_STATE_OPEN ); + setValveState( P37_VALV, VALVE_STATE_CLOSED ); + setValveState( P39_VALV, VALVE_STATE_CLOSED ); + setValveState( P20_VALV, VALVE_STATE_CLOSED ); + setValveState( P43_VALV, VALVE_STATE_CLOSED ); + tankFullDelayTime = getMSTimerCount(); + tankFullAlarmTimeout = getMSTimerCount(); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FP_INVALID_GENP_STATE, state ) + break; + } +} + +/*********************************************************************//** + * @brief + * The publishPermeateTankData function publishes permeate tank at the set interval. + * @details \b Message \b Sent: MSG_ID_FP_PERMEATE_TANK_DATA + * @details \b Inputs: permeateTankDataPublicationTimerCounter + * @details \b Outputs: permeateTankDataPublicationTimerCounter + * @return none + *************************************************************************/ +static void publishPermeateTankData( void ) +{ + // publish RO pump data on interval + if ( ++permeateTankDataPublicationTimerCounter >= getU32OverrideValue( &permeateTankPublishInterval ) ) + { + PERMEATE_TANK_DATA_T data; + data.tankState = permeateTankControllerState; + + broadcastData( MSG_ID_FP_PERMEATE_TANK_DATA, COMM_BUFFER_OUT_CAN_FP_BROADCAST, (U08*)&data, sizeof( PERMEATE_TANK_DATA_T ) ); + permeateTankDataPublicationTimerCounter = 0; + } +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testPermeateTankDataPublishIntervalOverride function overrides the + * permeate tank data publish interval. + * @details \b Inputs: permeateTankPublishInterval + * @details \b Outputs: permeateTankPublishInterval + * @param message Override message from Dialin which includes the value + * that override permeate tank data publish interval with (in ms) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testPermeateTankDataPublishIntervalOverride( MESSAGE_T *message ) +{ + BOOL result = u32BroadcastIntervalOverride( message, &permeateTankPublishInterval, TASK_GENERAL_INTERVAL ); + + return result; +} + +/**@}*/ + Index: firmware/App/Controllers/PermeateTank.h =================================================================== diff -u --- firmware/App/Controllers/PermeateTank.h (revision 0) +++ firmware/App/Controllers/PermeateTank.h (revision a0c144ed9f72066d7a7b1d047b01fb76ca56d667) @@ -0,0 +1,68 @@ +/************************************************************************** +* +* Copyright (c) 2020-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 PermeateTank.h +* +* @author (last) Sean Nash +* @date (last) 12-Nov-2024 +* +* @author (original) Sean Nash +* @date (original) 12-Nov-2024 +* +***************************************************************************/ + +#ifndef __PERMEATE_TANK_H__ +#define __PERMEATE_TANK_H__ + +// ********** public definitions ********** + +#include "FPCommon.h" + +/** + * @defgroup FPPermeateTank FPPermeateTank + * @brief Permeate Tank controller unit. Provides high level control functionality + * to manage the fluid level of the permeate tank. + * + * @addtogroup PermeateTank + * @{ + */ + +// ********** public definitions ********** + +/// Defined states for the air trap controller state machine. +typedef enum PermeateTank_States +{ + PERMEATE_TANK_INIT_STATE = 0, ///< Initialization state. + PERMEATE_TANK_MANUAL_CONTROL_STATE, ///< Manually control permeate valve state. + PERMEATE_TANK_FILL_STATE, ///< Tank fill state + PERMEATE_TANK_FULL_STATE, ///< Tank full state. + NUM_OF_PERMEATE_TANK_STATES ///< Number of permeate tank controller states. +} PERMEATE_TANK_STATE_T; + +/// Permeate Tank data record. +typedef struct +{ + U32 tankState; ///< Permeate Tank current state. +} PERMEATE_TANK_DATA_T; + +// ********** public function prototypes ********** + +void initPermeateTank(void); +void resetPermeateTank( void ); +void execPermeateTankController(void); + +void startPermeateTankControl( void ); +void endPermeateTankControl( void ); +BOOL isPermeateTankControlling( void ); +PERMEATE_TANK_STATE_T getPermeateTankState( void ); + +BOOL testPermeateTankDataPublishIntervalOverride( MESSAGE_T *message ); +BOOL testSetPermeateTankControl( MESSAGE_T *message ); + +/**@}*/ + +#endif Index: firmware/App/Controllers/ROPump.c =================================================================== diff -u -r228773fa681489a62db5c47807a4794e5761d4f5 -ra0c144ed9f72066d7a7b1d047b01fb76ca56d667 --- firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision 228773fa681489a62db5c47807a4794e5761d4f5) +++ firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision a0c144ed9f72066d7a7b1d047b01fb76ca56d667) @@ -163,7 +163,7 @@ break; default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, SW_FAULT_ID_FP_INVALID_PUMP_DUTY_CYCLE_SELECTED, roPumpState ) + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FP_INVALID_PUMP_DUTY_CYCLE_SELECTED, roPumpState ) roPumpState = RO_PUMP_OFF_STATE; break; } @@ -399,7 +399,7 @@ // Requested flow rate is out of range else { - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, SW_FAULT_ID_FP_PUMP_INVALID_FLOW_RATE_SET, roFlowRate ) + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FP_PUMP_INVALID_FLOW_RATE_SET, roFlowRate ) } return result; @@ -453,7 +453,7 @@ // Requested flow rate is out of range else { - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, SW_FAULT_ID_FP_PUMP_INVALID_PRESSURE_SELECTED, roPressure ) + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FP_PUMP_INVALID_PRESSURE_SELECTED, roPressure ) } return result; @@ -515,7 +515,7 @@ } else { - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, SW_FAULT_ID_FP_INVALID_PUMP_DUTY_CYCLE_SELECTED, dutyCycle ) + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FP_INVALID_PUMP_DUTY_CYCLE_SELECTED, dutyCycle ) } return result; Index: firmware/App/Drivers/FlowSensor.c =================================================================== diff -u --- firmware/App/Drivers/FlowSensor.c (revision 0) +++ firmware/App/Drivers/FlowSensor.c (revision a0c144ed9f72066d7a7b1d047b01fb76ca56d667) @@ -0,0 +1,186 @@ +/************************************************************************** +* +* 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 FlowSensor.c +* +* @author (last) Sean Nash +* @date (last) 21-Nov-2024 +* +* @author (original) Sean Nash +* @date (original) 21-Nov-2024 +* +***************************************************************************/ + +#include "FpgaDD.h" +#include "FlowSensor.h" +#include "Messaging.h" +#include "PersistentAlarm.h" + +/** + * @addtogroup FlowSensor + * @{ + */ + +// ********** private definitions ********** + +#define FLOW_TEMPERATURE_DIVIDER 10.0F ///< Divider for converting flow readings to mL/min flow rates. + +// ********** private data ********** + +static OVERRIDE_S32_T currentFlowReadings[ NUM_OF_FLOW_SENSORS ]; ///< Current flow sensor pressure readings (overrideable). +static OVERRIDE_F32_T currentFlowTempReadings[ NUM_OF_FLOW_SENSORS ]; ///< Current flow sensor temperature readings (overrideable). + +// ********** private function prototypes ********** + +/*********************************************************************//** + * @brief + * The initFlowSensor function initializes the Flow Sensor unit. + * @details \b Inputs: none + * @details \b Outputs: Flow Sensor unit is initialized. + * @return none + *************************************************************************/ +void initFlowSensor( void ) +{ + FLOW_SENSORS_T sensor; + + // Initialize override structures for each pressure sensor + for ( sensor = FLOW_SENSOR_FIRST; sensor < NUM_OF_FLOW_SENSORS; sensor++ ) + { + currentFlowReadings[ sensor ].data = 0; + currentFlowReadings[ sensor ].ovData = 0; + currentFlowReadings[ sensor ].ovInitData = 0; + currentFlowReadings[ sensor ].override = OVERRIDE_RESET; + + currentFlowTempReadings[ sensor ].data = 0.0F; + currentFlowTempReadings[ sensor ].ovData = 0.0F; + currentFlowTempReadings[ sensor ].ovInitData = 0.0F; + currentFlowTempReadings[ sensor ].override = OVERRIDE_RESET; + } +} + +/*********************************************************************//** + * @brief + * The readFlowSensors function gets the current flow rate reading + * for a all flow sensors from the FPGA. + * @note This function should be called periodically to maintain fresh + * sensor readings for all flow sensors. + * @details \b Inputs: FPGA + * @details \b Outputs: currentFlowReadings[], currentFlowTempReadings[] + * @return none + *************************************************************************/ +void readFlowSensors( void ) +{ + // Update raw flow rates to mL/min + currentFlowReadings[ P16_FLOW ].data = ( (S16)getFPGAFlowP16() ); + currentFlowReadings[ P7_FLOW ].data = ( (S16)getFPGAFlowP7() ); + + // Update and convert raw flow sensor temperatures to deg C + currentFlowTempReadings[ P16_FLOW ].data = (F32)( (S16)getFPGAFlowP16Temp() ) / FLOW_TEMPERATURE_DIVIDER; + currentFlowTempReadings[ P7_FLOW ].data = (F32)( (S16)getFPGAFlowP7Temp() ) / FLOW_TEMPERATURE_DIVIDER; +} + +/*********************************************************************//** + * @brief + * The getFlowRate function gets the current flow rate (in mL/min) for a given + * flow sensor. + * @details \b Alarm: ALARM_ID_RO_SOFTWARE_FAULT if given flow sensor is invalid. + * @details \b Inputs: currentFlowReadings[] + * @details \b Outputs: none + * @param sensor ID of flow sensor to get flow rate for. + * @return The current flow rate (in mL/min) of the given flow sensor. + *************************************************************************/ +S32 getFlowRate( FLOW_SENSORS_T sensor ) +{ + S32 result = 0; + + if ( sensor < NUM_OF_FLOW_SENSORS ) + { + result = currentFlowReadings[ sensor ].data; + if ( OVERRIDE_KEY == currentFlowReadings[ sensor ].override ) + { + result = currentFlowReadings[ sensor ].ovData; + } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FLOW_SENSOR_INVALID_SENSOR1, (U32)sensor ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getFlowTemperature function gets the current flow sensor + * temperature (in deg C) for a given flow sensor. + * @details \b Alarm: ALARM_ID_RO_SOFTWARE_FAULT if given flow sensor is invalid. + * @details \b Inputs: currentFlowTempReadings + * @details \b Outputs: none + * @param sensor ID of flow sensor to get flow rate for. + * @return The current flow sensor temperature (in deg C) of the given flow sensor. + *************************************************************************/ +F32 getFlowTemperature( FLOW_SENSORS_T sensor ) +{ + F32 result = 0.0F; + + if ( sensor < NUM_OF_FLOW_SENSORS ) + { + result = currentFlowTempReadings[ sensor ].data; + if ( OVERRIDE_KEY == currentFlowTempReadings[ sensor ].override ) + { + result = currentFlowTempReadings[ sensor ].ovData; + } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FLOW_SENSOR_INVALID_SENSOR2, (U32)sensor ) + } + + return result; +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testFlowSensorReadingsOverride function overrides the value of + * the specified flow sensor with a given value. + * @details \b Inputs: none + * @details \b Outputs: currentFlowReadings[] + * @param message Override message from Dialin which includes a sensor + * ID and override value of the flow sensor. + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testFlowSensorReadingsOverride( MESSAGE_T *message ) +{ + BOOL result = s32ArrayOverride( message, ¤tFlowReadings[0], NUM_OF_FLOW_SENSORS - 1 ); + + return result; +} + +/*********************************************************************//** + * @brief + * The testFlowSensorTemperatureReadingsOverride function overrides the + * value of the specified flow sensor temperature with a given value. + * @details \b Inputs: none + * @details \b Outputs: currentFlowTempReadings[] + * @param message Override message from Dialin which includes a sensor + * ID and override value of the flow sensor temperature. + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testFlowSensorTemperatureReadingsOverride( MESSAGE_T *message ) +{ + BOOL result = f32ArrayOverride( message, ¤tFlowTempReadings[0], NUM_OF_FLOW_SENSORS - 1 ); + + return result; +} + +/**@}*/ Index: firmware/App/Drivers/FlowSensor.h =================================================================== diff -u --- firmware/App/Drivers/FlowSensor.h (revision 0) +++ firmware/App/Drivers/FlowSensor.h (revision a0c144ed9f72066d7a7b1d047b01fb76ca56d667) @@ -0,0 +1,58 @@ +/************************************************************************** +* +* 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 FlowSensor.h +* +* @author (last) Sean Nash +* @date (last) 21-Nov-2024 +* +* @author (original) Sean Nash +* @date (original) 21-Nov-2024 +* +***************************************************************************/ + +#ifndef __FLOW_SENSOR_H__ +#define __FLOW_SENSOR_H__ + +#include "FPCommon.h" + +/** + * @defgroup FlowSensor FlowSensor + * @brief Flow sensors driver unit. Reads the flow rates and temperatures + * from the various RO flow sensors. + * + * @addtogroup FlowSensor + * @{ + */ + +// ********** public definitions ********** + +#define MIN_FLOW 0 ///< Minimum flow value used for overriding +#define MAX_FLOW 2000 ///< Maximum flow value used for overriding + +/// Enumeration of flow sensors handled by this unit. +typedef enum FlowSensors +{ + P7_FLOW = 0, ///< Water inlet flow sensor (FMS P7) + FLOW_SENSOR_FIRST = P7_FLOW, ///< First flow + P16_FLOW, ///< RO outlet flow sensor (FMP P16) + NUM_OF_FLOW_SENSORS ///< Number of flow sensors +} FLOW_SENSORS_T; + +// ********** public function prototypes ********** + +void initFlowSensor( void ); +void readFlowSensors( void ); +S32 getFlowRate( FLOW_SENSORS_T sensor ); +F32 getFlowTemperature( FLOW_SENSORS_T sensor ); + +BOOL testFlowSensorReadingsOverride( MESSAGE_T *message ); +BOOL testFlowSensorTemperatureReadingsOverride( MESSAGE_T *message ); + +/**@}*/ + +#endif Index: firmware/App/Modes/FPModes/FPOperationModes.c =================================================================== diff -u -r228773fa681489a62db5c47807a4794e5761d4f5 -ra0c144ed9f72066d7a7b1d047b01fb76ca56d667 --- firmware/App/Modes/FPModes/FPOperationModes.c (.../FPOperationModes.c) (revision 228773fa681489a62db5c47807a4794e5761d4f5) +++ firmware/App/Modes/FPModes/FPOperationModes.c (.../FPOperationModes.c) (revision a0c144ed9f72066d7a7b1d047b01fb76ca56d667) @@ -170,6 +170,14 @@ currentSubMode = execGenPermeateMode(); break; + case FP_MODE_DPGP: + currentSubMode = execPreGenPermeateDefeaturedMode(); + break; + + case FP_MODE_DEGP: + currentSubMode = execPreGenPMode(); + break; + default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, SW_FAULT_ID_OP_MODES_INVALID_MODE_STATE, currentMode ) currentMode = FP_MODE_FAUL; @@ -329,11 +337,11 @@ break; case FP_MODE_DPGP: - //currentSubMode = transitionToPreGenWMode(); + currentSubMode = transitionToPreGenPermeateDefeaturedMode(); break; case FP_MODE_DEGP: - //currentSubMode = transitionToGenWaterMode(); + currentSubMode = transitionToGenPermeateDefeaturedMode(); break; Index: firmware/App/Modes/FPModes/FlushConcentrate.c =================================================================== diff -u -r228773fa681489a62db5c47807a4794e5761d4f5 -ra0c144ed9f72066d7a7b1d047b01fb76ca56d667 --- firmware/App/Modes/FPModes/FlushConcentrate.c (.../FlushConcentrate.c) (revision 228773fa681489a62db5c47807a4794e5761d4f5) +++ firmware/App/Modes/FPModes/FlushConcentrate.c (.../FlushConcentrate.c) (revision a0c144ed9f72066d7a7b1d047b01fb76ca56d667) @@ -115,7 +115,7 @@ break; default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, SW_FAULT_ID_FP_INVALID_CONCENTRATE_FLUSH_STATE, (U32)concentrateFlushState ) + 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; } @@ -246,7 +246,7 @@ break; default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, SW_FAULT_ID_FP_INVALID_CONCENTRATE_FLUSH_STATE, state ) + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FP_INVALID_CONCENTRATE_FLUSH_STATE, state ) break; } } Index: firmware/App/Modes/FPModes/FlushPermeate.c =================================================================== diff -u -r228773fa681489a62db5c47807a4794e5761d4f5 -ra0c144ed9f72066d7a7b1d047b01fb76ca56d667 --- firmware/App/Modes/FPModes/FlushPermeate.c (.../FlushPermeate.c) (revision 228773fa681489a62db5c47807a4794e5761d4f5) +++ firmware/App/Modes/FPModes/FlushPermeate.c (.../FlushPermeate.c) (revision a0c144ed9f72066d7a7b1d047b01fb76ca56d667) @@ -118,7 +118,7 @@ break; default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, SW_FAULT_ID_FP_INVALID_PERMEATE_FLUSH_STATE, (U32)permeateFlushState ) + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FP_INVALID_PERMEATE_FLUSH_STATE, (U32)permeateFlushState ) permeateFlushState = PERM_FLUSH_PAUSED; break; } @@ -253,7 +253,7 @@ break; default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, SW_FAULT_ID_FP_INVALID_PERMEATE_FLUSH_STATE, state ) + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FP_INVALID_PERMEATE_FLUSH_STATE, state ) break; } } Index: firmware/App/Modes/FPModes/InletPressureCheck.c =================================================================== diff -u -r228773fa681489a62db5c47807a4794e5761d4f5 -ra0c144ed9f72066d7a7b1d047b01fb76ca56d667 --- firmware/App/Modes/FPModes/InletPressureCheck.c (.../InletPressureCheck.c) (revision 228773fa681489a62db5c47807a4794e5761d4f5) +++ firmware/App/Modes/FPModes/InletPressureCheck.c (.../InletPressureCheck.c) (revision a0c144ed9f72066d7a7b1d047b01fb76ca56d667) @@ -109,7 +109,7 @@ break; default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, SW_FAULT_ID_FP_INVALID_INLET_PRESSURE_CHECK_STATE, (U32)inletPressureCheckState ) + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FP_INVALID_INLET_PRESSURE_CHECK_STATE, (U32)inletPressureCheckState ) inletPressureCheckState = INLET_PRES_CHECK_PAUSED; break; } @@ -242,7 +242,7 @@ break; default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, SW_FAULT_ID_FP_INVALID_INLET_PRESSURE_CHECK_STATE, state ) + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FP_INVALID_INLET_PRESSURE_CHECK_STATE, state ) break; } } Index: firmware/App/Modes/FPModes/ModeGenPermeate.c =================================================================== diff -u -r228773fa681489a62db5c47807a4794e5761d4f5 -ra0c144ed9f72066d7a7b1d047b01fb76ca56d667 --- firmware/App/Modes/FPModes/ModeGenPermeate.c (.../ModeGenPermeate.c) (revision 228773fa681489a62db5c47807a4794e5761d4f5) +++ firmware/App/Modes/FPModes/ModeGenPermeate.c (.../ModeGenPermeate.c) (revision a0c144ed9f72066d7a7b1d047b01fb76ca56d667) @@ -16,6 +16,7 @@ ***************************************************************************/ #include "BoostPump.h" +#include "FPInterface.h" #include "FPModeStandby.h" #include "FPOperationModes.h" #include "Level.h" @@ -114,7 +115,7 @@ break; default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, SW_FAULT_ID_FP_INVALID_GENP_STATE, genPermeateState ) + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FP_INVALID_GENP_STATE, genPermeateState ) break; } @@ -159,7 +160,7 @@ break; default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, SW_FAULT_ID_FP_INVALID_GENP_STATE, state ) + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FP_INVALID_GENP_STATE, state ) break; } } @@ -249,7 +250,7 @@ GEN_PERMEATE_MODE_DATA_T data; data.genPermeateExecState = (U32)getCurrentGenPermeateState(); - data.setFlowRate = (F32)getDDPermeateFlowRate(); + data.setFlowRate = (F32)getFPFlowRate(); broadcastData( MSG_ID_FP_GEN_WATER_MODE_DATA, COMM_BUFFER_OUT_CAN_FP_BROADCAST, (U08*)&data, sizeof( GEN_PERMEATE_MODE_DATA_T ) ); Index: firmware/App/Modes/FPModes/ModePreGenPermeate.c =================================================================== diff -u -r228773fa681489a62db5c47807a4794e5761d4f5 -ra0c144ed9f72066d7a7b1d047b01fb76ca56d667 --- firmware/App/Modes/FPModes/ModePreGenPermeate.c (.../ModePreGenPermeate.c) (revision 228773fa681489a62db5c47807a4794e5761d4f5) +++ firmware/App/Modes/FPModes/ModePreGenPermeate.c (.../ModePreGenPermeate.c) (revision a0c144ed9f72066d7a7b1d047b01fb76ca56d667) @@ -141,7 +141,7 @@ break; default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, SW_FAULT_ID_FP_INVALID_PGEN_STATE, preGenPState ) + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FP_INVALID_PGEN_STATE, preGenPState ) break; } @@ -209,7 +209,7 @@ break; default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, SW_FAULT_ID_FP_INVALID_PGEN_STATE, state ) + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FP_INVALID_PGEN_STATE, state ) break; } } @@ -462,7 +462,7 @@ { BOOL result = FALSE; - if ( ( FP_MODE_STAN == getCurrentOperationMode() ) && ( FP_STANDBY_MODE_STATE_IDLE == getCurrentStandbyState() ) ) + if ( ( FP_MODE_STAN == getCurrentFPOperationMode() ) && ( FP_STANDBY_MODE_STATE_IDLE == getCurrentFPStandbyState() ) ) { result = TRUE; pendingStartPreGenRequest = TRUE; Index: firmware/App/Monitors/Flow.c =================================================================== diff -u --- firmware/App/Monitors/Flow.c (revision 0) +++ firmware/App/Monitors/Flow.c (revision a0c144ed9f72066d7a7b1d047b01fb76ca56d667) @@ -0,0 +1,438 @@ +/************************************************************************** +* +* 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 Flow.c +* +* @author (last) Sean Nash +* @date (last) 21-Nov-2024 +* +* @author (original) Sean Nash +* @date (original) 21-Nov-2024 +* +***************************************************************************/ + +#include "Flow.h" +#include "FPOperationModes.h" +#include "Messaging.h" +#include "PersistentAlarm.h" +#include "TaskPriority.h" + +/** + * @addtogroup Flow + * @{ + */ + +// ********** private definitions ********** + +#define FLOWS_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Interval (ms/task time) at which the flows data is published on the CAN bus. +#define DATA_PUBLISH_COUNTER_START_COUNT ( 5 ) ///< Data publish counter start count. +#define FLOW_SAMPLE_FILTER_MS ( 500 ) ///< Filter flow data for given time +#define FLOW_TEMP_SAMPLE_FILTER_MS ( 500 ) ///< Filter flow temperature data for given time +#define SIZE_OF_FLOW_ROLLING_AVG ( FLOW_SAMPLE_FILTER_MS / TASK_PRIORITY_INTERVAL ) ///< Filtered flow moving average sample count. +#define SIZE_OF_FLOW_TEMP_ROLLING_AVG ( FLOW_TEMP_SAMPLE_FILTER_MS / TASK_PRIORITY_INTERVAL ) ///< Filtered flow temprature moving average sample count. + +/// Defined states for the flow monitor state machine. +typedef enum FlowMonitor_States +{ + FLOW_INIT_STATE = 0, ///< Initialization state. + FLOW_CONTINUOUS_READ_STATE, ///< Continuous read flow sensors state. + NUM_OF_FLOW_STATES ///< Number of flow monitor states. +} FLOW_STATE_T; + +/// Filter flow readings record. +typedef struct +{ + F32 flowReadings[ SIZE_OF_FLOW_ROLLING_AVG ]; ///< Holds flow sample rolling average. + U32 flowReadingsIdx; ///< Index for next sample in rolling average array. + F32 flowReadingsTotal; ///< Rolling total - used to calc average. + U32 flowReadingsCount; ///< Number of samples in rolling average buffer +} FILTER_FLOW_READINGS_T; + +/// Filter flow temperature readings record. +typedef struct +{ + F32 flowTempReadings[ SIZE_OF_FLOW_TEMP_ROLLING_AVG ]; ///< Holds pressure temperature sample rolling average. + U32 flowTempReadingsIdx; ///< Index for next sample in rolling average array. + F32 flowTempReadingsTotal; ///< Rolling total - used to calc average. + U32 flowTempReadingsCount; ///< Number of samples in rolling average buffer +} FILTER_FLOW_TEMPERATURE_READINGS_T; + +// ********** private data ********** + +static OVERRIDE_F32_T filteredcurrentFlowReadings[ NUM_OF_FLOW_SENSORS ]; ///< filtered current flow sensor flow readings (overrideable). +static OVERRIDE_F32_T filteredcurrentFlowTempReadings[ NUM_OF_FLOW_SENSORS ]; ///< filtered current flow sensor temperature readings (overrideable). +//static RO_PRES_SENSORS_CAL_RECORD_T flowsCalRecord; ///< Flows calibration record. + +static FILTER_FLOW_READINGS_T filteredFlowReadings[NUM_OF_FLOW_SENSORS]; ///< Filtered flow reading for flow sensors. +static FILTER_FLOW_TEMPERATURE_READINGS_T filteredFlowTempReadings[NUM_OF_FLOW_SENSORS]; ///< Filtered temperature reading for flow sensors. +static FLOW_STATE_T flowsState; ///< current state of flow monitor state machine. +static U32 flowsDataPublicationTimerCounter; ///< used to schedule flow data publication to CAN bus. +static OVERRIDE_U32_T flowsDataPublishInterval; ///< Flow data publish interval. + +// ********** private function prototypes ********** + +static void filterFlowSensors( void ); +static void filterFlowSensorReadings( void ); +static void filterFlowSensorTemperatureReadings( void ); +//static F32 getCalibrationAppliedFlow( U08 sensorId, F32 flow ); +static FLOW_STATE_T handleFlowsInitState( void ); +static FLOW_STATE_T handleFlowsContReadState( void ); +static void publishFlowsData( void ); + +/*********************************************************************//** + * @brief + * The initFlow function initializes the Flow Monitor unit. + * @details \b Inputs: none + * @details \b Outputs: Flow monitor unit is initialized. + * @return none + *************************************************************************/ +void initFlow( void ) +{ + FLOW_SENSORS_T sensor; + + flowsState = FLOW_INIT_STATE; + flowsDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; + + // Initialize flow sensors driver + initFlowSensor(); + + // Initialize override structures for each flow sensor + for ( sensor = FLOW_SENSOR_FIRST; sensor < NUM_OF_FLOW_SENSORS; sensor++ ) + { + filteredcurrentFlowReadings[ sensor ].data = 0.0F; + filteredcurrentFlowReadings[ sensor ].ovData = 0.0F; + filteredcurrentFlowReadings[ sensor ].ovInitData = 0.0F; + filteredcurrentFlowReadings[ sensor ].override = OVERRIDE_RESET; + + filteredcurrentFlowTempReadings[ sensor ].data = 0.0F; + filteredcurrentFlowTempReadings[ sensor ].ovData = 0.0F; + filteredcurrentFlowTempReadings[ sensor ].ovInitData = 0.0F; + filteredcurrentFlowTempReadings[ sensor ].override = OVERRIDE_RESET; + + filteredFlowReadings[ sensor ].flowReadingsCount = 0; + filteredFlowReadings[ sensor ].flowReadingsIdx = 0; + filteredFlowReadings[ sensor ].flowReadingsTotal = 0.0F; + + filteredFlowTempReadings[ sensor ].flowTempReadingsCount = 0; + filteredFlowTempReadings[ sensor ].flowTempReadingsIdx = 0; + filteredFlowTempReadings[ sensor ].flowTempReadingsTotal = 0.0F; + } + + flowsDataPublishInterval.data = FLOWS_DATA_PUB_INTERVAL; + flowsDataPublishInterval.ovData = FLOWS_DATA_PUB_INTERVAL; + flowsDataPublishInterval.ovInitData = 0; + flowsDataPublishInterval.override = OVERRIDE_RESET; +} + +/*********************************************************************//** + * @brief + * The filterFlowSensors function gets averages the raw flow and flow + * temperature readings. + * @details \b Inputs: flow and temperature readings from FPGA + * @details \b Outputs: filteredFlowReadings[], filteredFlowTempReadings[] + * @return none + *************************************************************************/ +static void filterFlowSensors( void ) +{ + //Filter flow sensor reading + filterFlowSensorReadings(); + + //Filter flow sensor temperature reading + filterFlowSensorTemperatureReadings(); +} + +/*********************************************************************//** + * @brief + * The getFilteredFlow function gets the filtered current flow (in mL/min) + * for a given flow sensor. + * @details \b Alarm: ALARM_ID_RO_SOFTWARE_FAULT if given sensor is invalid. + * @details \b Inputs: filteredcurrentFlowReadings[] + * @details \b Outputs: none + * @param sensor ID of flow sensor to get filtered flow reading for. + * @return The filtered current flow (in mL/min) of the given flow sensor. + *************************************************************************/ +F32 getFilteredFlow( FLOW_SENSORS_T sensor ) +{ + F32 result = 0.0F; + + if ( sensor < NUM_OF_FLOW_SENSORS ) + { + result = filteredcurrentFlowReadings[ sensor ].data; + if ( OVERRIDE_KEY == filteredcurrentFlowReadings[ sensor ].override ) + { + result = filteredcurrentFlowReadings[ sensor ].ovData; + } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FLOW_SENSOR_INVALID_SENSOR3, (U32)sensor ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getFilteredFlowSensorTemperature function gets the filtered current + * flow sensor temperature (in deg C) for a given flow sensor. + * @details \b Alarm: ALARM_ID_FP_SOFTWARE_FAULT if given sensor is invalid. + * @details \b Inputs: currentFlowTempReadings + * @details \b Outputs: none + * @param sensor ID of flow sensor to get temperature reading for. + * @return The filtered current flow sensor temperature (in deg C) of the given flow sensor. + *************************************************************************/ +F32 getFilteredFlowSensorTemperature( FLOW_SENSORS_T sensor ) +{ + F32 result = 0.0F; + + if ( sensor < NUM_OF_FLOW_SENSORS ) + { + result = filteredcurrentFlowTempReadings[ sensor ].data; + if ( OVERRIDE_KEY == filteredcurrentFlowTempReadings[ sensor ].override ) + { + result = filteredcurrentFlowTempReadings[ sensor ].ovData; + } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FLOW_SENSOR_INVALID_SENSOR4, (U32)sensor ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The execFlowMonitor function executes the flow monitor state machine + * and publishes flow data. + * @note This function should be called periodically to maintain monitoring + * of the flow sensors. + * @details \b Inputs: flowsState + * @details \b Outputs: flowsState + * @details \b Alarm: ALARM_ID_FP_SOFTWARE_FAULT if in invalid flow state + * @return none + *************************************************************************/ +void execFlowMonitor( void ) +{ + // state machine + switch ( flowsState ) + { + case FLOW_INIT_STATE: + flowsState = handleFlowsInitState(); + break; + + case FLOW_CONTINUOUS_READ_STATE: + flowsState = handleFlowsContReadState(); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FLOW_INVALID_EXEC_STATE, (U32)flowsState ) + flowsState = FLOW_INIT_STATE; + break; + } + + // publish flow data on interval + publishFlowsData(); +} + +/*********************************************************************//** + * @brief + * The filterFlowSensorReadings function filters the flow rates for + * defined interval to get average flow rates. + * @details \b Inputs: filteredFlowReadings[] + * @details \b Outputs: filteredFlowReadings[], filteredcurrentFlowReadings[] + * @return none + *************************************************************************/ +static void filterFlowSensorReadings( void ) +{ + FLOW_SENSORS_T sensor; + + for ( sensor = FLOW_SENSOR_FIRST; sensor < NUM_OF_FLOW_SENSORS; sensor++ ) + { + F32 rawFlow = (F32)getFlowRate( sensor ); + + // TODO - calibrate + + if ( filteredFlowReadings[sensor].flowReadingsCount >= SIZE_OF_FLOW_ROLLING_AVG ) + { + filteredFlowReadings[sensor].flowReadingsTotal -= filteredFlowReadings[sensor].flowReadings[ filteredFlowReadings[sensor].flowReadingsIdx ]; + } + filteredFlowReadings[sensor].flowReadings[ filteredFlowReadings[sensor].flowReadingsIdx ] = rawFlow; + filteredFlowReadings[sensor].flowReadingsTotal += rawFlow; + filteredFlowReadings[sensor].flowReadingsIdx = INC_WRAP( filteredFlowReadings[sensor].flowReadingsIdx, 0, SIZE_OF_FLOW_ROLLING_AVG - 1 ); + filteredFlowReadings[sensor].flowReadingsCount = INC_CAP( filteredFlowReadings[sensor].flowReadingsCount, SIZE_OF_FLOW_ROLLING_AVG ); + filteredcurrentFlowReadings[sensor].data = filteredFlowReadings[sensor].flowReadingsTotal / (F32)filteredFlowReadings[sensor].flowReadingsCount; + } +} + +/*********************************************************************//** + * @brief + * The filterPressureSensorTemperatureReadings function filters the flow sensor + * temperature for defined interval to get moving average temperature reading. + * @details \b Inputs: filteredFlowTempReadings[] + * @details \b Outputs: filteredFlowTempReadings[], filteredcurrentFlowTempReadings[] + * @return none + *************************************************************************/ +static void filterFlowSensorTemperatureReadings( void ) +{ + FLOW_SENSORS_T sensor; + + for ( sensor = FLOW_SENSOR_FIRST; sensor < NUM_OF_FLOW_SENSORS; sensor++ ) + { + F32 flowTemperature = getFlowTemperature( sensor ); + + // TODO - calibrate? + + if ( filteredFlowTempReadings[sensor].flowTempReadingsCount >= SIZE_OF_FLOW_TEMP_ROLLING_AVG ) + { + filteredFlowTempReadings[sensor].flowTempReadingsTotal -= filteredFlowTempReadings[sensor].flowTempReadings[ filteredFlowTempReadings[sensor].flowTempReadingsIdx ]; + } + filteredFlowTempReadings[sensor].flowTempReadings[ filteredFlowTempReadings[sensor].flowTempReadingsIdx ] = flowTemperature; + filteredFlowTempReadings[sensor].flowTempReadingsTotal += flowTemperature; + filteredFlowTempReadings[sensor].flowTempReadingsIdx = INC_WRAP( filteredFlowTempReadings[sensor].flowTempReadingsIdx, 0, SIZE_OF_FLOW_TEMP_ROLLING_AVG - 1 ); + filteredFlowTempReadings[sensor].flowTempReadingsCount = INC_CAP( filteredFlowTempReadings[sensor].flowTempReadingsCount, SIZE_OF_FLOW_TEMP_ROLLING_AVG ); + filteredcurrentFlowTempReadings[sensor].data = filteredFlowTempReadings[sensor].flowTempReadingsTotal / (F32)filteredFlowTempReadings[sensor].flowTempReadingsCount; + } +} + +/*********************************************************************//** + * @brief + * The getCalibrationAppliedFlow function applies the calibration values + * to a given flow sensor and filtered flow rate and returns a calibrated flow. + * @details \b Inputs: flowsCalRecord + * @details \b Outputs: none + * @param sensorId the ID of the flow sensor + * @param flow the flow rate before applying calibration to it + * @return calibration applied flow rate + *************************************************************************/ +//static F32 getCalibrationAppliedFlow( U08 sensorId, F32 flow ) +//{ +// F32 calFlow = pow( flow, 4 ) * flowsCalRecord.flowSensors[ (FLOW_SENSORS_T)sensorId ].fourthOrderCoeff + +// pow( flow, 3 ) * flowsCalRecord.flowSensors[ (FLOW_SENSORS_T)sensorId ].thirdOrderCoeff + +// pow( flow, 2 ) * flowsCalRecord.flowSensors[ (FLOW_SENSORS_T)sensorId ].secondOrderCoeff + +// flow * flowsCalRecord.flowSensors[ (FLOW_SENSORS_T)sensorId ].gain + +// flowsCalRecord.flowSensors[ (FLOW_SENSORS_T)sensorId ].offset; +// return calFlow; +//} + +/*********************************************************************//** + * @brief + * The handleFlowsInitState function handles the flows initialize state + * of the flow monitor state machine. + * @details \b Inputs: none + * @details \b Outputs: none + * @return next state + *************************************************************************/ +static FLOW_STATE_T handleFlowsInitState( void ) +{ + return FLOW_CONTINUOUS_READ_STATE; +} + +/*********************************************************************//** + * @brief + * The handleFlowsContReadState function handles the continuous read state + * of the flows monitor state machine. Raw readings are read from driver + * and then filtered via moving average and calibrated. + * @details \b Inputs: raw readings from flow sensor driver + * @details \b Outputs: flow sensors are sampled, filtered and calibrated. + * @return next state + *************************************************************************/ +static FLOW_STATE_T handleFlowsContReadState( void ) +{ + FLOW_STATE_T result = FLOW_CONTINUOUS_READ_STATE; + + // Get raw flow readings + readFlowSensors(); + // filter raw flow readings + filterFlowSensors(); + + return result; +} + +/*********************************************************************//** + * @brief + * The publishFlowsData function publishes FP flow data at a set interval. + * @details \b Inputs: flowsDataPublicationTimerCounter + * @details \b Outputs: flowsDataPublicationTimerCounter + * @details \b Message \b Sent: MSG_ID_FP_FLOW_DATA to publish flow data. + * @return none + *************************************************************************/ +static void publishFlowsData( void ) +{ + // publish pressure/occlusion data on interval + if ( ++flowsDataPublicationTimerCounter >= getU32OverrideValue( &flowsDataPublishInterval ) ) + { + FLOW_TEMP_DATA_T data; + + data.p7Flow = getFilteredFlow( P7_FLOW ); + data.p16Flow = getFilteredFlow( P16_FLOW ); + data.p7Temp = getFilteredFlowSensorTemperature( P7_FLOW ); + data.p16Temp = getFilteredFlowSensorTemperature( P16_FLOW ); + + broadcastData( MSG_ID_FP_FLOW_DATA, COMM_BUFFER_OUT_CAN_FP_BROADCAST, (U08*)&data, sizeof( FLOW_TEMP_DATA_T ) ); + flowsDataPublicationTimerCounter = 0; + } +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testFlowSensorDataPublishIntervalOverride function overrides the + * flow sensor data publish interval. + * @details \b Inputs: none + * @details \b Outputs: flowsDataPublishInterval + * @param message Override message from Dialin which includes the value + * that override flow data publish interval with (in ms) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testFlowSensorDataPublishIntervalOverride( MESSAGE_T *message ) +{ + BOOL result = u32BroadcastIntervalOverride( message, &flowsDataPublishInterval, TASK_PRIORITY_INTERVAL ); + + return result; +} + +/*********************************************************************//** + * @brief + * The testFlowSensorFilteredReadingsOverride function overrides the + * filtered value of the specified flow sensor with a given value. + * @details \b Inputs: none + * @details \b Outputs: filteredcurrentFlowReadings[] + * @param message Override message from Dialin which includes a sensor + * ID and override value of the flow rate for that sensor. + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testFlowSensorFilteredReadingsOverride( MESSAGE_T *message ) +{ + BOOL result = f32ArrayOverride( message, &filteredcurrentFlowReadings[0], NUM_OF_FLOW_SENSORS - 1 ); + + return result; +} + +/*********************************************************************//** + * @brief + * The testFlowSensorFilteredTemperatureReadingsOverride function overrides the + * value of the specified flow sensor filtered temperature with a given value. + * @details \b Inputs: none + * @details \b Outputs: filteredcurrentFlowTempReadings[] + * @param message Override message from Dialin which includes a sensor + * ID and override value of the flow sensor temperature. + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testFlowSensorFilteredTemperatureReadingsOverride( MESSAGE_T *message ) +{ + BOOL result = f32ArrayOverride( message, &filteredcurrentFlowTempReadings[0], NUM_OF_FLOW_SENSORS - 1 ); + + return result; +} + +/**@}*/ Index: firmware/App/Monitors/Flow.h =================================================================== diff -u --- firmware/App/Monitors/Flow.h (revision 0) +++ firmware/App/Monitors/Flow.h (revision a0c144ed9f72066d7a7b1d047b01fb76ca56d667) @@ -0,0 +1,58 @@ +/************************************************************************** +* +* 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 Flow.h +* +* @author (last) Sean Nash +* @date (last) 21-Nov-2024 +* +* @author (original) Sean Nash +* @date (original) 21-Nov-2024 +* +***************************************************************************/ + +#ifndef __FLOW_H__ +#define __FLOW_H__ + +#include "FPCommon.h" +#include "FlowSensor.h" + +/** + * @defgroup Flow Flow + * @brief Flow sensors monitor unit. Monitors the various RO flow + * sensors. + * + * @addtogroup Flow + * @{ + */ + +// ********** public definitions ********** + +/// Flow data record. +typedef struct +{ + F32 p7Flow; ///< P7 flow rate at water inlet. + F32 p16Flow; ///< P16 flow rate at RO filter outlet. + F32 p7Temp; ///< P7 temperature from inlet flow sensor. + F32 p16Temp; ///< P16 temperature from outlet flow sensor. +} FLOW_TEMP_DATA_T; + +// ********** public function prototypes ********** + +void initFlow( void ); +void execFlowMonitor( void ); + +F32 getFilteredFlow( FLOW_SENSORS_T sensor ); +F32 getFilteredFlowSensorTemperature( FLOW_SENSORS_T sensor ); + +BOOL testFlowSensorDataPublishIntervalOverride( MESSAGE_T *message ); +BOOL testFlowSensorFilteredReadingsOverride( MESSAGE_T *message ); +BOOL testFlowSensorFilteredTemperatureReadingsOverride( MESSAGE_T *message ); + +/**@}*/ + +#endif Index: firmware/App/Monitors/Level.h =================================================================== diff -u -r229341f9eb23fec730cdf9b1f8f3960de2daf384 -ra0c144ed9f72066d7a7b1d047b01fb76ca56d667 --- firmware/App/Monitors/Level.h (.../Level.h) (revision 229341f9eb23fec730cdf9b1f8f3960de2daf384) +++ firmware/App/Monitors/Level.h (.../Level.h) (revision a0c144ed9f72066d7a7b1d047b01fb76ca56d667) @@ -38,6 +38,7 @@ D6_LEVL = 0, ///< floater switch low, medium and high status D63_LEVL, ///< bicarb level low or high status D46_LEVL, ///< Spent dialysate air separation chamber level low or high status + P25_LEVL, ///< IOFP floater sensor. low, medium, and high NUM_OF_LEVELS ///< Number of levels } LELVEL_T; Index: firmware/App/Monitors/WaterQualityMonitor.c =================================================================== diff -u --- firmware/App/Monitors/WaterQualityMonitor.c (revision 0) +++ firmware/App/Monitors/WaterQualityMonitor.c (revision a0c144ed9f72066d7a7b1d047b01fb76ca56d667) @@ -0,0 +1,239 @@ +/************************************************************************** +* +* 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 "FPModeStandby.h" +#include "FPOperationModes.h" +#include "PersistentAlarm.h" +#include "Pressure.h" +#include "SystemCommDD.h" +#include "TaskPriority.h" +#include "Temperature.h" +#include "WaterQualityMonitor.h" + +/** + * @addtogroup WaterQualityMonitor + * @{ + */ + +// ********** private definitions ********** +#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 ********** + +// ********** private function prototypes ********** + +/*********************************************************************//** + * @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 ) +{ + // 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 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 = getFilteredConductivitySensorTemperature( P9_COND ); + 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 ); +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/**@}*/ Index: firmware/App/Monitors/WaterQualityMonitor.h =================================================================== diff -u --- firmware/App/Monitors/WaterQualityMonitor.h (revision 0) +++ firmware/App/Monitors/WaterQualityMonitor.h (revision a0c144ed9f72066d7a7b1d047b01fb76ca56d667) @@ -0,0 +1,46 @@ +/************************************************************************** +* +* 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.h +* +* @author (last) Michael Garthwaite +* @date (last) 21-Nov-2024 +* +* @author (original) Michael Garthwaite +* @date (original) 21-Nov-2024 +* +***************************************************************************/ +#ifndef __WATER_QUALITY_MONITOR_H +#define __WATER_QUALITY_MONITOR_H + +#include "FPCommon.h" +#include "FPDefs.h" + +/** + * @defgroup WaterQualityMonitor WaterQualityMonitor + * @brief WaterQualityMonitor module monitors the inlet water conditions for FP sub-system. + * Considers temperature, pressure, flows, and conductivity. + * WaterQualityMonitor manufacturer: Custom built modules. + * + * @addtogroup WaterQualityMonitor + * @{ + */ + +// ********** public definitions ********** + + +// ********** public definitions ********** +void initWaterQualityMonitor( void ); +void execWaterQualityMonitor( void ); +void checkInletPressures( void ); +void checkROPressures( void ); +void checkPressureRelief( void ); +void checkInletTemperatures( void ); +void checkInletConductivity( void ); +void checkOutletConductivity( void ); + +#endif Index: firmware/App/Services/FPInterface.c =================================================================== diff -u -r88662452040aa91ce9a7da032e9ed1865517bdd5 -ra0c144ed9f72066d7a7b1d047b01fb76ca56d667 --- firmware/App/Services/FPInterface.c (.../FPInterface.c) (revision 88662452040aa91ce9a7da032e9ed1865517bdd5) +++ firmware/App/Services/FPInterface.c (.../FPInterface.c) (revision a0c144ed9f72066d7a7b1d047b01fb76ca56d667) @@ -16,9 +16,14 @@ ***************************************************************************/ #include "FPInterface.h" +#include "FPOperationModes.h" #include "Messaging.h" #include "MessagePayloads.h" #include "ModeInitPOST.h" +#include "ModeGenPermeate.h" +#include "ModeGenPermeateDefeatured.h" +#include "ModePreGenPermeate.h" +#include "ModePreGenPermeateDefeatured.h" #include "ModeStandby.h" #include "OperationModes.h" #include "PersistentAlarm.h" @@ -33,19 +38,16 @@ // ********** private definitions ********** -#define FP_DATA_FRESHNESS_TIMEOUT_MS ( 3 * MS_PER_SECOND ) ///< FP data freshness timeout (in ms). #define MAX_FP_FLOW_RATE ( 700.0F ) ///< Max FP pump flow rate // ********** private data ********** -static FP_OP_MODE_T fpCurrentOpMode; ///< Current TD operation mode. -static U32 fpSubMode; ///< Current state (sub-mode) of current TD operation mode. static F32 fpFlowRate; ///< FP flow rate -static BOOL fpOpModeDataFreshFlag = FALSE; ///< Flag to signal/process fresh FP op mode data // ********** private function prototypes ********** -static void checkFPDataFreshness( ALARM_ID_T alarmID, BOOL *fpFreshDataFlag ); +static BOOL handlePreGenCmd( BOOL start ); +static BOOL handleGenWaterCmd( BOOL start ); /*********************************************************************//** * @brief @@ -56,60 +58,11 @@ *************************************************************************/ void initFPInterface( void ) { - // Initialize unit variables - fpCurrentOpMode = FP_MODE_INIT; - fpSubMode = 0; - fpFlowRate = MAX_FP_FLOW_RATE; + fpFlowRate = MAX_FP_FLOW_RATE; } -/**********************************************************************//** - * @brief - * The checkFPDataFreshness function checks the freshness of data coming from - * the FP sub-system. - * @details \b Alarm: Given alarm is triggered if FP is communicating but has - * not published new data for too long. - * @details \b Inputs: FP communicating flag - * @details \b Outputs: none - * @param alarm ID of alarm to check - * @param fpFreshDataFlag Pointer to flag indicating whether new data has been - * received since last time this function has seen it. - * @return None - *************************************************************************/ -static void checkFPDataFreshness( ALARM_ID_T alarmID, BOOL *fpFreshDataFlag ) -{ - if ( TRUE == *fpFreshDataFlag ) - { - *fpFreshDataFlag = FALSE; - checkPersistentAlarm( alarmID, FALSE, 0.0, 0.0 ); - } - else - { // Alarm if not receiving FP fresh data message in timely manner - if ( TRUE == isFPCommunicating() ) - { - checkPersistentAlarm( alarmID, TRUE, 0.0, 0.0 ); - } - else - { - checkPersistentAlarm( alarmID, FALSE, 0.0, 0.0 ); - } - } -} - /*********************************************************************//** * @brief - * The execFPInterfaceMonitor function executes the FP Interface monitoring - * function. Ensures FP is sending fresh data in a timely manner. - * @details \b Inputs: none - * @details \b Outputs: none - * @return none - *************************************************************************/ -void execFPInterfaceMonitor( void ) -{ - -} - -/*********************************************************************//** - * @brief * The setFPFlowRate function sets the FP pump flow rate to deliver purified * water. * @details \b Inputs: none @@ -135,56 +88,112 @@ /*********************************************************************//** * @brief - * The getFPOpMode function gets the current latest reported FP operating mode. - * @details \b Inputs: fpCurrentOpMode - * @details \b Outputs: none - * @return Latest reported FP operating mode. + * The requestFPGeneratePermeate function handles a FP permeate + * request from DD. + * @details Inputs: none + * @details Outputs: message handled + * @param cmdID the ID of the command + * @param start the TRUE FALSE bool to determine start or stop + * @return TRUE if message is sucessfully parsed, FALSE if not. *************************************************************************/ -FP_OP_MODE_T getFPOpMode( void ) +BOOL requestFPGeneratePermeate( RO_CMD_ID cmdID, BOOL start ) { - return fpCurrentOpMode; + BOOL result = FALSE; + F32 flow = getFPFlowRate(); + + switch ( cmdID ) + { + case RO_PRE_GEN: + result = handlePreGenCmd( start ); + break; + case RO_GEN_WATER: + result = handleGenWaterCmd( start ); + break; + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FP_INVALID_FP_CMD, cmdID ) + break; + } + + return result; } /*********************************************************************//** * @brief - * The getFPSubMode function gets the latest reported FP operating sub-mode. - * @details \b Inputs: fpSubMode - * @details \b Outputs: none - * @return Latest reported FP operating sub-mode. + * The handlePreGenCmd function handles a FP pre generate water + * request from DD and updates permeate flow rate. + * @details Inputs: none + * @details Outputs: message handled + * @param start the TRUE FALSE bool to determine start or stop + * @return TRUE if message is sucessfully parsed, FALSE if not. *************************************************************************/ -U32 getFPSubMode( void ) +static BOOL handlePreGenCmd( BOOL start ) { - return fpSubMode; + BOOL result = FALSE; + FP_OP_MODE_T fpMode = getCurrentFPOperationMode(); + + if ( ( FP_MODE_STAN == fpMode ) && ( TRUE == start ) ) + { + if ( TRUE == isFPDefeatured() ) + { + result = requestPreGenDefStart(); + } + else + { + result = requestPreGenStart(); + } + } + else if ( FP_MODE_PGEN == fpMode ) + { + if ( FALSE == start ) + { + result = requestPreGenStop(); + } + else + { + result = TRUE; + } + } + else if ( FP_MODE_DPGP == fpMode ) + { + result = requestPreGenDefStop(); + } + + return result; } /*********************************************************************//** * @brief - * The setFPOpMode function sets the latest FP operating mode reported by - * the FP (called by FP published message handler). - * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT if reported FP mode is invalid. - * @details \b Inputs: none - * @details \b Outputs: fpCurrentOpMode, fpSubMode, fpOpModeDataFreshFlag - * @param opMode The operating mode reported by FP - * @param subMode The sub-mode of operating mode reported by FP - * @return none + * The handleGenWaterCmd function handles a generate water + * request from DD and updates permeate flow rate. + * @details Inputs: none + * @details Outputs: message handled + * @param start the TRUE FALSE bool to determine start or stop + * @return TRUE if message is sucessfully parsed, FALSE if not. *************************************************************************/ -void setFPOpMode( U32 opMode, U32 subMode ) +static BOOL handleGenWaterCmd( BOOL start ) { - if ( opMode < NUM_OF_FP_MODES ) + BOOL result = FALSE; + + if ( TRUE == start ) { - // update FP op mode and sub-mode - fpCurrentOpMode = (FP_OP_MODE_T)opMode; - fpSubMode = subMode; + if ( TRUE == isFPDefeatured() ) + { + result = requestGenWaterDefStart(); + } + else + { + result = requestGenWaterStart(); + } } else { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_FP_OPERATING_MODE, opMode ); + result = requestGenWaterStop(); + result = TRUE; } - fpOpModeDataFreshFlag = TRUE; + return result; } - /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ Index: firmware/App/Services/FPInterface.h =================================================================== diff -u -re0102a0a08c0d83bcc8e959551079063e2e60d9f -ra0c144ed9f72066d7a7b1d047b01fb76ca56d667 --- firmware/App/Services/FPInterface.h (.../FPInterface.h) (revision e0102a0a08c0d83bcc8e959551079063e2e60d9f) +++ firmware/App/Services/FPInterface.h (.../FPInterface.h) (revision a0c144ed9f72066d7a7b1d047b01fb76ca56d667) @@ -41,7 +41,7 @@ void initFPInterface( void ); void execFPInterfaceMonitor( void ); -BOOL cmdFPStartStop( BOOL startStop, RO_CMD_ID cmdMode); +BOOL requestFPGeneratePermeate( RO_CMD_ID cmdID, BOOL start ); void setFPFlowRate( F32 fpFlow ); F32 getFPFlowRate( void ); Index: firmware/App/Services/TDInterface.c =================================================================== diff -u -r333e2d0c0462dcb4343a279420949cce716ebab7 -ra0c144ed9f72066d7a7b1d047b01fb76ca56d667 --- firmware/App/Services/TDInterface.c (.../TDInterface.c) (revision 333e2d0c0462dcb4343a279420949cce716ebab7) +++ firmware/App/Services/TDInterface.c (.../TDInterface.c) (revision a0c144ed9f72066d7a7b1d047b01fb76ca56d667) @@ -16,6 +16,7 @@ ***************************************************************************/ #include "DialysatePumps.h" +#include "FPInterface.h" #include "Messaging.h" #include "MessagePayloads.h" #include "ModeGenDialysate.h" @@ -345,12 +346,16 @@ // Process the pre-gen dialysate delivery request message if ( ( DD_MODE_STAN == ddMode ) && ( TRUE == startPreGenRequest.start ) ) { + // Start FP Pre-Generate Permeate + requestFPGeneratePermeate( RO_PRE_GEN, TRUE ); // start pre-gen dialysate result = requestDDPreGenStart(); // Update Temperature, Acid/Bicarb type and dialysate rate for pregen process. setTDDialysateFlowrate( startPreGenRequest.dialRate ); setTDTargetDialysateTemperature( startPreGenRequest.dialTemp ); setTDAcidAndBicarbType( startPreGenRequest.acidType, startPreGenRequest.bicarbType ); + + } else if ( DD_MODE_PREG == ddMode ) { Index: firmware/DD.dil =================================================================== diff -u -r88662452040aa91ce9a7da032e9ed1865517bdd5 -ra0c144ed9f72066d7a7b1d047b01fb76ca56d667 --- firmware/DD.dil (.../DD.dil) (revision 88662452040aa91ce9a7da032e9ed1865517bdd5) +++ firmware/DD.dil (.../DD.dil) (revision a0c144ed9f72066d7a7b1d047b01fb76ca56d667) @@ -1,4 +1,4 @@ -# RM46L852PGE 09/08/25 10:13:51 +# RM46L852PGE 09/08/25 14:56:28 # ARCH=RM46L852PGE #