/************************************************************************** * * Copyright (c) 2021-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 Voltages.c * * @author (last) Vinayakam Mani * @date (last) 05-Apr-2024 * * @author (original) Sean Nash * @date (original) 15-Apr-2021 * ***************************************************************************/ #include "AlarmMgmt.h" #include "CPLD.h" #include "FPGA.h" #include "InternalADC.h" #include "PersistentAlarm.h" #include "SafetyShutdown.h" #include "SystemCommMessages.h" #include "SystemComm.h" #include "TaskGeneral.h" #include "Timers.h" #include "Voltages.h" /** * @addtogroup Voltages * @{ */ // ********** private definitions ********** #define VOLTAGES_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the voltages data is published on the CAN bus. #define VOLTAGES_ALARM_PERSISTENCE_MS ( 1 * MS_PER_SECOND ) ///< Alarm persistence period for voltage monitor alarms in milliseconds. #define POWER_LOSS_VOLTAGE_PERSISTENCE_MS 500 ///< Power supply voltage out of range persistence in milliseconds. #define DATA_PUBLISH_COUNTER_START_COUNT 14 ///< Data publish counter start count. /// Defined states for the voltage monitor state machine. typedef enum Voltages_States { VOLTAGES_INIT_STATE = 0, ///< Initialization state. VOLTAGES_MONITOR_STATE, ///< Continuous read sensors state. NUM_OF_VOLTAGES_STATES ///< Number of voltage monitor states. } VOLTAGES_STATE_T; /// Maximum voltage/current level for each monitored signal. static const F32 MAX_VOLTAGES[ NUM_OF_MONITORED_LINES ] = { 1.32, // MONITORED_LINE_1_2V 3.63, // MONITORED_LINE_3_3V 5.5, // MONITORED_LINE_5V_LOGIC 5.5, // MONITORED_LINE_5V_SENSORS 26.4, // MONITORED_LINE_24V 28.25, // MONITORED_LINE_24V_REGEN 1.3125, // MONITORED_LINE_FPGA_REF_V 3.3, // MONITORED_LINE_PBA_REF_V 1.1, // MONITORED_LINE_FPGA_VCC_V 1.98, // MONITORED_LINE_FPGA_AUX_V 0.1 // MONITORED_LINE_FPGA_PVN_V }; /// Minimum voltage/current level for each monitored signal. static const F32 MIN_VOLTAGES[ NUM_OF_MONITORED_LINES ] = { 1.08, // MONITORED_LINE_1_2V 2.97, // MONITORED_LINE_3_3V 4.5, // MONITORED_LINE_5V_LOGIC 4.5, // MONITORED_LINE_5V_SENSORS 21.6, // MONITORED_LINE_24V 22.0, // MONITORED_LINE_24V_REGEN 1.1875, // MONITORED_LINE_FPGA_REF_V 2.7, // MONITORED_LINE_PBA_REF_V 0.9, // MONITORED_LINE_FPGA_VCC_V 1.62, // MONITORED_LINE_FPGA_AUX_V -0.1 // MONITORED_LINE_FPGA_PVN_V }; // ********** private data ********** static VOLTAGES_STATE_T voltagesState; ///< Current state of voltages monitor state machine. static U32 voltagesDataPublicationTimerCounter; ///< Used to schedule voltages monitor data publication to CAN bus. /// Interval (in ms) at which to publish voltages monitor data to CAN bus. static OVERRIDE_U32_T voltagesDataPublishInterval = { VOLTAGES_DATA_PUB_INTERVAL, VOLTAGES_DATA_PUB_INTERVAL, 0, 0 }; static OVERRIDE_F32_T voltages[ NUM_OF_MONITORED_LINES ]; ///< Monitored voltages and currents. // ********** private function prototypes ********** static VOLTAGES_STATE_T handleVoltagesInitState( void ); static VOLTAGES_STATE_T handleVoltagesMonitorState( void ); static void checkVoltageRanges( void ); static void publishVoltagesData( void ); /*********************************************************************//** * @brief * The initVoltagesMonitor function initializes the Voltages module. * @details Inputs: none * @details Outputs: Voltages module initialized. * @return none *************************************************************************/ void initVoltagesMonitor( void ) { U32 i; voltagesState = VOLTAGES_INIT_STATE; voltagesDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; for ( i = 0; i < (U32)NUM_OF_MONITORED_LINES; i++ ) { voltages[i].data = 0.0; voltages[i].ovData = 0.0; voltages[i].ovInitData = 0.0; voltages[i].override = OVERRIDE_RESET; } initPersistentAlarm( ALARM_ID_HD_VOLTAGE_OUT_OF_RANGE, VOLTAGES_ALARM_PERSISTENCE_MS, VOLTAGES_ALARM_PERSISTENCE_MS ); initPersistentAlarm( ALARM_ID_HD_AC_POWER_LOST, POWER_LOSS_VOLTAGE_PERSISTENCE_MS, 0 ); } /*********************************************************************//** * @brief * The execVoltagesMonitor function executes the voltages monitor. * @details Inputs: voltagesState * @details Outputs: voltagesState * @return none *************************************************************************/ void execVoltagesMonitor( void ) { // State machine switch ( voltagesState ) { case VOLTAGES_INIT_STATE: voltagesState = handleVoltagesInitState(); break; case VOLTAGES_MONITOR_STATE: voltagesState = handleVoltagesMonitorState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, 0, voltagesState ) // TODO - add enum for this s/w fault break; } // Publish voltages data on interval publishVoltagesData(); } /*********************************************************************//** * @brief * The handleVoltagesInitState function handles the initialize state * of the voltages monitor state machine. * @details Inputs: none * @details Outputs: none * @return next state *************************************************************************/ static VOLTAGES_STATE_T handleVoltagesInitState( void ) { VOLTAGES_STATE_T result = VOLTAGES_MONITOR_STATE; return result; } /*********************************************************************//** * @brief * The handleVoltagesMonitorState function handles the monitor state * of the voltages monitor state machine. * @details Inputs: converted internal ADC readings * @details Outputs: alarm on failed check * @return next state *************************************************************************/ static VOLTAGES_STATE_T handleVoltagesMonitorState( void ) { VOLTAGES_STATE_T result = VOLTAGES_MONITOR_STATE; // Get latest signal levels voltages[ MONITORED_LINE_1_2V ].data = getIntADCVoltageConverted( INT_ADC_1_2V_PROCESSOR ); voltages[ MONITORED_LINE_3_3V ].data = getIntADCVoltageConverted( INT_ADC_3_3V ); voltages[ MONITORED_LINE_5V_LOGIC ].data = getIntADCVoltageConverted( INT_ADC_5V_LOGIC ); voltages[ MONITORED_LINE_5V_SENSORS ].data = getIntADCVoltageConverted( INT_ADC_5V_SENSORS ); voltages[ MONITORED_LINE_24V ].data = getIntADCVoltageConverted( INT_ADC_24V_ACTUATORS ); voltages[ MONITORED_LINE_24V_REGEN ].data = getIntADCVoltageConverted( INT_ADC_24V_ACTUATORS_REG ); voltages[ MONITORED_LINE_FPGA_REF_V ].data = getIntADCVoltageConverted( INT_ADC_1_25_FPGA_ADC_REF ); voltages[ MONITORED_LINE_PBA_REF_V ].data = getIntADCVoltageConverted( INT_ADC_PBA_ADC_REF ); voltages[ MONITORED_LINE_FPGA_VCC_V ].data = getFPGAVcc(); voltages[ MONITORED_LINE_FPGA_AUX_V ].data = getFPGAVccAux(); voltages[ MONITORED_LINE_FPGA_PVN_V ].data = getFPGAVpvn(); // Check voltage ranges checkVoltageRanges(); return result; } /*********************************************************************//** * @brief * The checkVoltageRanges function checks each monitored voltage or current * against its minimum and maximum range. * @details Inputs: MAX_VOLTAGES[], MIN_VOLTAGES[] * @details Outputs: alarm if out of range * @return none *************************************************************************/ static void checkVoltageRanges( void ) { MONITORED_VOLTAGES_T channel; MONITORED_VOLTAGES_T channelInAlarm; BOOL hasPowerBeenLost = getCPLDACPowerLossDetected(); BOOL isVoltageOutOfRange = FALSE; F32 volts = 0.0F; F32 alarmVoltage = 0.0F; // Check range for ( channel = MONITORED_LINE_FIRST_VOLTAGE; channel < NUM_OF_MONITORED_LINES; channel++ ) { if ( ( ( isSafetyShutdownActivated() != TRUE ) && ( hasPowerBeenLost != TRUE ) ) || ( ( channel != MONITORED_LINE_24V ) && ( channel != MONITORED_LINE_24V_REGEN ) ) ) { #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_VOLTAGES_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) #endif { volts = getMonitoredLineLevel( channel ); if ( ( volts > MAX_VOLTAGES[ channel ] ) || ( volts < MIN_VOLTAGES[ channel] ) ) { isVoltageOutOfRange = TRUE; channelInAlarm = channel; alarmVoltage = volts; break; // once a channel is out of range there is no need to continue } } } } // Check the persistence alarm checkPersistentAlarm ( ALARM_ID_HD_VOLTAGE_OUT_OF_RANGE, isVoltageOutOfRange, channelInAlarm, alarmVoltage ); if ( TRUE == hasPowerBeenLost ) { HD_OP_MODE_T opMode = getCurrentOperationMode(); // Pre-Treatment, Treatment, or Post-Treatment mode if ( ( MODE_PRET == opMode ) || ( MODE_TREA == opMode ) || ( MODE_POST == opMode ) ) { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_AC_POWER_LOST_IN_TREATMENT, getMonitoredLineLevel( MONITORED_LINE_24V ), getMonitoredLineLevel( MONITORED_LINE_24V_REGEN ) ); } else { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_AC_POWER_LOST, getMonitoredLineLevel( MONITORED_LINE_24V ), getMonitoredLineLevel( MONITORED_LINE_24V_REGEN ) ); } // Reset the alarm clearance counter resetPersistentAlarmTimer( ALARM_ID_HD_AC_POWER_LOST ); } else { if ( TRUE == isPersistentAlarmConditionCleared( ALARM_ID_HD_AC_POWER_LOST, hasPowerBeenLost ) ) { clearAlarmCondition( ALARM_ID_HD_AC_POWER_LOST ); // Just to make sure we are not clearing the AC power lost in treatment alarm until DG powers up and not in // POST mode, to avoid HD sending commands when DG is not yet ready. if ( DG_MODE_INIT != getDGOpMode() ) { clearAlarmCondition( ALARM_ID_HD_AC_POWER_LOST_IN_TREATMENT ); } } } } /*********************************************************************//** * @brief * The getMonitoredLineLevel function gets the current voltage or current * level for a given signal. * @details Inputs: voltages[] * @details Outputs: none * @param signal the signal that is being asked for * @return the voltage/current for the given signal *************************************************************************/ F32 getMonitoredLineLevel( MONITORED_VOLTAGES_T signal ) { F32 result = 0.0; if ( signal < NUM_OF_MONITORED_LINES ) { result = voltages[ signal ].data; if ( OVERRIDE_KEY == voltages[ signal ].override ) { result = voltages[ signal ].ovData; } } else { // TODO - s/w fault } return result; } /*********************************************************************//** * @brief * The publishVoltagesData function publishes voltages monitor data at the * set interval. * @details Inputs: latest voltages and currents * @details Outputs: voltages monitor data are published to CAN bus. * @return none *************************************************************************/ static void publishVoltagesData( void ) { // Publish voltages monitor data on interval if ( ++voltagesDataPublicationTimerCounter >= getU32OverrideValue( &voltagesDataPublishInterval ) ) { VOLTAGES_DATA_PAYLOAD_T data; data.adc1_2VProc = getMonitoredLineLevel( MONITORED_LINE_1_2V ); data.adc3_3V = getMonitoredLineLevel( MONITORED_LINE_3_3V ); data.adc5VLogic = getMonitoredLineLevel( MONITORED_LINE_5V_LOGIC ); data.adc5VSensors = getMonitoredLineLevel( MONITORED_LINE_5V_SENSORS ); data.adc24V = getMonitoredLineLevel( MONITORED_LINE_24V ); data.adc24VRegen = getMonitoredLineLevel( MONITORED_LINE_24V_REGEN ); data.adcFpgaAdcRef = getMonitoredLineLevel( MONITORED_LINE_FPGA_REF_V ); data.adcPbaRef = getMonitoredLineLevel( MONITORED_LINE_PBA_REF_V ); data.fpgaVcc = getMonitoredLineLevel( MONITORED_LINE_FPGA_VCC_V ); data.fpgaVaux = getMonitoredLineLevel( MONITORED_LINE_FPGA_AUX_V ); data.fpgaVpvn = getMonitoredLineLevel( MONITORED_LINE_FPGA_PVN_V ); broadcastData( MSG_ID_HD_VOLTAGES_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( VOLTAGES_DATA_PAYLOAD_T ) ); voltagesDataPublicationTimerCounter = 0; } } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testSetVoltagesDataPublishIntervalOverride function overrides the * monitored voltages data publish interval. * @details Inputs: none * @details Outputs: voltagesDataPublishInterval * @param value override monitored voltages data publish interval with (in ms) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetVoltagesDataPublishIntervalOverride( U32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { U32 intvl = value / TASK_GENERAL_INTERVAL; result = TRUE; voltagesDataPublishInterval.ovData = intvl; voltagesDataPublishInterval.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetVoltagesDataPublishIntervalOverride function resets the override * of the monitored voltages data publish interval. * @details Inputs: none * @details Outputs: voltagesDataPublishInterval * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetVoltagesDataPublishIntervalOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; voltagesDataPublishInterval.override = OVERRIDE_RESET; voltagesDataPublishInterval.ovData = voltagesDataPublishInterval.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetLineLevelOverride function overrides the given monitored voltage * or current. * @details Inputs: none * @details Outputs: voltages[] * @param signal the signal to override * @param value override signal level with this value * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetLineLevelOverride( U32 signal, F32 value ) { BOOL result = FALSE; if ( signal < NUM_OF_MONITORED_LINES ) { if ( TRUE == isTestingActivated() ) { result = TRUE; voltages[ signal ].ovData = value; voltages[ signal ].override = OVERRIDE_KEY; } } return result; } /*********************************************************************//** * @brief * The testResetLineLevelOverride function resets the override of the * given monitored voltage or current. * @details Inputs: none * @details Outputs: voltages[] * @param signal the signal to reset override * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetLineLevelOverride( U32 signal ) { BOOL result = FALSE; if ( signal < NUM_OF_MONITORED_LINES ) { if ( TRUE == isTestingActivated() ) { result = TRUE; voltages[ signal ].override = OVERRIDE_RESET; voltages[ signal ].ovData = voltages[ signal ].ovInitData; } } return result; } /**@}*/