Index: firmware/.settings/org.eclipse.core.resources.prefs =================================================================== diff -u -r533272e6ef2873fcfe7a41338a6c88c7a601605d -rc7dcb245c2378b1c96eeaa02f120f61dff598b11 --- firmware/.settings/org.eclipse.core.resources.prefs (.../org.eclipse.core.resources.prefs) (revision 533272e6ef2873fcfe7a41338a6c88c7a601605d) +++ firmware/.settings/org.eclipse.core.resources.prefs (.../org.eclipse.core.resources.prefs) (revision c7dcb245c2378b1c96eeaa02f120f61dff598b11) @@ -1,8 +1,12 @@ eclipse.preferences.version=1 +encoding//Debug/App/Controllers/subdir_rules.mk=UTF-8 +encoding//Debug/App/Controllers/subdir_vars.mk=UTF-8 encoding//Debug/App/Drivers/subdir_rules.mk=UTF-8 encoding//Debug/App/Drivers/subdir_vars.mk=UTF-8 encoding//Debug/App/Modes/subdir_rules.mk=UTF-8 encoding//Debug/App/Modes/subdir_vars.mk=UTF-8 +encoding//Debug/App/Monitors/subdir_rules.mk=UTF-8 +encoding//Debug/App/Monitors/subdir_vars.mk=UTF-8 encoding//Debug/App/Services/subdir_rules.mk=UTF-8 encoding//Debug/App/Services/subdir_vars.mk=UTF-8 encoding//Debug/App/Tasks/subdir_rules.mk=UTF-8 Index: firmware/App/Controllers/Valves.c =================================================================== diff -u --- firmware/App/Controllers/Valves.c (revision 0) +++ firmware/App/Controllers/Valves.c (revision c7dcb245c2378b1c96eeaa02f120f61dff598b11) @@ -0,0 +1,468 @@ +/************************************************************************** +* +* 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 Valves.c +* +* @author (last) Sean Nash +* @date (last) 09-Nov-2024 +* +* @author (original) Sean Nash +* @date (original) 09-Nov-2024 +* +***************************************************************************/ + +#include // For memcpy + +#include "FpgaRO.h" +#include "MessageSupport.h" +#include "Messaging.h" +#include "TaskPriority.h" +#include "Timers.h" +#include "Valves.h" + +/** + * @addtogroup Valves + * @{ + */ + +// ********** private definitions ********** + +#define DEENERGIZED 0 ///< 0 for de-energized valve. +#define ENERGIZED 1 ///< 1 for energized valve. +#define ALL_VALVES_DEENERGIZED 0x0000 ///< 0 in U16 bit field for all valves. + +#define MAX_VALVE_STATE_MISMATCH_TIMER_COUNT (100 / TASK_PRIORITY_INTERVAL ) ///< Maximum time commanded valves state can fail to match read back valve states in a row. + +#define VALVES_STATE_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Interval ( ms / task time ) at which valves states are published on CAN bus. +#define DATA_PUBLISH_COUNTER_START_COUNT 50 ///< Data publish counter start count. + +/// Payload record structure for valve open/close request +typedef struct +{ + U32 valveID; ///< ValveID ( valid range 0 to 28 ) + U32 valveState; ///< Valve state ( Open : 0, closed :1) +} VALVE_CMD_PAYLOAD_T; + +// ********** private data ********** + +static U32 valvesStatesPublicationTimerCounter; ///< Timer counter used to schedule valve state publication to CAN bus. +static U16 commandedValvesStates; ///< Initialize commanded valves states bit field. +static U32 valveStateMismatchTimerCounter; ///< Initialize valve state mismatch timer. +static U32 pendingValveStateChanges[ NUM_OF_VALVES ]; ///< Delayed (pending) valve state changes. +static U32 pendingValveStateChangeCountDowns[ NUM_OF_VALVES ]; ///< Delayed (pending) valve state change count down timers (in task intervals). + +static OVERRIDE_U32_T valveStates[ NUM_OF_VALVES ]; ///< Currently commanded valves states. +static OVERRIDE_U32_T valveSensedStates[ NUM_OF_VALVES ]; ///< Valve sensed states override. +static OVERRIDE_U32_T valvesStatesPublishInterval = { VALVES_STATE_PUB_INTERVAL, VALVES_STATE_PUB_INTERVAL, 0, 0 }; ///< Interval (in ms/task interval) at which to publish valves state to CAN bus. + +// ********** private function prototypes ********** + +static void publishValvesStates( void ); +static void readCommandedValveStates( void ); +static U32 convertValveStateNameToValveState( VALVE_STATE_NAMES_T valveStateName ); +static U32 getValveState( U32 valveID ); + +/*********************************************************************//** + * @brief + * The initValves function initializes the Valves unit. + * @details \b Inputs: none + * @details \b Outputs: Valves unit initialized + * @return none + *************************************************************************/ +void initValves( void ) +{ + U32 valve; + + // initialize valve states + for ( valve = 0; valve < NUM_OF_VALVES; valve++ ) + { + valveStates[ valve ].data = DEENERGIZED; + valveStates[ valve ].ovInitData = DEENERGIZED; + valveStates[ valve ].ovData = DEENERGIZED; + valveStates[ valve ].override = OVERRIDE_RESET; + pendingValveStateChanges[ valve ] = DEENERGIZED; + pendingValveStateChangeCountDowns[ valve ] = 0; + valveSensedStates[ valve ].data = DEENERGIZED; + valveSensedStates[ valve ].ovInitData = DEENERGIZED; + valveSensedStates[ valve ].ovData = DEENERGIZED; + valveSensedStates[ valve ].override = OVERRIDE_RESET; + } + + // initialize timer counters + valveStateMismatchTimerCounter = 0; + valvesStatesPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; // reset valves states publication timer + + // initially set all valves to de-energized state via FPGA + readCommandedValveStates(); + setFPGAValveStates( commandedValvesStates ); +} + +/*********************************************************************//** + * @brief + * The execValves function executes the valves controller. + * @details \b Inputs: valvesStates, valveStateMismatchCounter + * pendingValveStateChangeCountDowns, commandedValvesStates + * @details \b Outputs: valvesStates, valveStateMismatchCounter + * pendingValveStateChanges, valve controls + * @details \b Alarm: ALARM_ID_RO_VALVE_CONTROL_FAILURE when FPGA read back + * valve state mismatches with the commanded valve state after defined time (100ms). + * @return none + *************************************************************************/ +void execValves( void ) +{ + U32 valve; + U16 readValvesStates = getFPGAValveStates(); // get valves states from FPGA + + // Verify read back FPGA valve states match last commanded valve states + if ( readValvesStates != commandedValvesStates ) + { + valveStateMismatchTimerCounter++; // increment valve state mismatch counter by 1 + if ( valveStateMismatchTimerCounter > MAX_VALVE_STATE_MISMATCH_TIMER_COUNT ) + { +// activateAlarmNoData( ALARM_ID_RO_VALVE_CONTROL_FAILURE ); + } + } + else + { + valveStateMismatchTimerCounter = 0; + } + + // Handle pending delayed valve state changes + for ( valve = 0; valve < NUM_OF_VALVES; valve++ ) + { + if ( pendingValveStateChangeCountDowns[ valve ] > 0 ) + { + pendingValveStateChangeCountDowns[ valve ]--; + if ( 0 == pendingValveStateChangeCountDowns[ valve ] ) + { + valveStates[ valve ].data = pendingValveStateChanges[ valve ]; + pendingValveStateChanges[ valve ] = DEENERGIZED; + } + } + } + + // Set valves states (via FPGA) to currently commanded states + readCommandedValveStates(); + setFPGAValveStates( commandedValvesStates ); + + // Publish valve states on interval + publishValvesStates(); +} + +/*********************************************************************//** + * @brief + * The readCommandedValveStates function gets the hydraulics, Balancing chamber + * and Ultrafiltration valvesStates that can be passed to FPGA for setting valves. + * @details \b Inputs: valveStates[] + * @details \b Outputs: commandedValvesStates + * @return none + *************************************************************************/ +static void readCommandedValveStates( void ) +{ + U32 valve; + + // Initiliaze before updating commanded states + commandedValvesStates = ALL_VALVES_DEENERGIZED; + + // flag hydraulics valves that are currently commanded to be energized + for ( valve = FIRST_VALVE; valve < NUM_OF_VALVES; valve++ ) + { + commandedValvesStates |= ( getValveState( valve ) == ENERGIZED ? 0x0001 << valve : 0 ); + } +} + +/*********************************************************************//** + * @brief + * The convertValveStateNameToValveState function converts valve state \n + * name to its corresponding de-energized (0) or energized (1) valve state. + * @details \b Inputs: none + * @details \b Outputs: none + * @details \b Alarm : ALARM_ID_RO_SOFTWARE_FAULT when invalid valve state name passed + * @param valveStateName valve state name enumeration to convert to energized/de-energized + * @return converted valve state for given valve state name + *************************************************************************/ +static U32 convertValveStateNameToValveState( VALVE_STATE_NAMES_T valveStateName ) +{ + U32 vState = DEENERGIZED; // initialize valve state to de-energized + + if ( valveStateName < NUM_OF_VALVE_STATES ) + { + if ( VALVE_STATE_OPEN == valveStateName ) + { + vState = ENERGIZED; + } + } + else + { +// SET_ALARM_WITH_2_U32_DATA( ALARM_ID_RO_SOFTWARE_FAULT, SW_FAULT_ID_VALVES_INVALID_VALVE_STATE_NAME, valveStateName ) + } + + return vState; +} + +/*********************************************************************//** + * @brief + * The setValveState function sets the valve state for given valve. + * @details \b Inputs: none + * @details \b Outputs: valveStates[], pendingValveStateChanges[], pendingValveStateChangeCountDowns[] + * @details \b Alarm: ALARM_ID_RO_SOFTWARE_FAULT when invalid valve ID passed + * @param valveID ID of valve to set state for + * @param valveStateName name of valve state to set given valve to + * @return TRUE if new valve state is set for given valve ID, FALSE if not. + *************************************************************************/ +BOOL setValveState( VALVES_T valveID, VALVE_STATE_NAMES_T valveStateName ) +{ + BOOL result = FALSE; // initialize result flag to FALSE + + if ( valveID < NUM_OF_VALVES ) + { + if ( valveStateName < NUM_OF_VALVE_STATES ) + { + valveStates[ valveID ].data = convertValveStateNameToValveState( valveStateName ); + result = TRUE; + // If a delayed state change is pending for this valve, cancel it + pendingValveStateChanges[ valveID ] = DEENERGIZED; + pendingValveStateChangeCountDowns[ valveID ] = 0; + } + else + { +// SET_ALARM_WITH_2_U32_DATA( ALARM_ID_RO_SOFTWARE_FAULT, SW_FAULT_ID_VALVES_INVALID_VALVE_STATE, valveID ) + } + } + else + { +// SET_ALARM_WITH_2_U32_DATA( ALARM_ID_RO_SOFTWARE_FAULT, SW_FAULT_ID_VALVES_INVALID_VALVE_ID, valveID ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The setValveStateDelayed function sets the valve state for given valve + * after a given delay. + * @details \b Inputs: pendingValveStateChangeCountDowns[] + * @details \b Outputs: pendingValveStateChangeCountDowns[], pendingValveStateChangeCountDowns[] + * @details \b Alarm: ALARM_ID_RO_SOFTWARE_FAULT when invalid valve ID passed + * @param valveID ID of valve to set state for + * @param valveStateName name of valve state to set given valve to + * @param delayMs delay duration (in ms) before actuation + * @return TRUE if new valve state is set for given valve ID, FALSE if not. + *************************************************************************/ +BOOL setValveStateDelayed( VALVES_T valveID, VALVE_STATE_NAMES_T valveStateName, U32 delayMs ) +{ + BOOL result = FALSE; // initialize result flag to FALSE + + if ( valveID < NUM_OF_VALVES ) + { + if ( valveStateName < NUM_OF_VALVE_STATES ) + { + // If a delayed state change is already pending for this valve, execute it now before setting a new delayed state change + if ( pendingValveStateChangeCountDowns[ valveID ] > 0 ) + { + valveStates[ valveID ].data = pendingValveStateChanges[ valveID ]; + } + // Set delayed valve state change + pendingValveStateChanges[ valveID ] = convertValveStateNameToValveState( valveStateName ); + pendingValveStateChangeCountDowns[ valveID ] = delayMs / TASK_PRIORITY_INTERVAL; + result = TRUE; + } + else + { +// SET_ALARM_WITH_2_U32_DATA( ALARM_ID_RO_SOFTWARE_FAULT, SW_FAULT_ID_VALVES_INVALID_VALVE_STATE, valveID ) + } + } + else + { +// SET_ALARM_WITH_2_U32_DATA( ALARM_ID_RO_SOFTWARE_FAULT, SW_FAULT_ID_VALVES_INVALID_VALVE_ID, valveID ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getValveStateName function gets the current valve state enum for a + * given valve. + * @details \b Inputs: valveStates[] + * @details \b Outputs: none + * @details \b Alarm: ALARM_ID_RO_SOFTWARE_FAULT when invalid valve ID passed. + * @param valveID ID of valve to get state for + * @return the current valve state for given valve in enum + *************************************************************************/ +VALVE_STATE_NAMES_T getValveStateName( VALVES_T valveID ) +{ + // Initialized per CppCheck. + VALVE_STATE_NAMES_T name = NUM_OF_VALVE_STATES; + + if ( valveID < NUM_OF_VALVES ) + { + U32 valveState = getU32OverrideValue( &valveStates[ valveID ] ); + + if ( OVERRIDE_KEY == valveSensedStates[ valveID ].override ) + { + valveState = valveSensedStates[ valveID ].ovData; + } + + name = ( ENERGIZED == valveState ? VALVE_STATE_OPEN : VALVE_STATE_CLOSED ); + } + else + { +// SET_ALARM_WITH_2_U32_DATA( ALARM_ID_RO_SOFTWARE_FAULT, SW_FAULT_ID_VALVES_INVALID_VALVE_ID, valveID ) + } + + return name; +} + +/*********************************************************************//** + * @brief + * The getValveState function gets the current valve state for given valve. + * @details \b Inputs: valveStates[] + * @details \b Outputs: none + * @details \b Alarm : ALARM_ID_RO_SOFTWARE_FAULT when invalid valve ID passed + * @param valveID ID of valve to get state for + * @return the current valve state for given valve + *************************************************************************/ +static U32 getValveState( U32 valveID ) +{ + U32 valveState = DEENERGIZED; + + if ( valveID < NUM_OF_VALVES ) + { + valveState = getU32OverrideValue( &valveStates[ valveID ] ); + } + else + { +// SET_ALARM_WITH_2_U32_DATA( ALARM_ID_RO_SOFTWARE_FAULT, SW_FAULT_ID_VALVES_INVALID_VALVE_ID, valveID ) + } + + return valveState; +} + +/*********************************************************************//** + * @brief + * The publishValvesStates function publishes DG valves states at the set interval. + * @details \b Inputs: valvesStatesPublicationTimerCounter + * @details \b Outputs: valvesStatesPublicationTimerCounter + * @details \b Message \b Sent: MSG_ID_RO_VALVES_STATES_DATA to publish FPGA read valve states. + * @return none + *************************************************************************/ +static void publishValvesStates( void ) +{ + // publish valve state on interval + if ( ++valvesStatesPublicationTimerCounter >= getU32OverrideValue( &valvesStatesPublishInterval ) ) + { + RO_VALVES_DATA_T data; + U32 valve; + + data.valvesStatus = getFPGAValveStates(); + + for ( valve = 0; valve < NUM_OF_VALVES; valve++ ) + { + data.valvesSensedState[ valve ] = (U08)getValveStateName( (VALVES_T)valve ); + } + +// broadcastData( MSG_ID_RO_VALVES_STATES_DATA, COMM_BUFFER_OUT_CAN_DD_BROADCAST, (U08*)&data, sizeof( RO_VALVES_DATA_T ) ); + + valvesStatesPublicationTimerCounter = 0; + } +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testValvesStatesPublishIntervalOverride function overrides the + * valves states publish interval. + * @details \b Inputs: none + * @details \b Outputs: valvesStatesPublishInterval + * @param message Override message from Dialin which includes the value + * that override valves states publish interval with (in ms) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testValvesStatesPublishIntervalOverride( MESSAGE_T *message ) +{ + BOOL result = u32BroadcastIntervalOverride( message, &valvesStatesPublishInterval, TASK_PRIORITY_INTERVAL ); + + return result; +} + +/*********************************************************************//** + * @brief + * The testValveStateOverride function overrides the value of the + * specified valve with a given value. + * @details \b Inputs: none + * @details \b Outputs: valveStates[] + * @param message Override message from Dialin which includes an ID of + * the valve to override and the state to override the valve to. + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testValveStateOverride( MESSAGE_T *message ) +{ + BOOL result = u32ArrayOverride( message, &valveStates[0], NUM_OF_VALVES - 1, 0, NUM_OF_VALVE_STATES - 1 ); + + return result; +} + +/*********************************************************************//** + * @brief + * The testValveSensedStateOverride function overrides the value of the + * specified sensed state with a given value. + * @details \b Inputs: none + * @details \b Outputs: valveSensedStates[] + * @param message Override message from Dialin which includes an ID of + * the valve to override and the state to override the valve to. + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testValveSensedStateOverride( MESSAGE_T *message ) +{ + BOOL result = u32ArrayOverride( message, &valveSensedStates[0], NUM_OF_VALVES - 1, 0, NUM_OF_VALVE_STATES - 1 ); + + return result; +} + +/*********************************************************************//** + * @brief + * The testValveOpenCloseStateOverride function overrides the value of the + * specified valve with a given value. + * @details \b Inputs: tester logged in + * @details \b Outputs: valveStates[] + * @param message set message from Dialin which includes the valve Id to set + * and the state to set the valves to. + * @return TRUE if set request is successful, FALSE if not + *************************************************************************/ +BOOL testValveOpenCloseStateOverride( MESSAGE_T *message ) +{ + BOOL result = FALSE; + + // Verify tester has logged in with TD + if ( TRUE == isTestingActivated() ) + { + // Verify payload length is valid + if ( sizeof( VALVE_CMD_PAYLOAD_T ) == message->hdr.payloadLen ) + { + VALVE_CMD_PAYLOAD_T payload; + + memcpy( &payload, message->payload, sizeof(VALVE_CMD_PAYLOAD_T) ); + + if ( ( (VALVES_T)payload.valveID < NUM_OF_VALVES ) && + ( (VALVE_STATE_NAMES_T)payload.valveState < NUM_OF_VALVE_STATES ) ) + { + setValveState( (VALVES_T)payload.valveID, (VALVE_STATE_NAMES_T)payload.valveState ); + result = TRUE; + } + } + } + + return result; +} + +/**@}*/ Index: firmware/App/Controllers/Valves.h =================================================================== diff -u --- firmware/App/Controllers/Valves.h (revision 0) +++ firmware/App/Controllers/Valves.h (revision c7dcb245c2378b1c96eeaa02f120f61dff598b11) @@ -0,0 +1,80 @@ +/************************************************************************** +* +* 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 Valves.h +* +* @author (last) Sean Nash +* @date (last) 09-Nov-2024 +* +* @author (original) Sean Nash +* @date (original) 09-Nov-2024 +* +***************************************************************************/ + +#ifndef __VALVES_H__ +#define __VALVES_H__ + +#include "ROCommon.h" + +/** + * @defgroup Valves Valves + * @brief Valves driver unit. Controls all RO valves through FPGA Interface. + * + * @addtogroup Valves + * @{ + */ + +/// Enumeration of valves. +typedef enum Valves +{ + VFF = 0, ///< Valve (P6) + FIRST_VALVE = 0, ///< First valve + VPI, ///< Valve (P11) + VLP, ///< Valve (P21) + VCR, ///< Valve (P33) + VCB, ///< Valve (P34) + VCD, ///< Valve (P37) + VROD, ///< Valve (P39) + NUM_OF_VALVES ///< Number of valves +} VALVES_T; + +/// Enumeration of available valve state names per valve type (from SA and DG SRS documents). +typedef enum ValveStateNames +{ + VALVE_STATE_OPEN = 0, ///< Open valve state, + VALVE_STATE_CLOSED, ///< Closed valve state, + NUM_OF_VALVE_STATES ///< number of valve states +} VALVE_STATE_NAMES_T; + +#pragma pack(push, 1) +/// Valves publish structure +typedef struct +{ + U16 valvesStatus; ///< 2 way valves status. + U08 valvesBCStatus; ///< Balancing chamber valves status. + U08 valvesUFStatus; ///< Ultrafiltration valves status. + U08 valvesSensedState[ NUM_OF_VALVES ]; ///< DD valves sensed states. +} RO_VALVES_DATA_T; +#pragma pack(pop) + +// ********** public function prototypes ********** + +void initValves( void ); +void execValves( void ); + +BOOL setValveState( VALVES_T valve, VALVE_STATE_NAMES_T valveState ); +BOOL setValveStateDelayed( VALVES_T valve, VALVE_STATE_NAMES_T valveState, U32 delayMs ); +VALVE_STATE_NAMES_T getValveStateName( VALVES_T valveID ); + +BOOL testValvesStatesPublishIntervalOverride( MESSAGE_T *message ); +BOOL testValveStateOverride( MESSAGE_T *message ); +BOOL testValveSensedStateOverride( MESSAGE_T *message ); +BOOL testValveOpenCloseStateOverride( MESSAGE_T *message ); + +/**@}*/ + +#endif Index: firmware/App/Monitors/Conductivity.c =================================================================== diff -u --- firmware/App/Monitors/Conductivity.c (revision 0) +++ firmware/App/Monitors/Conductivity.c (revision c7dcb245c2378b1c96eeaa02f120f61dff598b11) @@ -0,0 +1,139 @@ +/************************************************************************** +* +* 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 Conductivity.c +* +* @author (last) Vinayakam Mani +* @date (last) 10-Sep-2024 +* +* @author (original) Vinayakam Mani +* @date (original) 10-Sep-2024 +* +***************************************************************************/ +#include // Used for calculating the polynomial calibration equation. +#include // For memcpy + +#include "Conductivity.h" +#include "MessageSupport.h" +#include "Messaging.h" +#include "OperationModes.h" +#include "TaskPriority.h" +#include "Utilities.h" + +/** + * @addtogroup Conductivity + * @{ + */ + +// ********** private definitions ********** + +#define COND_SENSOR_REPORT_PERIOD ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Broadcast conductivity values message every second. +#define DATA_PUBLISH_COUNTER_START_COUNT 40 ///< Data publish counter start count. + +// ********** private data ********** + +static U32 conductivityPublishTimerCounter; +static OVERRIDE_U32_T conductivityDataPublishInterval = { COND_SENSOR_REPORT_PERIOD, + COND_SENSOR_REPORT_PERIOD, 0, 0 }; ///< Conductivity sensors publish time interval override. + +// ********** private function prototypes ********** + +static void publishConductivitySensorsData( void ); + +/*********************************************************************//** + * @brief + * The initConductivity function initializes the ConductivitySensors module. + * @details \b Inputs: none + * @details \b Outputs: Conductivity unit variables initialized + * @return none + *************************************************************************/ +void initConductivity( void ) +{ + conductivityPublishTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; + + initConductivitySensors(); +} + +/*********************************************************************//** + * @brief + * The execConductivity function gets conductivity sensors' latest + * readings from FPGA and publishes them over CAN. + * @details \b Inputs: none + * @details \b Outputs: Conductivity sensor latest reading is updated and + * published. + * @return none + *************************************************************************/ +void execConductivity( void ) +{ + //read conductivity sensors raw value + readConductivitySensors(); + + //control conductivity sensor + // TODO : need more clarity on why and when to execute following control. + handleConductivitySensorsReset(); + handleConductivitySensorsInitProcedure(); + execConductivitySensorWrite(); + execConductivitySensorRead(); + + // publish conductivity sensors + publishConductivitySensorsData(); +} + +/*********************************************************************//** + * @brief + * The publishConductivitySensorsData function publishes DD conductivity data + * at a set interval. + * @details \b Inputs: conductivityPublishTimerCounter + * @details \b Outputs: conductivityPublishTimerCounter + * @details \b Message \b Sent: MSG_ID_DD_CONDUCTIVITY_DATA to publish conductivity data. + * @return none + *************************************************************************/ +static void publishConductivitySensorsData( void ) +{ + // publish pressure/occlusion data on interval + if ( ++conductivityPublishTimerCounter >= getU32OverrideValue( &conductivityDataPublishInterval ) ) + { + CONDUCTIVITY_DATA_T data; + + data.cd1 = getConductivityValue( CONDUCTIVITYSENSORS_CD1_SENSOR ); + data.cd2 = getConductivityValue( CONDUCTIVITYSENSORS_CD2_SENSOR ); + data.cd3 = getConductivityValue( CONDUCTIVITYSENSORS_CD3_SENSOR ); + data.cd4 = getConductivityValue( CONDUCTIVITYSENSORS_CD4_SENSOR ); + data.td1 = getConductivityTemperatureValue( CONDUCTIVITYSENSORS_CD1_SENSOR ); + data.td2 = getConductivityTemperatureValue( CONDUCTIVITYSENSORS_CD2_SENSOR ); + data.td3 = getConductivityTemperatureValue( CONDUCTIVITYSENSORS_CD3_SENSOR ); + data.td4 = getConductivityTemperatureValue( CONDUCTIVITYSENSORS_CD4_SENSOR ); + conductivityPublishTimerCounter = 0; + + broadcastData( MSG_ID_DD_CONDUCTIVITY_DATA, COMM_BUFFER_OUT_CAN_DD_BROADCAST, (U08*)&data, sizeof( CONDUCTIVITY_DATA_T ) ); + } +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testConductivitySensorDataPublishIntervalOverride function overrides the + * conductivity sensor data publish interval. + * @details \b Inputs: none + * @details \b Outputs: conductivityDataPublishInterval + * @param message Override message from Dialin which includes the value + * that override valves states publish interval with (in ms) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testConductivitySensorDataPublishIntervalOverride( MESSAGE_T *message ) +{ + BOOL result = u32BroadcastIntervalOverride( message, &conductivityDataPublishInterval, TASK_PRIORITY_INTERVAL ); + + return result; +} + +/**@}*/ Index: firmware/App/Monitors/Conductivity.h =================================================================== diff -u --- firmware/App/Monitors/Conductivity.h (revision 0) +++ firmware/App/Monitors/Conductivity.h (revision c7dcb245c2378b1c96eeaa02f120f61dff598b11) @@ -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 Conductivity.h +* +* @author (last) Vinayakam Mani +* @date (last) 10-Sep-2024 +* +* @author (original) Vinayakam Mani +* @date (original) 10-Sep-2024 +* +***************************************************************************/ + +#ifndef __CONDUCTIVITY_H__ +#define __CONDUCTIVITY_H__ + +#include "DDCommon.h" +#include "ConductivitySensors.h" + +/** + * @defgroup Conductivity Conductivity + * @brief Conductivity Sensors monitor module. Monitors and filters conductivity sensor readings. + * + * + * + * @addtogroup Conductivity + * @{ + */ + +// ********** public definitions ********** + +/// Conductivity data struct. +typedef struct +{ + F32 cd1; ///< CD1 conductivity sensor value + F32 cd2; ///< CD2 conductivity sensor value + F32 cd3; ///< CD3 conductivity sensor value + F32 cd4; ///< CD4 conductivity sensor value + F32 td1; ///< TD1 temperature value + F32 td2; ///< TD2 temperature value + F32 td3; ///< TD3 temperature value + F32 td4; ///< TD4 temperature value +} CONDUCTIVITY_DATA_T; + +// ********** public function prototypes ********** + +void initConductivity( void ); +void execConductivity( void ); + +BOOL testConductivitySensorDataPublishIntervalOverride( MESSAGE_T *message ); + +/**@}*/ + +#endif Index: firmware/App/Monitors/Level.c =================================================================== diff -u --- firmware/App/Monitors/Level.c (revision 0) +++ firmware/App/Monitors/Level.c (revision c7dcb245c2378b1c96eeaa02f120f61dff598b11) @@ -0,0 +1,271 @@ +/************************************************************************** +* +* 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 Level.c +* +* @author (last) Vinayakam Mani +* @date (last) 11-Oct-2024 +* +* @author (original) Vinayakam Mani +* @date (original) 11-Oct-2024 +* +***************************************************************************/ + +#include "FpgaDD.h" +#include "Level.h" +#include "MessageSupport.h" +#include "Messaging.h" +#include "TaskPriority.h" +#include "Timers.h" + +/** + * @addtogroup Level + * @{ + */ + +// ********** private definitions ********** + +#define LEVEL_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Interval (ms/task time) at which the level data is published on the CAN bus. +#define LEVEL_DEBOUNCE_TIME_MS ( MS_PER_SECOND / 10 ) ///< Level debounce time in milliseconds. +#define DATA_PUBLISH_COUNTER_START_COUNT 7 ///< Data publish counter start count. + +/// Level status structure +typedef struct +{ + OVERRIDE_U32_T status; ///< Level status. + U32 debounceStartTime; ///< Debounce start time. + U32 debounceTime; ///< Debounce time +} LEVEL_STATUS_T; + +// ********** private data ********** + +static U32 levelsDataPublicationCounter; ///< Level data publication counter. +static OVERRIDE_U32_T levelsDataPublishInterval = { LEVEL_DATA_PUB_INTERVAL, + LEVEL_DATA_PUB_INTERVAL, 0, 0 }; ///< Interval (in ms) at which to publish Level data to CAN bus. +static LEVEL_STATUS_T levelsStatus[ NUM_OF_LEVELS ]; ///< Level status array. + +// ********** private function prototypes ********** + +static void publishLevelsData( void ); + +/*********************************************************************//** + * @brief + * The initLevels function initializes the level module. + * @details \b Inputs: none + * @details \b Outputs: Level unit variables initialized. + * @return none + *************************************************************************/ +void initLevels( void ) +{ + U32 i; + + levelsDataPublicationCounter = DATA_PUBLISH_COUNTER_START_COUNT; + + // Initialize all the Level + for ( i = 0; i < NUM_OF_LEVELS; i++ ) + { + levelsStatus[ i ].status.data = (U32)STATE_HIGH; + levelsStatus[ i ].status.ovData = (U32)STATE_HIGH; + levelsStatus[ i ].status.ovInitData = (U32)STATE_HIGH; + levelsStatus[ i ].status.override = OVERRIDE_RESET; + levelsStatus[ i ].debounceStartTime = 0; + levelsStatus[ i ].debounceTime = LEVEL_DEBOUNCE_TIME_MS; + } +} + +/*********************************************************************//** + * @brief + * The execLevels function executes the floater and level sensor states. + * @details \b Inputs: level sensor and floater reading from FPGA + * @details \b Outputs: levelStatus + * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid level sensor + * executed. + * @return none + *************************************************************************/ +void execLevels( void ) +{ + U32 i; + U32 currentLevelStatus = 0; + + for ( i = 0; i < NUM_OF_LEVELS; i++ ) + { + // Get the current level status + switch ( i ) + { + // Process the status of the Level + case FLOATER_1: + currentLevelStatus = ( getFPGAFloater1Status() != 0 ? STATE_LOW : STATE_MEDIUM ); + break; + + case FLOATER_2: + currentLevelStatus = ( getFPGAFloater2Status() != 0 ? STATE_MEDIUM : STATE_HIGH ); + break; + + case BICARB_LEVEL: + currentLevelStatus = ( getFPGALevelSensor1() != 0 ? STATE_LOW : STATE_HIGH ); + break; + + case SPENT_DIALYSATE_LEVEL: + currentLevelStatus = ( getFPGALevelSensor2() != 0 ? STATE_LOW : STATE_HIGH ); + break; + +#ifndef _VECTORCAST_ + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_LEVEL_SELECTED, i ); + break; +#endif + } + + // Check if the current level status is not the same as the recorded data + if ( currentLevelStatus != levelsStatus[ i ].status.data ) + { + // If the debounce time is 0, start the timer + if ( 0 == levelsStatus[ i ].debounceStartTime ) + { + levelsStatus[ i ].debounceStartTime = getMSTimerCount(); + } + // If the debounce time has been elapsed, update the level sensor status to the new status + else if ( TRUE == didTimeout( levelsStatus[ i ].debounceStartTime, levelsStatus[ i ].debounceTime ) ) + { + switch ( i ) + { + case FLOATER_1: + SEND_EVENT_WITH_2_U32_DATA( DD_EVENT_FLOATER_1_LEVEL_CHANGE, (U32)levelsStatus[ i ].status.data, (U32)currentLevelStatus ); + break; + + case FLOATER_2: + SEND_EVENT_WITH_2_U32_DATA( DD_EVENT_FLOATER_2_LEVEL_CHANGE, (U32)levelsStatus[ i ].status.data, (U32)currentLevelStatus ); + break; + + case BICARB_LEVEL: + SEND_EVENT_WITH_2_U32_DATA( DD_EVENT_BICARB_LEVEL_CHANGE, (U32)levelsStatus[ i ].status.data, (U32)currentLevelStatus ); + break; + + case SPENT_DIALYSATE_LEVEL: + SEND_EVENT_WITH_2_U32_DATA( DD_EVENT_SPENT_DIALYSATE_LEVEL_CHANGE, (U32)levelsStatus[ i ].status.data, (U32)currentLevelStatus ); + break; + +#ifndef _VECTORCAST_ + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_LEVEL_SELECTED, i ); + break; +#endif + } + + levelsStatus[ i ].debounceStartTime = 0; + levelsStatus[ i ].status.data = currentLevelStatus; + } + } + else + { + levelsStatus[ i ].debounceStartTime = 0; + } + } + + publishLevelsData(); +} + +/*********************************************************************//** + * @brief + * The getLevelStatus function returns the status of the called level sensor. + * @details \b Inputs: levelStatus + * @details \b Outputs: levelStatus + * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid level sensor + * passed. + * @param levelId which is the sensor that its status is requested + * @return level status + *************************************************************************/ +LEVEL_STATE_T getLevelStatus( LELVEL_T levelId ) +{ + U32 status = 0; + + if ( levelId < NUM_OF_LEVELS ) + { + // Assume there is no override + status = levelsStatus[ levelId ].status.data; + + if ( OVERRIDE_KEY == levelsStatus[ levelId ].status.override ) + { + status = levelsStatus[ levelId ].status.ovData; + } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_DD_INVALID_LEVEL_ID, (U32)levelId ) + } + + return (LEVEL_STATE_T)status; +} + +/*********************************************************************//** + * @brief + * The publishLevelsData function broadcasts the level data at the + * publication interval. + * @details \b Inputs: levelsDataPublicationCounter + * @details \b Outputs: levelsDataPublicationCounter + * @details \b Message \b Sent: MSG_ID_DD_LEVEL_DATA to publish level + * sensors data. + * @return none + *************************************************************************/ +static void publishLevelsData( void ) +{ + if ( ++levelsDataPublicationCounter >= getU32OverrideValue( &levelsDataPublishInterval ) ) + { + LEVEL_DATA_T data; + + data.floater1Level = (U32)getLevelStatus( FLOATER_1 ); + data.floater2Level = (U32)getLevelStatus( FLOATER_2 ); + data.bicarbLevel = (U32)getLevelStatus( BICARB_LEVEL ); + data.spentDialysateLevel = (U32)getLevelStatus( SPENT_DIALYSATE_LEVEL ); + + levelsDataPublicationCounter = 0; + + broadcastData( MSG_ID_DD_LEVEL_DATA, COMM_BUFFER_OUT_CAN_DD_BROADCAST, (U08*)&data, sizeof( LEVEL_DATA_T ) ); + } +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testLevelsDataPublishIntervalOverride function overrides + * the Level publish data interval. + * @details \b Inputs: levelsDataPublishInterval + * @details \b Outputs: levelsDataPublishInterval + * @param Override message from Dialin which includes the interval + * (in ms) to override the level data broadcast interval to. + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testLevelsDataPublishIntervalOverride( MESSAGE_T *message ) +{ + BOOL result = u32BroadcastIntervalOverride( message, &levelsDataPublishInterval, TASK_PRIORITY_INTERVAL ); + + return result; +} + +/*********************************************************************//** + * @brief + * The testLevelStatusOverride function sets the override status + * for a specific level sensor. + * @details \b Inputs: none + * @details \b Outputs: levelStatus + * @param message Override message from Dialin which includes an ID of + * the level sensor to override and the state to override the level sensor to. + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testLevelStatusOverride( MESSAGE_T *message ) +{ + BOOL result = u32ArrayOverride( message, &levelsStatus[0].status, NUM_OF_LEVELS - 1, 0, NUM_OF_LEVELS_STATES -1 ); + + return result; +} + +/**@}*/ Index: firmware/App/Monitors/Level.h =================================================================== diff -u --- firmware/App/Monitors/Level.h (revision 0) +++ firmware/App/Monitors/Level.h (revision c7dcb245c2378b1c96eeaa02f120f61dff598b11) @@ -0,0 +1,74 @@ +/************************************************************************** +* +* 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 Level.h +* +* @author (last) Vinayakam Mani +* @date (last) 11-Oct-2024 +* +* @author (original) Vinayakam Mani +* @date (original) 11-Oct-2024 +* +***************************************************************************/ + +#ifndef LEVEL_H_ +#define LEVEL_H_ + +#include "DDCommon.h" + +/** + * @defgroup Level Level + * @brief Level module monitors the floater levels, Bicarb gas separation level and Spent + * dialsate balance air separation level. + * Level manufacturer: Custom built modules. + * + * @addtogroup Level + * @{ + */ + +// ********** public definitions ********** + +/// DD floater and level sensor enumeration +typedef enum level_names +{ + FLOATER_1 = 0, ///< floater switch low to medium status + FLOATER_2, ///< floater switch medium to high status + BICARB_LEVEL, ///< bicarb level low or high status + SPENT_DIALYSATE_LEVEL, ///< Spent dialysate air separation chamber level low or high status + NUM_OF_LEVELS ///< Number of levels +} LELVEL_T; + +/// floater and level sensor states. +typedef enum level_States +{ + STATE_LOW = 0, ///< Low level + STATE_HIGH, ///< High level + STATE_MEDIUM, ///< Medium level + NUM_OF_LEVELS_STATES ///< Number of level states +} LEVEL_STATE_T; + +/// DD floater and level sensor data publish structure +typedef struct +{ + U32 floater1Level; ///< Floater 1 level + U32 floater2Level; ///< Floater 2 level + U32 bicarbLevel; ///< Bicarb level + U32 spentDialysateLevel; ///< Spent dialysate level +} LEVEL_DATA_T; + +// ********** public function prototypes ********** + +void initLevels( void ); +void execLevels( void ); +LEVEL_STATE_T getLevelStatus( LELVEL_T levelId ); + +BOOL testLevelsDataPublishIntervalOverride( MESSAGE_T *message ); +BOOL testLevelStatusOverride( MESSAGE_T *message ); + +/**@}*/ + +#endif Index: firmware/App/Monitors/Pressure.c =================================================================== diff -u --- firmware/App/Monitors/Pressure.c (revision 0) +++ firmware/App/Monitors/Pressure.c (revision c7dcb245c2378b1c96eeaa02f120f61dff598b11) @@ -0,0 +1,557 @@ +/************************************************************************** +* +* 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 Pressure.c +* +* @author (last) Vinayakam Mani +* @date (last) 04-Sep-2024 +* +* @author (original) Vinayakam Mani +* @date (original) 04-Sep-2024 +* +***************************************************************************/ + +#include "AlarmMgmtDD.h" +#include "Messaging.h" +#include "Pressure.h" +#include "PersistentAlarm.h" +#include "TaskPriority.h" +#include "Valves.h" + +/** + * @addtogroup Pressure + * @{ + */ + +// ********** private definitions ********** + +#define PRESSURES_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Interval (ms/task time) at which the pressures data is published on the CAN bus. +#define DATA_PUBLISH_COUNTER_START_COUNT ( 5 ) ///< Data publish counter start count. +#define PRESSURE_SAMPLE_FILTER_MS ( 200 ) ///< Filter pressure data for given time +#define PRESSURE_TEMP_SAMPLE_FILTER_MS ( 200 ) ///< Filter temperature data for given time +#define SIZE_OF_PRESSURE_ROLLING_AVG ( PRESSURE_SAMPLE_FILTER_MS / TASK_PRIORITY_INTERVAL ) ///< Filtered pressure moving average. +#define SIZE_OF_PRESSURETEMP_ROLLING_AVG ( PRESSURE_TEMP_SAMPLE_FILTER_MS / TASK_PRIORITY_INTERVAL ) ///< Filtered pressure temprature w/ 1 second moving average. +#define MMHG_TO_PSI_CONVERSION 0.0193368F ///< MMHG to PSI conversion. + +#define MIN_INLET_WATER_PRESSURE_WARNING_LOW_PSIG 20.0F ///< Minimum allowed Input low pressure value in psig. +#define MAX_INLET_WATER_PRESSURE_WARNING_HIGH_PSIG 80.0F ///< Maximum allowed Input high pressure value in psig. +#define MIN_INLET_PRESSURE_TO_CLEAR_WARINING_PSIG 24.0F ///< Minimum allowed Input low pressure value in psig ( to clear alarm) +#define MIN_INLET_WATER_PRESSURE_WARNING_HIGH_PSIG 78.0F ///< Minimum allowed Input high pressure value in psig. +#define INLET_WATER_PRES_OUT_OF_RANGE_TIMEOUT_MS ( 20 * MS_PER_SECOND ) ///< Persistence period for pressure out of range error in milliseconds. +#define INLET_WATER_PRES_OUT_OF_RANGE_CLEAR_MS ( 10 * MS_PER_SECOND ) ///< Persistence period for pressure out of range clear in milliseconds. + +#define MIN_INLET_WATER_PRES_OUT_WARNING_LOW_PSIG 10.0F ///< Minimum allowed output low pressure value in psig. +#define MAX_INLET_WATER_PRES_OUT_WARNING_HIGH_PSIG 20.0F ///< Maximum allowed output high pressure value in psig. +#define MIN_INLET_PRES_OUT_TO_CLEAR_WARINING_PSIG 11.0F ///< Minimum allowed output low pressure value in psig ( to clear alarm) +#define MIN_INLET_WATER_PRES_OUT_WARNING_HIGH_PSIG 18.0F ///< Minimum allowed output high pressure value in psig. + +/// Defined states for the pressures monitor state machine. +typedef enum PresMonitor_States +{ + PRESSURE_INIT_STATE = 0, ///< Initialization state. + PRESSURE_CONTINUOUS_READ_STATE, ///< Continuous read sensors state. + NUM_OF_PRESSURE_STATES ///< Number of pressure monitor states. +} PRESSURE_STATE_T; + +/// Filter pressure reading. +typedef struct +{ + F32 pressureReadings[ SIZE_OF_PRESSURE_ROLLING_AVG ]; ///< Holds pressure sample rolling average. + U32 pressureReadingsIdx; ///< Index for next sample in rolling average array. + F32 pressureReadingsTotal; ///< Rolling total - used to calc average. + U32 pressureReadingsCount; ///< Number of samples in rolling average buffer +}FILTER_PRESSURE_READINGS_T; + +/// Filter pressuretemperature reading. +typedef struct +{ + F32 pressureTempReadings[ SIZE_OF_PRESSURETEMP_ROLLING_AVG ]; ///< Holds pressure temperature sample rolling average. + U32 pressureTempReadingsIdx; ///< Index for next sample in rolling average array. + F32 pressureTempReadingsTotal; ///< Rolling total - used to calc average. + U32 pressureTempReadingsCount; ///< Number of samples in rolling average buffer +}FILTER_PRESSURE_TEMPERATURE_READINGS_T; + +// ********** private data ********** + +static OVERRIDE_F32_T filteredcurrentPressureReadings[ NUM_OF_PRESSURE_SENSORS ]; ///< filtered current pressure sensor pressure readings (overrideable). +static OVERRIDE_F32_T filteredcurrentPresTempReadings[ NUM_OF_PRESSURE_SENSORS ]; ///< filtered current pressure sensor temperature readings (overrideable). +//static DD_PRES_SENSORS_CAL_RECORD_T pressuresCalRecord; ///< Pressures calibration record. + +static FILTER_PRESSURE_READINGS_T filteredPressureReadings[NUM_OF_PRESSURE_SENSORS]; ///< Filtered pressure reading for pressure sensors. +static FILTER_PRESSURE_TEMPERATURE_READINGS_T filteredPressureTempReadings[NUM_OF_PRESSURE_SENSORS]; ///< Filtered pressure reading for pressure sensors. +static PRESSURE_STATE_T pressuresState; ///< current state of pressure monitor state machine. +static U32 pressuresDataPublicationTimerCounter; ///< used to schedule pressure data publication to CAN bus. +static OVERRIDE_U32_T pressuresDataPublishInterval = { PRESSURES_DATA_PUB_INTERVAL, + PRESSURES_DATA_PUB_INTERVAL, 0, 0 }; ///< Pressure data publish interval. + +// ********** private function prototypes ********** + +static void filterPressureSensorReadings( void ); +static void filterPressureSensorTemperatureReadings( void ); +//static F32 getCalibrationAppliedPressure( U08 sensorId, F32 pressure ); +static F32 getConvertedPressure( PRESSURE_SENSORS_T sensor, F32 pressure ); +static PRESSURE_STATE_T handlePressuresInitState( void ); +static PRESSURE_STATE_T handlePressuresContReadState( void ); +static void publishPressuresData( void ); + +/*********************************************************************//** + * @brief + * The initPressureSensor function initializes the Pressure Sensor unit. + * @details \b Inputs: none + * @details \b Outputs: Pressure Sensor unit is initialized. + * @return none + *************************************************************************/ +void initPressure( void ) +{ + U32 i; + + pressuresState = PRESSURE_INIT_STATE; + pressuresDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; + + initPressureSensor(); + + // Initialize override structures for each pressure sensor + for ( i = (U32)PRESSURE_SENSOR_FIRST; i < (U32)NUM_OF_PRESSURE_SENSORS; i++ ) + { + filteredcurrentPressureReadings[ i ].data = 0.0F; + filteredcurrentPressureReadings[ i ].ovData = 0.0F; + filteredcurrentPressureReadings[ i ].ovInitData = 0.0F; + filteredcurrentPressureReadings[ i ].override = OVERRIDE_RESET; + + filteredcurrentPresTempReadings[ i ].data = 0.0F; + filteredcurrentPresTempReadings[ i ].ovData = 0.0F; + filteredcurrentPresTempReadings[ i ].ovInitData = 0.0F; + filteredcurrentPresTempReadings[ i ].override = OVERRIDE_RESET; + + filteredPressureReadings[i].pressureReadingsCount = 0; + filteredPressureReadings[i].pressureReadingsIdx = 0; + filteredPressureReadings[i].pressureReadingsTotal = 0.0F; + + filteredPressureTempReadings[i].pressureTempReadingsCount = 0; + filteredPressureTempReadings[i].pressureTempReadingsIdx = 0; + filteredPressureTempReadings[i].pressureTempReadingsTotal = 0.0F; + } + + initPersistentAlarm( ALARM_ID_DD_INLET_WATER_PRESSURE_IN_LOW_RANGE, INLET_WATER_PRES_OUT_OF_RANGE_CLEAR_MS, INLET_WATER_PRES_OUT_OF_RANGE_TIMEOUT_MS ); + initPersistentAlarm( ALARM_ID_DD_INLET_WATER_PRESSURE_IN_HIGH_RANGE, INLET_WATER_PRES_OUT_OF_RANGE_CLEAR_MS, INLET_WATER_PRES_OUT_OF_RANGE_TIMEOUT_MS ); + initPersistentAlarm( ALARM_ID_DD_INLET_WATER_PRESSURE_OUT_LOW_RANGE, INLET_WATER_PRES_OUT_OF_RANGE_CLEAR_MS, INLET_WATER_PRES_OUT_OF_RANGE_TIMEOUT_MS ); + initPersistentAlarm( ALARM_ID_DD_INLET_WATER_PRESSURE_OUT_HIGH_RANGE, INLET_WATER_PRES_OUT_OF_RANGE_CLEAR_MS, INLET_WATER_PRES_OUT_OF_RANGE_TIMEOUT_MS ); +} + +/*********************************************************************//** + * @brief + * The filterPressureSensors function gets averages the raw pressure and + * temperature readings. + * @note This function should be called periodically to maintain fresh + * sensor filtered readings for all pressure sensors. + * @details \b Inputs: currentPressureReadings[],currentPresTempReadings[], + * @details \b Outputs: filteredPressureReadings[], filteredPressureTempReadings[] + * @return none + *************************************************************************/ +static void filterPressureSensors( void ) +{ + //Filter pressure sensor reading + filterPressureSensorReadings(); + + //Filter pressure sensor temperature reading + filterPressureSensorTemperatureReadings(); +} + +/*********************************************************************//** + * @brief + * The getFilteredPressure function gets the filtered current pressure (in mmHg) + * for a given pressure sensor. + * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT if given sensor is invalid. + * @details \b Inputs: filteredcurrentPressureReadings + * @details \b Outputs: none + * @param sensor ID of pressure sensor to get pressure reading for. + * @return The filtered current pressure (in mmHg) of the given pressure sensor. + *************************************************************************/ +F32 getFilteredPressure( PRESSURE_SENSORS_T sensor ) +{ + F32 result = 0.0F; + + if ( sensor < NUM_OF_PRESSURE_SENSORS ) + { + result = filteredcurrentPressureReadings[ sensor ].data; + if ( OVERRIDE_KEY == filteredcurrentPressureReadings[ sensor ].override ) + { + result = filteredcurrentPressureReadings[ sensor ].ovData; + } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_PRESSURE_SENSOR_INVALID_SENSOR5, sensor ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getFilteredPressureSensorTemperature function gets the filtered current + * pressure sensor temperature (in deg C) for a given pressure sensor. + * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT if given sensor is invalid. + * @details \b Inputs: currentPresTempReadings + * @details \b Outputs: none + * @param sensor ID of pressure sensor to get temperature reading for. + * @return The filtered current pressure sensor temperature (in deg C) of the given pressure sensor. + *************************************************************************/ +F32 getFilteredPressureSensorTemperature( PRESSURE_SENSORS_T sensor ) +{ + F32 result = 0.0F; + + if ( sensor < NUM_OF_PRESSURE_SENSORS ) + { + result = filteredcurrentPresTempReadings[ sensor ].data; + if ( OVERRIDE_KEY == filteredcurrentPresTempReadings[ sensor ].override ) + { + result = filteredcurrentPresTempReadings[ sensor ].ovData; + } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_PRESSURE_SENSOR_INVALID_SENSOR6, sensor ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The checkInletWaterPressure function checks inlet water pressure value + * and triggers an alarm when pressure value is out of allowed range. + * @details \b Inputs: RO pump inlet pressure sensor value + * @details \b Outputs: Triggers low pressure persistent alarm + * @details \b Alarms: ALARM_ID_DD_INLET_WATER_PRESSURE_IN_LOW_RANGE when + * the inlet water pressure is less than the low limit. + * @details \b Alarms: ALARM_ID_DD_INLET_WATER_PRESSURE_IN_HIGH_RANGE when + * the inlet water pressure is greater than the high limit. + * @return none + *************************************************************************/ +void checkInletWaterPressure( void ) +{ + F32 pressureIn = getFilteredPressure( PRESSURE_SENSOR_WATER_INLET_INPUT ); + F32 PressureOut = getFilteredPressure( PRESSURE_SENSOR_WATER_INLET_OUTPUT ); + + //Check Water Inlet Input pressure range + if ( VALVE_STATE_OPEN == getValveStateName( VWI ) ) + { + BOOL isPressureTooLow; + BOOL isPressureTooHigh; + F32 maxInletWaterPressureWarningLow = MIN_INLET_WATER_PRESSURE_WARNING_LOW_PSIG; + F32 minInletWaterPressureWarningLow = MIN_INLET_PRESSURE_TO_CLEAR_WARINING_PSIG; + + isPressureTooLow = ( pressureIn < maxInletWaterPressureWarningLow ? TRUE : FALSE ); + isPressureTooHigh = ( pressureIn > MAX_INLET_WATER_PRESSURE_WARNING_HIGH_PSIG ? TRUE : FALSE ); + + if ( TRUE == isAlarmActive( ALARM_ID_DD_INLET_WATER_PRESSURE_IN_LOW_RANGE ) ) + { + isPressureTooLow = ( pressureIn >= minInletWaterPressureWarningLow ? FALSE : TRUE ); + } + checkPersistentAlarm( ALARM_ID_DD_INLET_WATER_PRESSURE_IN_LOW_RANGE, isPressureTooLow, pressureIn, maxInletWaterPressureWarningLow ); + + if ( TRUE == isAlarmActive( ALARM_ID_DD_INLET_WATER_PRESSURE_IN_HIGH_RANGE ) ) + { + isPressureTooHigh = ( pressureIn <= MIN_INLET_WATER_PRESSURE_WARNING_HIGH_PSIG ? FALSE : TRUE ); + } + checkPersistentAlarm( ALARM_ID_DD_INLET_WATER_PRESSURE_IN_HIGH_RANGE, isPressureTooHigh, pressureIn, MAX_INLET_WATER_PRESSURE_WARNING_HIGH_PSIG ); + } + else + { + // VWI is closed - clear all alarms + checkPersistentAlarm( ALARM_ID_DD_INLET_WATER_PRESSURE_IN_LOW_RANGE, FALSE, pressureIn, MIN_INLET_WATER_PRESSURE_WARNING_LOW_PSIG ); + checkPersistentAlarm( ALARM_ID_DD_INLET_WATER_PRESSURE_IN_HIGH_RANGE, FALSE, pressureIn, MAX_INLET_WATER_PRESSURE_WARNING_HIGH_PSIG ); + } + + //Check Water Inlet Output pressure range + if ( VALVE_STATE_OPEN == getValveStateName( VWI ) ) + { + BOOL isPressureTooLow; + BOOL isPressureTooHigh; + F32 maxInletWaterPressureWarningLow = MIN_INLET_WATER_PRES_OUT_WARNING_LOW_PSIG; + F32 minInletWaterPressureWarningLow = MIN_INLET_PRES_OUT_TO_CLEAR_WARINING_PSIG; + + isPressureTooLow = ( PressureOut < maxInletWaterPressureWarningLow ? TRUE : FALSE ); + isPressureTooHigh = ( PressureOut > MAX_INLET_WATER_PRES_OUT_WARNING_HIGH_PSIG ? TRUE : FALSE ); + + if ( TRUE == isAlarmActive( ALARM_ID_DD_INLET_WATER_PRESSURE_OUT_LOW_RANGE ) ) + { + isPressureTooLow = ( PressureOut >= minInletWaterPressureWarningLow ? FALSE : TRUE ); + } + checkPersistentAlarm( ALARM_ID_DD_INLET_WATER_PRESSURE_OUT_LOW_RANGE, isPressureTooLow, PressureOut, maxInletWaterPressureWarningLow ); + + if ( TRUE == isAlarmActive( ALARM_ID_DD_INLET_WATER_PRESSURE_OUT_HIGH_RANGE ) ) + { + isPressureTooHigh = ( PressureOut <= MIN_INLET_WATER_PRES_OUT_WARNING_HIGH_PSIG ? FALSE : TRUE ); + } + checkPersistentAlarm( ALARM_ID_DD_INLET_WATER_PRESSURE_OUT_HIGH_RANGE, isPressureTooHigh, PressureOut, MAX_INLET_WATER_PRES_OUT_WARNING_HIGH_PSIG ); + } + else + { + // VWI is closed - clear all alarms + checkPersistentAlarm( ALARM_ID_DD_INLET_WATER_PRESSURE_OUT_LOW_RANGE, FALSE, PressureOut, MIN_INLET_WATER_PRES_OUT_WARNING_LOW_PSIG ); + checkPersistentAlarm( ALARM_ID_DD_INLET_WATER_PRESSURE_OUT_HIGH_RANGE, FALSE, PressureOut, MAX_INLET_WATER_PRES_OUT_WARNING_HIGH_PSIG ); + } +} + +/*********************************************************************//** + * @brief + * The execPressureSensor function executes the pressure monitor state machine + * and publish pressure data. + * @details \b Inputs: pressuresState + * @details \b Outputs: pressuresState + * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT if invalid pressure state seen + * @return none + *************************************************************************/ +void execPressureSensor( void ) +{ + // state machine + switch ( pressuresState ) + { + case PRESSURE_INIT_STATE: + pressuresState = handlePressuresInitState(); + break; + + case PRESSURE_CONTINUOUS_READ_STATE: + pressuresState = handlePressuresContReadState(); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_PRESSURE_INVALID_EXEC_STATE, pressuresState ) + pressuresState = PRESSURE_INIT_STATE; + break; + } + + // publish pressure/occlusion data on interval + publishPressuresData(); +} + +/*********************************************************************//** + * @brief + * The filterPressureSensorReadings function filters the pressures for + * defined interval to get average pressure reading. + * @details \b Inputs: filteredPressureReadings,currentPressureReadings + * @details \b Outputs: filteredPressureReadings,filteredcurrentPressureReadings + * @return none + *************************************************************************/ +static void filterPressureSensorReadings( void ) +{ + U32 i; + + for ( i = (U32)PRESSURE_SENSOR_FIRST; i < (U32)NUM_OF_PRESSURE_SENSORS; i++ ) + { + F32 pressureinmmHG = getPressure( (PRESSURE_SENSORS_T)i ); + F32 pressure = getConvertedPressure( (PRESSURE_SENSORS_T)i, pressureinmmHG ); + + if ( filteredPressureReadings[i].pressureReadingsCount >= SIZE_OF_PRESSURE_ROLLING_AVG ) + { + filteredPressureReadings[i].pressureReadingsTotal -= filteredPressureReadings[i].pressureReadings[ filteredPressureReadings[i].pressureReadingsIdx ]; + } + filteredPressureReadings[i].pressureReadings[ filteredPressureReadings[i].pressureReadingsIdx ] = pressure; + filteredPressureReadings[i].pressureReadingsTotal += pressure; + filteredPressureReadings[i].pressureReadingsIdx = INC_WRAP( filteredPressureReadings[i].pressureReadingsIdx, 0, SIZE_OF_PRESSURE_ROLLING_AVG - 1 ); + filteredPressureReadings[i].pressureReadingsCount = INC_CAP( filteredPressureReadings[i].pressureReadingsCount, SIZE_OF_PRESSURE_ROLLING_AVG ); + filteredcurrentPressureReadings[i].data = filteredPressureReadings[i].pressureReadingsTotal / (F32)filteredPressureReadings[i].pressureReadingsCount; + } +} + +/*********************************************************************//** + * @brief + * The filterPressureSensorTemperatureReadings function filters the pressure sensor + * temperature for defined interval to get average temperature reading. + * @details \b Inputs: filteredPressureTempReadings,currentPresTempReadings + * @details \b Outputs: filteredPressureTempReadings,filteredcurrentPresTempReadings + * @return none + *************************************************************************/ +static void filterPressureSensorTemperatureReadings( void ) +{ + U32 i; + + for ( i = (U32)PRESSURE_SENSOR_FIRST; i < (U32)NUM_OF_PRESSURE_SENSORS; i++ ) + { + F32 pressureTemperature = getPressureSensorTemperature( (PRESSURE_SENSORS_T)i ); + + if ( filteredPressureTempReadings[i].pressureTempReadingsCount >= SIZE_OF_PRESSURETEMP_ROLLING_AVG ) + { + filteredPressureTempReadings[i].pressureTempReadingsTotal -= filteredPressureTempReadings[i].pressureTempReadings[ filteredPressureTempReadings[i].pressureTempReadingsIdx ]; + } + filteredPressureTempReadings[i].pressureTempReadings[ filteredPressureTempReadings[i].pressureTempReadingsIdx ] = pressureTemperature; + filteredPressureTempReadings[i].pressureTempReadingsTotal += pressureTemperature; + filteredPressureTempReadings[i].pressureTempReadingsIdx = INC_WRAP( filteredPressureTempReadings[i].pressureTempReadingsIdx, 0, SIZE_OF_PRESSURETEMP_ROLLING_AVG - 1 ); + filteredPressureTempReadings[i].pressureTempReadingsCount = INC_CAP( filteredPressureTempReadings[i].pressureTempReadingsCount, SIZE_OF_PRESSURETEMP_ROLLING_AVG ); + filteredcurrentPresTempReadings[i].data = filteredPressureTempReadings[i].pressureTempReadingsTotal / (F32)filteredPressureTempReadings[i].pressureTempReadingsCount; + } +} + +/*********************************************************************//** + * @brief + * The getConvertedPressure function converts the pressure in PSI unit and + * calibration applied to it. + * @details \b Inputs: none + * @details \b Outputs: none + * @param sensor sesnor id for the calibration to be applied for + * @param pressure pressure (mmHG) to be converted in PSI + * @return converted pressure in PSI. + *************************************************************************/ +static F32 getConvertedPressure( PRESSURE_SENSORS_T sensor, F32 pressure ) +{ + F32 baroPressurePSI = getPressure( PRESSURE_SENSOR_BAROMETRIC ) * MMHG_TO_PSI_CONVERSION; + F32 pressurePSI = pressure * MMHG_TO_PSI_CONVERSION; + + // calibrated pressure + //F32 calPressure = getCalibrationAppliedPressure( sensor, pressurePSI ); + + return pressurePSI; +} + +/*********************************************************************//** + * @brief + * The getCalibrationAppliedPressure function applies the calibration values + * to the provided pressure and returns the values. + * @details \b Inputs: pressuresCalRecord + * @details \b Outputs: none + * @param sensorId the ID of the pressure sensor + * @param pressure the pressure before applying calibration to it + * @return calibration applied pressure + *************************************************************************/ +//static F32 getCalibrationAppliedPressure( U08 sensorId, F32 pressure ) +//{ +// F32 calPressure = pow( pressure, 4 ) * pressuresCalRecord.pressureSensors[ (PRESSURE_SENSORS_T)sensorId ].fourthOrderCoeff + +// pow( pressure, 3 ) * pressuresCalRecord.pressureSensors[ (PRESSURE_SENSORS_T)sensorId ].thirdOrderCoeff + +// pow( pressure, 2 ) * pressuresCalRecord.pressureSensors[ (PRESSURE_SENSORS_T)sensorId ].secondOrderCoeff + +// pressure * pressuresCalRecord.pressureSensors[ (PRESSURE_SENSORS_T)sensorId ].gain + +// pressuresCalRecord.pressureSensors[ (PRESSURE_SENSORS_T)sensorId ].offset; +// return calPressure; +//} + +/*********************************************************************//** + * @brief + * The handlePressuresInitState function handles the pressures initialize state + * of the pressures monitor state machine. + * @details \b Inputs: none + * @details \b Outputs: none + * @return next state + *************************************************************************/ +static PRESSURE_STATE_T handlePressuresInitState( void ) +{ + return PRESSURE_CONTINUOUS_READ_STATE; +} + +/*********************************************************************//** + * @brief + * The handlePressuresContReadState function handles the continuous read state + * of the pressures monitor state machine. + * @details \b Inputs: pressureFilterCounter + * @details \b Outputs: pressure sensor values updated + * @return next state + *************************************************************************/ +static PRESSURE_STATE_T handlePressuresContReadState( void ) +{ + PRESSURE_STATE_T result = PRESSURE_CONTINUOUS_READ_STATE; + + //Get raw pressure value + readPressureSensors(); + // filter pressure readings + filterPressureSensors(); + + return result; +} + +/*********************************************************************//** + * @brief + * The publishPressuresData function publishes DD pressures data at a set interval. + * @details \b Inputs: pressuresDataPublicationTimerCounter + * @details \b Outputs: pressuresDataPublicationTimerCounter + * @details \b Message \b Sent: MSG_ID_DD_PRESSURES_DATA to publish pressure data. + * @return none + *************************************************************************/ +static void publishPressuresData( void ) +{ + // publish pressure/occlusion data on interval + if ( ++pressuresDataPublicationTimerCounter >= getU32OverrideValue( &pressuresDataPublishInterval ) ) + { + PRESSURE_TEMP_DATA_T data; + + data.filteredWaterInletInputPressure = getFilteredPressure( PRESSURE_SENSOR_WATER_INLET_INPUT ); + data.filteredWaterInletOutputPressure = getFilteredPressure( PRESSURE_SENSOR_WATER_INLET_OUTPUT ); + data.filteredHydraulicsOutletPressure = getFilteredPressure( PRESSURE_SENSOR_HYDRAULICS_OUTLET ); + data.filteredBibagPressure = getFilteredPressure( PRESSURE_SENSOR_BIBAG ); + data.filteredSpentdialysatePressure = getFilteredPressure( PRESSURE_SENSOR_SPENT_DIALYSATE ); + data.filteredFreshdialysatePressure = getFilteredPressure( PRESSURE_SENSOR_FRESH_DIALYSATE ); + data.filteredTransmembranePressure = getFilteredPressure( PRESSURE_SENSOR_TRANSMEMBRANE ); + data.filteredWaterInletInputTemp = getFilteredPressureSensorTemperature( PRESSURE_SENSOR_WATER_INLET_INPUT ); + data.filteredWaterInletOutputTemp = getFilteredPressureSensorTemperature( PRESSURE_SENSOR_WATER_INLET_OUTPUT ); + data.filteredHydraulicsOutletTemp = getFilteredPressureSensorTemperature( PRESSURE_SENSOR_HYDRAULICS_OUTLET ); + data.filteredBibagTemp = getFilteredPressureSensorTemperature( PRESSURE_SENSOR_BIBAG ); + data.filteredSpentdialysateTemp = getFilteredPressureSensorTemperature( PRESSURE_SENSOR_SPENT_DIALYSATE ); + data.filteredFreshdialysateTemp = getFilteredPressureSensorTemperature( PRESSURE_SENSOR_FRESH_DIALYSATE ); + data.filteredTransmembraneTemp = getFilteredPressureSensorTemperature( PRESSURE_SENSOR_TRANSMEMBRANE ); + pressuresDataPublicationTimerCounter = 0; + + broadcastData( MSG_ID_DD_PRESSURES_DATA, COMM_BUFFER_OUT_CAN_DD_BROADCAST, (U08*)&data, sizeof( PRESSURE_TEMP_DATA_T ) ); + } +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testPressureSensorDataPublishIntervalOverride function overrides the + * pressure sensor data publish interval. + * @details \b Inputs: none + * @details \b Outputs: pressuresDataPublishInterval + * @param message Override message from Dialin which includes the value + * that override valves states publish interval with (in ms) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testPressureSensorDataPublishIntervalOverride( MESSAGE_T *message ) +{ + BOOL result = u32BroadcastIntervalOverride( message, &pressuresDataPublishInterval, TASK_PRIORITY_INTERVAL ); + + return result; +} + +/*********************************************************************//** + * @brief + * The testPressureSensorFilteredReadingsOverride function overrides the + * filtered value of the specified pressure sensor with a given value. + * @details \b Inputs: none + * @details \b Outputs: filteredcurrentPressureReadings[] + * @param message Override message from Dialin which includes an sensor + * ID and override value of the pressure sensor. + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testPressureSensorFilteredReadingsOverride( MESSAGE_T *message ) +{ + BOOL result = f32ArrayOverride( message, &filteredcurrentPressureReadings[0], NUM_OF_PRESSURE_SENSORS - 1 ); + + return result; +} + +/*********************************************************************//** + * @brief + * The testPressureSensorFilteredTemperatureReadingsOverride function overrides the + * value of the specified pressure sensor filtered temperature with a given value. + * @details \b Inputs: none + * @details \b Outputs: currentPresTempReadings[] + * @param message Override message from Dialin which includes an sensor + * ID and override value of the pressure sensor temperature. + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testPressureSensorFilteredTemperatureReadingsOverride( MESSAGE_T *message ) +{ + BOOL result = f32ArrayOverride( message, &filteredcurrentPresTempReadings[0], NUM_OF_PRESSURE_SENSORS - 1 ); + + return result; +} + +/**@}*/ Index: firmware/App/Monitors/Pressure.h =================================================================== diff -u --- firmware/App/Monitors/Pressure.h (revision 0) +++ firmware/App/Monitors/Pressure.h (revision c7dcb245c2378b1c96eeaa02f120f61dff598b11) @@ -0,0 +1,69 @@ +/************************************************************************** +* +* 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 Pressure.h +* +* @author (last) Vinayakam Mani +* @date (last) 04-Sep-2024 +* +* @author (original) Vinayakam Mani +* @date (original) 04-Sep-2024 +* +***************************************************************************/ + +#ifndef __PRESSURE_H__ +#define __PRESSURE_H__ + +#include "DDCommon.h" +#include "PressureSensor.h" + +/** + * @defgroup Pressure Pressure + * @brief Pressure sensors monitor module. Monitors the various DD pressure + * sensors. + * + * @addtogroup Pressure + * @{ + */ + +// ********** public definitions ********** + +/// Pressure data struct. +typedef struct +{ + F32 filteredWaterInletInputPressure; ///< Water Inlet Input pressure + F32 filteredWaterInletOutputPressure; ///< Water Inlet Output pressure + F32 filteredHydraulicsOutletPressure; ///< Hydraulics outlet pressure + F32 filteredBibagPressure; ///< Bicarb bag pressure + F32 filteredSpentdialysatePressure; ///< Spent Dialysate pressure + F32 filteredFreshdialysatePressure; ///< Fresh Dialysate pressure + F32 filteredTransmembranePressure; ///< Transmembrane pressure + F32 filteredWaterInletInputTemp; ///< Water Inlet Input temperature + F32 filteredWaterInletOutputTemp; ///< Water Inlet Output temperature + F32 filteredHydraulicsOutletTemp; ///< Hydraulics outlet pressure temperature + F32 filteredBibagTemp; ///< Bicarb bag temperature + F32 filteredSpentdialysateTemp; ///< Spent Dialysate temperature + F32 filteredFreshdialysateTemp; ///< Fresh Dialysate temperature + F32 filteredTransmembraneTemp; ///< Transmembrane temperature +} PRESSURE_TEMP_DATA_T; + +// ********** public function prototypes ********** + +void initPressure( void ); +void execPressureSensor( void ); +void checkInletWaterPressure( void ); + +F32 getFilteredPressure( PRESSURE_SENSORS_T sensor ); +F32 getFilteredPressureSensorTemperature( PRESSURE_SENSORS_T sensor ); + +BOOL testPressureSensorDataPublishIntervalOverride( MESSAGE_T *message ); +BOOL testPressureSensorFilteredReadingsOverride( MESSAGE_T *message ); +BOOL testPressureSensorFilteredTemperatureReadingsOverride( MESSAGE_T *message ); + +/**@}*/ + +#endif Index: firmware/App/Monitors/Temperature.c =================================================================== diff -u --- firmware/App/Monitors/Temperature.c (revision 0) +++ firmware/App/Monitors/Temperature.c (revision c7dcb245c2378b1c96eeaa02f120f61dff598b11) @@ -0,0 +1,246 @@ +/************************************************************************** +* +* 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 Temperature.c +* +* @author (last) Vinayakam Mani +* @date (last) 23-Sep-2024 +* +* @author (original) Vinayakam Mani +* @date (original) 23-Sep-2024 +* +***************************************************************************/ + +#include "Messaging.h" +#include "MessageSupport.h" +#include "OperationModes.h" +#include "Temperature.h" +#include "Timers.h" +#include "TaskPriority.h" +#include "Utilities.h" + +/** + * @addtogroup Temperature + * @{ + */ + +// ********** private definitions ********** +#define ADC_FPGA_READ_DELAY 30U ///< Delay in ms before reading the ADC values from FPGA. + +#define TEMP_SENSORS_DATA_PUBLISH_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Temperature sensors publish data time interval. +#define TEMP_SENSORS_FPGA_ERROR_TIMEOUT_MS ( 2 * MS_PER_SECOND ) ///< Temperature sensors FPGA error timeout in milliseconds. + +#define DATA_PUBLISH_COUNTER_START_COUNT 30 ///< Data publish counter start count. + +/// Temperature sensor exec states. +typedef enum tempSensors_Exec_States +{ + TEMPSENSORS_EXEC_STATE_START = 0, ///< Temperature sensors exec start + TEMPSENSORS_EXEC_STATE_GET_ADC_VALUES, ///< Temperature sensors exec get ADC values + NUM_OF_TEMPSENSORS_EXEC_STATES, ///< Total number of exec states +} TEMPSENSORS_EXEC_STATES_T; + +// ********** private data ********** + +static TEMPSENSORS_EXEC_STATES_T tempSensorsExecState; ///< TemperatureSensor exec state. +static U32 startTime; ///< star time to read FPGA values. + +static U32 dataPublicationTimerCounter; ///< Temperature sensors data publish timer counter. +static OVERRIDE_U32_T tempSensorsPublishInterval = { TEMP_SENSORS_DATA_PUBLISH_INTERVAL, + TEMP_SENSORS_DATA_PUBLISH_INTERVAL, 0, 0 }; ///< Temperature sensors publish time interval override. + +// ********** private function prototypes ********** + +static TEMPSENSORS_EXEC_STATES_T handleExecStart( void ); +static TEMPSENSORS_EXEC_STATES_T handleExecGetADCValues( void ); +static void publishTemperatureSensorsData( void ); + +/*********************************************************************//** + * @brief + * The initTemperature function initializes the temperature unit. + * @details \b Inputs: none + * @details \b Outputs: temperature unit variables initialized. + * @return none + *************************************************************************/ +void initTemperature( void ) +{ + startTime = 0; + tempSensorsExecState = TEMPSENSORS_EXEC_STATE_START; + dataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; + + // Initialize the temperature sensors + initTemperatureSensors(); +} + +/*********************************************************************//** + * @brief + * The execTemperatureSensorsSelfTest function runs the TemperatureSensors + * POST during the self-test. + * @details \b Inputs: none + * @details \b Outputs: none + * @return tempSensorsSelfTestState which is the status of the self test + *************************************************************************/ +SELF_TEST_STATUS_T execTemperatureSensorsSelfTest( void ) +{ + SELF_TEST_STATUS_T result = SELF_TEST_STATUS_IN_PROGRESS; + + //BOOL calStatus = getNVRecord2Driver( GET_CAL_TEMP_SENSORS, (U08*)&tempSensorCalRecord, sizeof( DD_TEMP_SENSORS_CAL_RECORD_T ), + // NUM_OF_CAL_DATA_TEMP_SENSORS, ALARM_ID_DD_TEMPERATURE_SENSORS_INVALID_CAL_RECORD ); + BOOL calStatus = TRUE; + + if ( TRUE == calStatus ) + { + result = SELF_TEST_STATUS_PASSED; + } + else + { + result = SELF_TEST_STATUS_FAILED; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The execTemperatureSensors function executes the temperature sensors' + * state machine. + * @details \b Inputs: tempSensorsExecState + * @details \b Outputs: tempSensorsExecState + * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid temperature + * sensor state is seen. + * @return none + *************************************************************************/ +void execTemperatureSensors( void ) +{ + // Check if a new calibration is available +// if ( TRUE == isNewCalibrationRecordAvailable() ) +// { +// getNVRecord2Driver( GET_CAL_TEMP_SENSORS, (U08*)&tempSensorCalRecord, sizeof( DD_TEMP_SENSORS_CAL_RECORD_T ), +// NUM_OF_CAL_DATA_TEMP_SENSORS, ALARM_ID_DD_TEMPERATURE_SENSORS_INVALID_CAL_RECORD ); +// } + + // Read the sensors all the time + switch ( tempSensorsExecState ) + { + case TEMPSENSORS_EXEC_STATE_START: + tempSensorsExecState = handleExecStart(); + break; + + case TEMPSENSORS_EXEC_STATE_GET_ADC_VALUES: + tempSensorsExecState = handleExecGetADCValues(); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_TEMPERATURE_SENSORS_EXEC_INVALID_STATE, tempSensorsExecState ); + tempSensorsExecState = TEMPSENSORS_EXEC_STATE_GET_ADC_VALUES; + break; + } + + // Monitor the temperature values + monitorTemperatureSenors(); + + // Publish the data + publishTemperatureSensorsData(); +} + +/*********************************************************************//** + * @brief + * The handleExecStart function waits for a period of time and switches to + * the state that reads the ADC values from FPGA. + * @details \b Inputs: startTime + * @details \b Outputs: startTime, baroCoeffsWaitToRcvStartTime + * @return the next state of the state machine + *************************************************************************/ +static TEMPSENSORS_EXEC_STATES_T handleExecStart( void ) +{ + TEMPSENSORS_EXEC_STATES_T state = TEMPSENSORS_EXEC_STATE_START; + + if ( 0 == startTime ) + { + startTime = getMSTimerCount(); + } + // A delay to let FPGA to boot up + else if ( TRUE == didTimeout( startTime, ADC_FPGA_READ_DELAY ) ) + { + startTime = 0; + setBaroSensorCoefficientReadStartTime(); + state = TEMPSENSORS_EXEC_STATE_GET_ADC_VALUES; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleExecGetADCValues function reads the ADC values from FPGA and + * at the specified time intervals and calls required functions to calculate + * the actual tempetature from the raw ADC values. + * @details \b Inputs: FPGA + * @details \b Outputs: temperature value. + * @return the next state of the state machine + *************************************************************************/ +static TEMPSENSORS_EXEC_STATES_T handleExecGetADCValues( void ) +{ + // Read temperature sensors + readTemperatureSensors(); + + return TEMPSENSORS_EXEC_STATE_GET_ADC_VALUES; +} + +/*********************************************************************//** + * @brief + * The publishTemperatureSensorsData function broadcasts the temperature + * sensors data at the publication interval. + * @details \b Inputs: dataPublicationTimerCounter and publish interval time. + * @details \b Outputs: dataPublicationTimerCounter + * @details \b Message \b Sent: MSG_ID_DD_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.inletHeatExchanger = getTemperatureValue( TEMPSENSORS_INLET_HEAT_EXCHANGER ); + data.outletHeatExchanger = getTemperatureValue( TEMPSENSORS_OUTLET_HEAT_EXCHANGER ); + data.hydraulicsPrimaryHeater = getTemperatureValue( TEMPSENSORS_HYDRAULICS_PRIMARY_HEATER ); + data.trimmerHeater = getTemperatureValue( TEMPSENSORS_TRIMMER_HEATER ); + data.boardTemp = getTemperatureValue( TEMPSENSORS_BOARD_TEMPERATURE ); + data.baroTempSensor = getTemperatureValue( TEMPSENSORS_BAROMETRIC_TEMP_SENSOR ); + + broadcastData( MSG_ID_DD_TEMPERATURE_DATA, COMM_BUFFER_OUT_CAN_DD_BROADCAST, (U08*)&data, sizeof( TEMPERATURE_SENSORS_DATA_T ) ); + dataPublicationTimerCounter = 0; + } +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testTemperatureSensorsDataPublishIntervalOverride function overrides the + * temperature sensor 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; +} + + +/**@}*/ Index: firmware/App/Monitors/Temperature.h =================================================================== diff -u --- firmware/App/Monitors/Temperature.h (revision 0) +++ firmware/App/Monitors/Temperature.h (revision c7dcb245c2378b1c96eeaa02f120f61dff598b11) @@ -0,0 +1,56 @@ +/************************************************************************** +* +* 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 Temperature.h +* +* @author (last) Vinayakam Mani +* @date (last) 23-Sep-2024 +* +* @author (original) Vinayakam Mani +* @date (original) 23-Sep-2024 +* +***************************************************************************/ + +#ifndef __TEMPERATURE_H__ +#define __TEMPERATURE_H__ + +#include "DDCommon.h" +#include "TemperatureSensors.h" + +/** + * @defgroup Temperature Temperature + * @brief Temperature Monitor unit. Reads and processes the temperature sensors. + * + * @addtogroup Temperature + * @{ + */ + +// ********** public definitions ********** + +/// Temperature sensors data structure. +typedef struct +{ + F32 inletHeatExchanger; ///< Inlet heat exchanger temperature sensor + F32 outletHeatExchanger; ///< Outlet heat exchanger temperature sensor + F32 hydraulicsPrimaryHeater; ///< Hydraulics primary heater temperature sensor + F32 trimmerHeater; ///< Trimmer heater temperature sensor + F32 boardTemp; ///< Board temperature sensor + F32 baroTempSensor; ///< Barometric temperature sensor +} TEMPERATURE_SENSORS_DATA_T; + + +// ********** public function prototypes ********** + +void initTemperature( void ); +SELF_TEST_STATUS_T execTemperatureSensorsSelfTest( void ); +void execTemperatureSensors( void ); + +BOOL testTemperatureSensorsDataPublishIntervalOverride( MESSAGE_T *message ); + +/**@}*/ + +#endif Index: firmware/App/Services/FpgaRO.c =================================================================== diff -u -r129a1c2f4343bc85efdb4767c2dec35e4ba8ce98 -rc7dcb245c2378b1c96eeaa02f120f61dff598b11 --- firmware/App/Services/FpgaRO.c (.../FpgaRO.c) (revision 129a1c2f4343bc85efdb4767c2dec35e4ba8ce98) +++ firmware/App/Services/FpgaRO.c (.../FpgaRO.c) (revision c7dcb245c2378b1c96eeaa02f120f61dff598b11) @@ -1,3 +1,19 @@ +/************************************************************************** +* +* Copyright (c) 2019-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 FPGA.c +* +* @author (last) Sean Nash +* @date (last) 09-Nov-2024 +* +* @author (original) Sean Nash +* @date (original) 09-Nov-2024 +* +***************************************************************************/ #include "string.h" // for memset(), memcpy() @@ -21,26 +37,262 @@ // ********** private definitions ********** -#define MAX_FPGA_COMM_FAILURES_WINDOW_MS ( 1 * SEC_PER_MIN * MS_PER_SECOND ) ///< FPGA comm failures window -#define MAX_FPGA_COMM_FAILURES 3 ///< FPGA maximum comm failures per MAX_FPGA_COMM_FAILURES_WINDOW_MS -#define MIN_POWER_ON_TIME_FOR_COMM_FAILS ( 1 * MS_PER_SECOND ) ///< Allow FPGA comm errors for first second after power-up +#define FPGA_EXPECTED_ID 0x01 ///< Expected ID for TD FPGA. +#define PROCESSOR_FPGA_CLOCK_DIFF_TOLERANCE 1 ///< Tolerance for processor clock speed check against FPGA clock. + +#define MAX_FPGA_COMM_FAILURES_WINDOW_MS ( 1 * SEC_PER_MIN * MS_PER_SECOND ) ///< FPGA comm failures window +#define MAX_FPGA_COMM_FAILURES 3 ///< FPGA maximum comm failures per MAX_FPGA_COMM_FAILURES_WINDOW_MS +#define MIN_POWER_ON_TIME_FOR_COMM_FAILS ( 1 * MS_PER_SECOND ) ///< Allow FPGA comm errors for first second after power-up + +// FPGA Sensors Record +#pragma pack(push,1) + +/// Record structure for FPGA header read. +typedef struct +{ + U08 fpgaId; ///< Reg 0. FPGA ID code. Checked against expected value at power up to verify basic FPGA communication and operation. + U08 fpgaRev; ///< Reg 1. FPGA revision (minor) being reported. + U08 fpgaRevMajor; ///< Reg 2. FPGA revision (major) being reported. + U08 fpgaRevLab; ///< Reg 3. FPGA revision (lab) being reported. +} FPGA_HEADER_T; // Read only on FPGA + +/// Record structure for FPGA continuous priority reads. +typedef struct +{ + U16 compatibilityRev; ///< Reg 256. FPGA compatibility revision. + U16 counterTimer1ms; ///< Reg 258. FPGA 1ms timer counter. + U16 fpgaGenWrRd; ///< Reg 260. FPGA general read-back register (mirrored from a general write register in write page at addr 4). + U08 errorCountProcessor; ///< Reg 262. Error count for processor communications. + U08 errorCountPC; ///< Reg 263. Error count for TBD. + S16 pressurePri; ///< Reg 264. PRi pressure data. + U16 temperaturePri; ///< Reg 266. PRi temperature data. + U08 readCountPri; ///< Reg 268. PRi read counter. + U08 errorCountPri; ///< Reg 269. PRi error counter. + S16 pressurePro; ///< Reg 270. PRo pressure data. + U16 temperaturePro; ///< Reg 272. PRo temperature data. + U08 readCountPro; ///< Reg 274. PRo read counter. + U08 errorCountPro; ///< Reg 275. PRo error counter. + S16 pressurePsi; ///< Reg 276. PSi pressure data. + U16 temperaturePsi; ///< Reg 278. PSi temperature data. + U08 readCountPsi; ///< Reg 280. PSi read counter. + U08 errorCountPsi; ///< Reg 281. PSi error counter. + S16 pressurePso; ///< Reg 282. PSo pressure data. + U16 temperaturePso; ///< Reg 284. PSo temperature data. + U08 readCountPso; ///< Reg 286. PSo read counter. + U08 errorCountPso; ///< Reg 287. PSo error counter. + S16 pressurePc1o; ///< Reg 288. PC1o pressure data. + U16 temperaturePc1o; ///< Reg 290. PC1o temperature data. + U08 readCountPc1o; ///< Reg 292. PC1o read counter. + U08 errorCountPc1o; ///< Reg 293. PC1o error counter. + S16 pressurePc2o; ///< Reg 294. PC2o pressure data. + U16 temperaturePc2o; ///< Reg 296. PC2o temperature data. + U08 readCountPc2o; ///< Reg 298. PC2o read counter. + U08 errorCountPc2o; ///< Reg 299. PC2o error counter. + S16 pressurePpo; ///< Reg 300. PPo pressure data. + U16 temperaturePpo; ///< Reg 302. PPo temperature data. + U08 readCountPpo; ///< Reg 304. PPo read counter. + U08 errorCountPpo; ///< Reg 305. PPo error counter. + S16 pressurePmp; ///< Reg 306. PMp pressure data. + U16 temperaturePmp; ///< Reg 308. PMp temperature data. + U08 readCountPmp; ///< Reg 310. PMp read counter. + U08 errorCountPmp; ///< Reg 311. PMp error counter. + S16 pressurePmc; ///< Reg 312. PMc pressure data. + U16 temperaturePmc; ///< Reg 314. PMc temperature data. + U08 readCountPmc; ///< Reg 316. PMc read counter. + U08 errorCountPmc; ///< Reg 317. PMc error counter. + S16 pressurePpi; ///< Reg 318. PPi pressure data. + U16 temperaturePpi; ///< Reg 320. PPi temperature data. + U08 readCountPpi; ///< Reg 322. PPi read counter. + U08 errorCountPpi; ///< Reg 323. PPi error counter. + S16 pressurePax1; ///< Reg 324. Pax1 pressure data. + U16 temperaturePax1; ///< Reg 326. Pax1 temperature data. + U08 readCountPax1; ///< Reg 328. Pax1 read counter. + U08 errorCountPax1; ///< Reg 329. Pax1 error counter. + S16 pressurePax2; ///< Reg 330. Pax2 pressure data. + U16 temperaturePax2; ///< Reg 332. Pax2 temperature data. + U08 readCountPax2; ///< Reg 334. Pax2 read counter. + U08 errorCountPax2; ///< Reg 335. Pax2 error counter. + U32 conductSensor1; ///< Reg 336. Conductivity sensor 1. + U16 conductSensor1Data; ///< Reg 340. Conductivity sensor 1 data. + U16 conductSensor1Temp; ///< Reg 342. Conductivity sensor 1 temperature. + U08 conductSensor1ReadCount; ///< Reg 344. Conductivity sensor 1 read counter. + U08 conductSensor1ErrorCount; ///< Reg 345. Conductivity sensor 1 error counter. + U32 conductSensor2; ///< Reg 346. Conductivity sensor 2. + U16 conductSensor2Data; ///< Reg 350. Conductivity sensor 2 data. + U16 conductSensor2Temp; ///< Reg 352. Conductivity sensor 2 temperature. + U08 conductSensor2ReadCount; ///< Reg 354. Conductivity sensor 2 read counter. + U08 conductSensor2ErrorCount; ///< Reg 355. Conductivity sensor 2 error counter. + U16 flowRateCountFmp; ///< Reg 356. FMP flow sensor pulse counter. + U16 levelSwitch; ///< Reg 358. LRO1..3 level sensors. +} FPGA_SENSORS_T; + +/// Record structure for FPGA continuous priority writes. +typedef struct +{ + U08 valveControl; ///< Reg 04. Valve control register. + U08 valvePWMEnable; ///< Reg 05. Valve PWM enable register. + U08 conductSensorControl1; ///< Reg 06. Conductivity sensor control register 1. + U08 conductSensorControl2; ///< Reg 07. Conductivity sensor control register 2. + U16 conductAddress1; ///< Reg 08. Conductivity sensor address register 1. + U32 conductData1; ///< Reg 10. Conductivity sensor data in register 1. + U16 conductAddress2; ///< Reg 14. Conductivity sensor address register 2. + U32 conductData2; ///< Reg 16. Conductivity sensor data in register 2. + U16 fpgaGenWrRd; ///< Reg 20. FPGA general write/read-back register (mirrored to a general read register in read page at addr 256). + U16 descalePumpSpeed; ///< Reg 22. Descaler pump speed register. + U08 descalePumpControl; ///< Reg 24. Descaler pump control register. + U08 reserved1; ///< Reg 25. Reserved. + U16 valveVwiPWMLow; ///< Reg 26. Valve VWi PWM low pulse period in 0.1 uSec. + U16 valveVwiPWMPeriod; ///< Reg 28. Valve VWi PWM full period in 0.1 uSec. + U16 valveVffPWMLow; ///< Reg 30. + U16 valveVffPWMPeriod; ///< Reg 32. + U16 valveVPiPWMLow; ///< Reg 34. + U16 valveVPiPWMPeriod; ///< Reg 36. + U16 valveVcrPWMLow; ///< Reg 38. + U16 valveVcrPWMPeriod; ///< Reg 40. + U16 valveVcmPWMLow; ///< Reg 42. + U16 valveVcmPWMPeriod; ///< Reg 44. + U16 valveVprPWMLow; ///< Reg 46. + U16 valveVprPWMPeriod; ///< Reg 48. +} FPGA_ACTUATORS_T; + +#pragma pack(pop) + +// ********** private data ********** + +// FPGA data +static FPGA_HEADER_T fpgaHeader; ///< Record of last received FPGA header data. +static FPGA_SENSORS_T fpgaSensorReadings; ///< Record of last received FPGA priority sensor data. +static FPGA_ACTUATORS_T fpgaActuatorSetPoints; ///< Record of next transmitted FPGA priority actuator data. + +// FPGA Clock Speed Test +static U16 currentFPGATimerCount_ms = 0; ///< Last read ms timer count from FPGA. +static U32 currentTimerCount_ms = 0; ///< Last read ms timer count from processor. + /*********************************************************************//** * @brief * The initFPGARO function initializes the RO FPGA unit. * @details \b Inputs: none - * @details \b Outputs: FPGA unit initialized. + * @details \b Outputs: RO FPGA unit initialized. * @return none *************************************************************************/ void initFPGARO( void ) { + // Initialize fpga driver + initFPGA( (U08*)&fpgaHeader, (U08*)&fpgaSensorReadings, (U08*)&fpgaActuatorSetPoints, + sizeof(FPGA_HEADER_T), sizeof(FPGA_SENSORS_T), sizeof(FPGA_ACTUATORS_T) ); + // Initialize fpga data structures + memset( &fpgaHeader, 0, sizeof(FPGA_HEADER_T) ); + memset( &fpgaSensorReadings, 0, sizeof(FPGA_SENSORS_T) ); + memset( &fpgaActuatorSetPoints, 0, sizeof(FPGA_ACTUATORS_T) ); // initialize FPGA clock speed error time windowed count initTimeWindowedCount( TIME_WINDOWED_COUNT_FPGA_COMM_FAILURES, MAX_FPGA_COMM_FAILURES, MAX_FPGA_COMM_FAILURES_WINDOW_MS); } /*********************************************************************//** * @brief + * The execFPGATest function executes the FPGA self-test. + * @details \b Alarm: ALARM_ID_RO_FPGA_POST_TEST_FAILED if self-test fails. + * @details \b Inputs: fpgaHeader + * @details \b Outputs: none + * @return passed or failed + *************************************************************************/ +SELF_TEST_STATUS_T execFPGATest( void ) +{ + SELF_TEST_STATUS_T result; + + // check FPGA reported correct ID + if ( FPGA_EXPECTED_ID == fpgaHeader.fpgaId ) + { + // Check FPGA compatibility w/ firmware + if ( TD_FPGA_COMPATIBILITY_REV == fpgaSensorReadings.compatibilityRev ) + { + result = SELF_TEST_STATUS_PASSED; + } + else + { + result = SELF_TEST_STATUS_FAILED; + // TODO uncomment +// SET_ALARM_WITH_2_U32_DATA( ALARM_ID_RO_FPGA_POST_TEST_FAILED, (U32)TD_FPGA_COMPATIBILITY_REV, (U32)fpgaSensorReadings.fpgaCompatibilityRev ) + } + } + else + { + result = SELF_TEST_STATUS_FAILED; + // TODO uncomment +// SET_ALARM_WITH_1_U32_DATA( ALARM_ID_RO_FPGA_POST_TEST_FAILED, (U32)fpgaHeader.fpgaId ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getFPGATimerCount function gets the latest FPGA timer millisecond count. + * @details \b Inputs: fpgaSensorReadings + * @details \b Outputs: none + * @return last FPGA millisecond timer count + *************************************************************************/ +U16 getFPGATimerCount( void ) +{ + return fpgaSensorReadings.counterTimer1ms; +} + +/*********************************************************************//** + * @brief + * The execFPGAClockSpeedTest function verifies the processor clock speed + * against the FPGA clock. + * @details \b Alarm: ALARM_ID_RO_FPGA_CLOCK_SPEED_CHECK_FAILURE if test fails. + * @details \b Inputs: fpgaSensorReadings.fpgaTimerCount_ms, msTimerCount, + * currentFPGATimerCount_ms, currentTimerCount_ms + * @details \b Outputs: currentFPGATimerCount_ms, currentTimerCount_ms + * @return none + *************************************************************************/ +void execFPGAClockSpeedTest( void ) +{ +// DEBUG WARNING +// It may be necessary to comment out the following +// code to prevent the alarm from occurring while +// debugging. + U16 newFPGATimerCount_ms = getFPGATimerCount(); + U32 newTimerCount_ms = getMSTimerCount(); + U32 diffFPGATimerCount = (U32)u16DiffWithWrap( currentFPGATimerCount_ms, newFPGATimerCount_ms ); + U32 diffTimerCount = u32DiffWithWrap( currentTimerCount_ms, newTimerCount_ms ); + + if ( getCurrentOperationMode() != RO_MODE_INIT ) + { + if ( abs( diffFPGATimerCount - diffTimerCount ) > PROCESSOR_FPGA_CLOCK_DIFF_TOLERANCE ) + { + if ( TRUE == incTimeWindowedCount( TIME_WINDOWED_COUNT_FPGA_CLOCK_SPEED_ERROR ) ) + { + // TODO uncomment +// SET_ALARM_WITH_2_U32_DATA( ALARM_ID_RO_FPGA_CLOCK_SPEED_CHECK_FAILURE, diffFPGATimerCount, diffTimerCount ); + } + } + } + + currentFPGATimerCount_ms = newFPGATimerCount_ms; + currentTimerCount_ms = newTimerCount_ms; +} + +/*********************************************************************//** + * @brief + * The getFPGAVersions function gets the fpga version numbers. + * @details \b Inputs: fpgaHeader + * @details \b Outputs: Given version reference variables are populated. + * @return none + *************************************************************************/ +void getFPGAVersions( U08 *Id, U08 *Maj, U08 *Min, U08 *Lab ) +{ + *Id = fpgaHeader.fpgaId; + *Min = fpgaHeader.fpgaRev; + *Maj = fpgaHeader.fpgaRevMajor; + *Lab = fpgaHeader.fpgaRevLab; +} + +/*********************************************************************//** + * @brief * The checkFPGACommFailure function increments the FPGA comm failure * windowed timer and returns whether or not the number of failures in * the window have been reached. @@ -55,7 +307,7 @@ if ( TRUE == incTimeWindowedCount( TIME_WINDOWED_COUNT_FPGA_COMM_FAILURES ) ) { // TODO uncomment - //SET_ALARM_WITH_2_U32_DATA( ALARM_ID_RO_FPGA_COMM_TIMEOUT, MAX_FPGA_COMM_FAILURES, (U32)fpgaSensorReadings.fpgaIOErrorCntProcessor ) +// SET_ALARM_WITH_2_U32_DATA( ALARM_ID_RO_FPGA_COMM_TIMEOUT, MAX_FPGA_COMM_FAILURES, (U32)fpgaSensorReadings.errorCountProcessor ) } } } @@ -93,4 +345,42 @@ return status; } +/*********************************************************************//** + * @brief + * The setFPGAValveStates function sets the RO valve states with an 8-bit + * mask of states - one bit per valve, with a 1 meaning "energized" and a 0 + * meaning "de-energized". The bit positions for these bit states are as follows: + * 0 - VFf.\n + * 1 - VPi.\n + * 2 - VLp.\n + * 3 - VCr.\n + * 4 - VCb.\n + * 5 - VCd1.\n + * 6 - VROd.\n + * 7 - reserved or unused. + * @details \b Inputs: none + * @details \b Outputs: fpgaActuatorSetPoints.valveControl + * @param valveStates bit mask for requested valve states + * @return none + *************************************************************************/ +void setFPGAValveStates( U16 valveStates ) +{ + fpgaActuatorSetPoints.valveControl = valveStates; +} + +/*********************************************************************//** + * @brief + * The getFPGAValveStates function gets the RO valve commanded states with + * an 8-bit mask representing the set of states with a 1 meaning "energized" + * and a 0 meaning "de-energized". + * @details \b Inputs: none + * @details \b Outputs: fpgaSensorReadings.TBD + * @return none + *************************************************************************/ +U08 getFPGAValveStates( void ) +{ +// return fpgaSensorReadings.TBD; + return 0; // TODO +} + /**@}*/ Index: firmware/App/Services/FpgaRO.h =================================================================== diff -u -r129a1c2f4343bc85efdb4767c2dec35e4ba8ce98 -rc7dcb245c2378b1c96eeaa02f120f61dff598b11 --- firmware/App/Services/FpgaRO.h (.../FpgaRO.h) (revision 129a1c2f4343bc85efdb4767c2dec35e4ba8ce98) +++ firmware/App/Services/FpgaRO.h (.../FpgaRO.h) (revision c7dcb245c2378b1c96eeaa02f120f61dff598b11) @@ -1,5 +1,20 @@ +/************************************************************************** +* +* Copyright (c) 2019-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 FPGA.h +* +* @author (last) Sean Nash +* @date (last) 09-Nov-2024 +* +* @author (original) Sean Nash +* @date (original) 09-Nov-2024 +* +***************************************************************************/ - #ifndef __FPGA_RO_H__ #define __FPGA_RO_H__ @@ -23,6 +38,9 @@ void checkFPGACommFailure( void ); BOOL checkFPGAFEOEFailure( void ); +void setFPGAValveStates( U16 valveStates ); +U08 getFPGAValveStates( void ); + /**@}*/ #endif