/************************************************************************** * * Copyright (c) 2020-2023 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 PersistentAlarm.c * * @author (last) Bill Bracken * @date (last) 30-Mar-2023 * * @author (original) Quang Nguyen * @date (original) 17-Aug-2020 * ***************************************************************************/ #include "AlarmMgmt.h" #include "PersistentAlarm.h" #include "Timers.h" /** * @addtogroup PersistentAlarm * @{ */ // ********** private definitions ********** #define NUM_OF_FPGA_ALARMS_PER_GROUP 2 ///< Number of FPGA alarms per group. #define FPGA_READ_ALARM_INDEX 0 ///< FPGA read alarm index number. #define FPGA_ERROR_ALARM_INDEX 1 ///< FPGA error alarm index number. /// FPGA persistent alarm types typedef enum { FPGA_READ_ERROR = 0, ///< FPGA read error type. FPGA_ERROR_ERROR, ///< FPGA error error type. NUM_OF_FPGA_ERROR_TYPES ///< Number of FPGA error types. } FPGA_ERROR_TYPE_T; /// Persistent alarm structure typedef struct { ALARM_ID_T alarm; ///< Alarm ID. U32 persistentClearPeriod; ///< Persistent count limit before clear alarm. U32 persistentTriggerPeriod; ///< Persistent count limit before trigger alarm. U32 errorClearedStartTime; ///< Error cleared start time. U32 errorOccurredStartTime; ///< Error occurred start time. BOOL alarmActive; ///< State of alarm last time alarm checked. } PERSISTENT_ALARM_DATA_T; /// FPGA persistent alarm data structure typedef struct { U32 fpagErrorClearedStartTime; ///< FPGA error cleared start time. U32 fpgaErrorOccurredStartTime; ///< FPGA error occurred start time. U32 fpgaPreviousCount; ///< FPGA previous read count. BOOL fpgaIsConditionClear; ///< FPGA is persistent condition clear. } FPGA_ALARM_DATA_T; /// FPGA persistent alarm structure typedef struct { ALARM_ID_T fpgaAlarm; ///< FPGA read alarm. U32 fpgaPersistentClearPeriod; ///< FPGA persistent count limit before clear alarm. U32 fpgaPersistentTriggerPeriod; ///< FPGA persistent count limit before trigger alarm. FPGA_ALARM_DATA_T fpgaAlarmData[ NUM_OF_FPGA_ERROR_TYPES ]; ///< FPGA persistent alarm data. } FPGA_PERSISTENT_ALARM_GROUP_T; // ********** private data ********** static PERSISTENT_ALARM_DATA_T persistentAlarms[ NUM_OF_ALARM_IDS ]; ///< Array of persistent alarm structure. static FPGA_PERSISTENT_ALARM_GROUP_T fpgaPersistentAlarmGroup[ NUM_OF_FPGA_SENSOR_GROUPS ]; ///< FPGA persistent alarm group. // ********** private function prototypes ********** static BOOL isFPGAPersistentAlarmTriggered( FPGA_PERSISTENT_ALARM_GROUP_T* alarmGroup, U32 fpgaCount, FPGA_ERROR_TYPE_T errorType ); /*********************************************************************//** * @brief * The initPersistentAlarm function initializes the PersistentAlarm module * when the alarm count lower than maximum persistent alarm allowed. * @details Inputs: none * @details Outputs: PersistentAlarm module initialized * @param alarmId Alarm id * @param persistentClearPeriod Persistent period limit before clear alarm (in ms) * @param persistentTriggerPeriod Persistent period limit before trigger alarm (in ms) * @return none *************************************************************************/ void initPersistentAlarm( ALARM_ID_T alarmId, U32 persistentClearPeriod, U32 persistentTriggerPeriod ) { if ( alarmId < NUM_OF_ALARM_IDS ) { persistentAlarms[ alarmId ].persistentClearPeriod = persistentClearPeriod; persistentAlarms[ alarmId ].persistentTriggerPeriod = persistentTriggerPeriod; persistentAlarms[ alarmId ].errorClearedStartTime = 0U; persistentAlarms[ alarmId ].errorOccurredStartTime = 0U; persistentAlarms[ alarmId ].alarmActive = FALSE; } else { #ifdef _DG_ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_PERSISTENT_ALARM_INVALID_INDEX, alarmId ); #else SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_PERSISTENT_ALARM_INVALID_INDEX, alarmId ); #endif } } /*********************************************************************//** * @brief * The initFPGAPersistentAlarm function initializes the FPGA persistent alarm * when the alarm count lower than maximum persistent alarm allowed and the FPGA * sensor group is less than the maximum allowed sensor group. * @details Inputs: none * @details Outputs: fpgaPersistentAlarmGroup * @param group which is the FPGA persistent alarm group * @param alarmId Alarm id * @param persistentClearPeriod Persistent period limit before clear alarm (in ms) * @param persistentTriggerPeriod Persistent period limit before trigger alarm (in ms) * @return none *************************************************************************/ void initFPGAPersistentAlarm( FPGA_PERSISTENT_ALARMS_GROUP_T group, ALARM_ID_T alarmIndex, U32 persistentClearPeriod, U32 persistentTriggerPeriod ) { if ( ( group < NUM_OF_FPGA_SENSOR_GROUPS ) && ( alarmIndex < NUM_OF_ALARM_IDS ) ) { fpgaPersistentAlarmGroup[ group ].fpgaAlarm = alarmIndex; fpgaPersistentAlarmGroup[ group ].fpgaPersistentClearPeriod = persistentClearPeriod; fpgaPersistentAlarmGroup[ group ].fpgaPersistentTriggerPeriod = persistentTriggerPeriod; fpgaPersistentAlarmGroup[ group ].fpgaAlarmData[ FPGA_READ_ALARM_INDEX ].fpgaIsConditionClear = TRUE; fpgaPersistentAlarmGroup[ group ].fpgaAlarmData[ FPGA_READ_ALARM_INDEX ].fpagErrorClearedStartTime = 0; fpgaPersistentAlarmGroup[ group ].fpgaAlarmData[ FPGA_READ_ALARM_INDEX ].fpgaErrorOccurredStartTime = 0; fpgaPersistentAlarmGroup[ group ].fpgaAlarmData[ FPGA_READ_ALARM_INDEX ].fpgaPreviousCount = 0; fpgaPersistentAlarmGroup[ group ].fpgaAlarmData[ FPGA_ERROR_ALARM_INDEX ].fpgaIsConditionClear = TRUE; fpgaPersistentAlarmGroup[ group ].fpgaAlarmData[ FPGA_ERROR_ALARM_INDEX ].fpagErrorClearedStartTime = 0; fpgaPersistentAlarmGroup[ group ].fpgaAlarmData[ FPGA_ERROR_ALARM_INDEX ].fpgaErrorOccurredStartTime = 0; fpgaPersistentAlarmGroup[ group ].fpgaAlarmData[ FPGA_ERROR_ALARM_INDEX ].fpgaPreviousCount = 0; } } /*********************************************************************//** * @brief * The isPersistentAlarmTriggered function checks if the error condition has * persisted for given time limit. * @details Inputs: persistentAlarms[] * @details Outputs: none * @param alarmId Alarm id * @param isErrorOccurred Flag indicates error condition is occurring or not * @return TRUE if error condition persisted over given time limit, FALSE if not *************************************************************************/ BOOL isPersistentAlarmTriggered( ALARM_ID_T alarmId, BOOL const isErrorOccurred ) { BOOL isAlarmTriggered = FALSE; if ( alarmId < NUM_OF_ALARM_IDS ) { BOOL alarmIsActive = isAlarmActive( alarmId ); // Reset persistence if alarm was just cleared if ( ( FALSE == alarmIsActive ) && ( TRUE == persistentAlarms[ alarmId ].alarmActive ) ) { persistentAlarms[ alarmId ].errorOccurredStartTime = 0; } persistentAlarms[ alarmId ].alarmActive = alarmIsActive; // remember latest alarm state for next time // Update start time when error occurs for the first time if ( ( TRUE == isErrorOccurred ) && ( 0 == persistentAlarms[ alarmId ].errorOccurredStartTime ) ) { persistentAlarms[ alarmId ].errorOccurredStartTime = getMSTimerCount(); } if ( TRUE == isErrorOccurred ) { isAlarmTriggered = didTimeout( persistentAlarms[ alarmId ].errorOccurredStartTime, persistentAlarms[ alarmId ].persistentTriggerPeriod ); } else { persistentAlarms[ alarmId ].errorOccurredStartTime = 0; } } else { #ifdef _DG_ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_PERSISTENT_ALARM_INVALID_INDEX, alarmId ); #else SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_PERSISTENT_ALARM_INVALID_INDEX, alarmId ); #endif } return isAlarmTriggered; } /*********************************************************************//** * @brief * The isPersistentAlarmConditionCleared function checks if the error condition has * been cleared for given time limit. * @details Inputs: persistentAlarms[] * @details Outputs: none * @param alarmId Alarm id * @param isErrorOccurred Flag indicates error condition is occurring or not * @return TRUE if error condition has been cleared over given time limit, FALSE if not *************************************************************************/ BOOL isPersistentAlarmConditionCleared( ALARM_ID_T alarmId, BOOL const isErrorOccurred ) { BOOL isErrorConditionCleared = FALSE; if ( alarmId < NUM_OF_ALARM_IDS ) { // Update start time when error condition clears for the first time if ( ( FALSE == isErrorOccurred ) && ( 0 == persistentAlarms[ alarmId ].errorClearedStartTime ) ) { persistentAlarms[ alarmId ].errorClearedStartTime = getMSTimerCount(); } if ( FALSE == isErrorOccurred ) { isErrorConditionCleared = didTimeout( persistentAlarms[ alarmId ].errorClearedStartTime, persistentAlarms[ alarmId ].persistentClearPeriod ); } else { persistentAlarms[ alarmId ].errorClearedStartTime = 0; } } else { #ifdef _DG_ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_PERSISTENT_ALARM_INVALID_INDEX, alarmId ) #endif #ifdef _HD_ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_PERSISTENT_ALARM_INVALID_INDEX, alarmId ) #endif } return isErrorConditionCleared; } /*********************************************************************//** * @brief * The checkPersistentAlarm function triggers/clears an alarm if an alarm condition * has persisted/cleared over given time limit. * @details Inputs: none * @details Outputs: checks whether an alarm is triggered or an alarm condition is cleared * @param alarmID ID of alarm to check * @param isErrorOccured Flag indicates alarm condition is active or not * @param data alarm data * @param limit alarm condition limit * @return TRUE if given alarm is active, FALSE if not *************************************************************************/ BOOL checkPersistentAlarm( ALARM_ID_T alarm, BOOL isErrorOccured, F32 data, F32 limit ) { BOOL status = FALSE; if ( TRUE == isPersistentAlarmTriggered( alarm, isErrorOccured ) ) { SET_ALARM_WITH_2_F32_DATA( alarm, data, limit ); } if ( TRUE == isPersistentAlarmConditionCleared( alarm, isErrorOccured ) ) { clearAlarmCondition( alarm ); status = TRUE; } return status; } /*********************************************************************//** * @brief * The resetPersistentAlarmTimer function resets the start time for error * condition clear start time and error start time. * @details Inputs: none * @details Outputs: reset condition clear start time and error occur start time * @param alarmId Alarm id of the alarm to reset timer * @return none *************************************************************************/ void resetPersistentAlarmTimer( ALARM_ID_T alarmId ) { persistentAlarms[ alarmId ].errorOccurredStartTime = 0; persistentAlarms[ alarmId ].errorClearedStartTime = 0; } /*********************************************************************//** * @brief * The checkFPGAPersistentAlarms function checks the FPGA persistent alarm * status of the provided FPGA persistent alarm group. * @details Inputs: fpgaPersistentAlarmGroup * @details Outputs: fpgaPersistentAlarmGroup * @param alarmGroup which is the alarm group of the persistent alarm * (i.e. 2-wire temperature sensor) * @param readCount which is the FPGA read count of the sensor group * @return none *************************************************************************/ void checkFPGAPersistentAlarms( FPGA_PERSISTENT_ALARMS_GROUP_T group, U32 readCount ) { if ( group < NUM_OF_FPGA_SENSOR_GROUPS ) { FPGA_ERROR_TYPE_T type = FPGA_READ_ERROR; BOOL isReadPersTrgrd = isFPGAPersistentAlarmTriggered( &fpgaPersistentAlarmGroup[ group ], readCount, type ); if ( TRUE == isReadPersTrgrd ) { SET_ALARM_WITH_2_U32_DATA( fpgaPersistentAlarmGroup[ group ].fpgaAlarm, type, group ) } } else { #ifdef _DG_ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_FPGA_SENSOR_GROUP_SELECTED, (U32)group ) #endif #ifdef _HD_ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_FPGA_SENSOR_GROUP_SELECTED, (U32)group ) #endif } } /*********************************************************************//** * @brief * The checkFPGAPersistentErrorCountAlarm function checks the FPGA persistent * error count alarm status of the provided FPGA persistent alarm group. * @details Inputs: fpgaPersistentAlarmGroup * @details Outputs: none * @param alarmGroup which is the alarm group of the persistent alarm * (i.e. 2-wire temperature sensor) * @param errorCount which is the FPGA error count of the sensor group * @return none *************************************************************************/ void checkFPGAPersistentErrorCountAlarm( FPGA_PERSISTENT_ALARMS_GROUP_T group, U32 errorCount ) { if ( group < NUM_OF_FPGA_SENSOR_GROUPS ) { BOOL isErrorPersTrgrd = isFPGAPersistentAlarmTriggered( &fpgaPersistentAlarmGroup[ group ], errorCount, FPGA_ERROR_ERROR ); if ( TRUE == isErrorPersTrgrd ) { SET_ALARM_WITH_2_U32_DATA( fpgaPersistentAlarmGroup[ group ].fpgaAlarm, FPGA_ERROR_ERROR, group ) } } else { #ifdef _DG_ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_FPGA_SENSOR_GROUP_SELECTED, (U32)group ) #endif #ifdef _HD_ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_FPGA_SENSOR_GROUP_SELECTED, (U32)group ) #endif } } /*********************************************************************//** * @brief * The isFPGAPersistentAlarmTriggered function checks whether persistent alarm * has been triggered or not. * @details Inputs: alarmGroup * @details Outputs: alarmGroup * @param alarmGroup which is the alarm group of the persistent alarm * (i.e. 2-wire temperature sensor) * @param fpgaCount which is the FPGA count of the sensor group * @param errorType which is the FPGA error type (i.e. read or error count) * @return TRUE if the persistent alarm is triggered otherwise, FALSE *************************************************************************/ static BOOL isFPGAPersistentAlarmTriggered( FPGA_PERSISTENT_ALARM_GROUP_T* alarmGroup, U32 fpgaCount, FPGA_ERROR_TYPE_T errorType ) { BOOL isPersistentTriggered = FALSE; BOOL hasErrorOccured = FALSE; switch ( errorType ) { case FPGA_READ_ERROR: hasErrorOccured = ( fpgaCount == alarmGroup->fpgaAlarmData[ errorType ].fpgaPreviousCount ? TRUE : FALSE ); break; case FPGA_ERROR_ERROR: hasErrorOccured = ( alarmGroup->fpgaAlarmData[ errorType ].fpgaPreviousCount != fpgaCount ? TRUE : FALSE ); break; default: #ifdef _DG_ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_FPGA_ERROR_GROUP_SELECTED, errorType ) #endif #ifdef _HD_ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_FPGA_ERROR_GROUP_SELECTED, errorType ) #endif break; } if ( TRUE == hasErrorOccured ) { if ( TRUE == alarmGroup->fpgaAlarmData[ errorType ].fpgaIsConditionClear ) { alarmGroup->fpgaAlarmData[ errorType ].fpgaIsConditionClear = FALSE; alarmGroup->fpgaAlarmData[ errorType ].fpgaErrorOccurredStartTime = getMSTimerCount(); } else if ( TRUE == didTimeout( alarmGroup->fpgaAlarmData[ errorType ].fpgaErrorOccurredStartTime, alarmGroup->fpgaPersistentTriggerPeriod ) ) { isPersistentTriggered = TRUE; } } else { alarmGroup->fpgaAlarmData[ errorType ].fpgaIsConditionClear = TRUE; } alarmGroup->fpgaAlarmData[ errorType ].fpgaPreviousCount = fpgaCount; return isPersistentTriggered; } /**@}*/