/************************************************************************** * * Copyright (c) 2020-2022 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) Dara Navaei * @date (last) 04-Jan-2022 * * @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 #define FPGA_READ_ALARM_INDEX 0 #define FPGA_ERROR_ALARM_INDEX 1 /// FPGA persistent alarm types typedef enum { FPGA_READ_ERROR = 0, FPGA_ERROR_ERROR, FPGA_NOT_UPDATING_ERROR, NUM_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 } 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_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 ]; // ********** 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; } 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 } } 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; memset( &fpgaPersistentAlarmGroup[ group ].fpgaAlarmData[ FPGA_READ_ALARM_INDEX ], 0x0, sizeof( FPGA_ALARM_DATA_T ) ); memset( &fpgaPersistentAlarmGroup[ group ].fpgaAlarmData[ FPGA_ERROR_ALARM_INDEX ], 0x0, sizeof( FPGA_ALARM_DATA_T ) ); } } /*********************************************************************//** * @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 ) { // 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 ); #else 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; } 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; case FPGA_NOT_UPDATING_ERROR: 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; } void checkFPGAPersistentAlarms( FPGA_PERSISTENT_ALARMS_GROUP_T group, U32 errorCount, U32 readCount, U32 sensorIndex ) { if ( group < NUM_OF_FPGA_SENSOR_GROUPS ) { FPGA_ERROR_TYPE_T type = NUM_OF_FPGA_ERROR_TYPES; BOOL isPersistenceTrgrd = FALSE; FPGA_ALARM_DATA_T readData = fpgaPersistentAlarmGroup[ group ].fpgaAlarmData[ FPGA_READ_ERROR ]; FPGA_ALARM_DATA_T errorData = fpgaPersistentAlarmGroup[ group ].fpgaAlarmData[ FPGA_ERROR_ERROR ]; if ( ( readCount == readData.fpgaPreviousCount ) && ( errorCount == errorData.fpgaPreviousCount ) ) { type = FPGA_NOT_UPDATING_ERROR; isPersistenceTrgrd = isFPGAPersistentAlarmTriggered( &fpgaPersistentAlarmGroup[ group ], readCount, FPGA_NOT_UPDATING_ERROR ); } else if ( readData.fpgaPreviousCount != readCount ) { type = FPGA_READ_ERROR; isPersistenceTrgrd = isFPGAPersistentAlarmTriggered( &fpgaPersistentAlarmGroup[ group ], readCount, FPGA_READ_ERROR ); } else if ( errorData.fpgaPreviousCount != errorCount ) { type = FPGA_ERROR_ERROR; isPersistenceTrgrd = isFPGAPersistentAlarmTriggered( &fpgaPersistentAlarmGroup[ group ], errorCount, FPGA_ERROR_ERROR ); } if ( TRUE == isPersistenceTrgrd ) { SET_ALARM_WITH_2_U32_DATA( fpgaPersistentAlarmGroup[ group ].fpgaAlarm, type, sensorIndex ); } } else { // TODO software fault } } /**@}*/