Index: firmware/App/Services/AlarmMgmt.c =================================================================== diff -u -rebbb1f85550a1f9b8f946655f7b2b63f76fbf67d -rea42ed9f07834acc921c934a2312e7fdd572dbd9 --- firmware/App/Services/AlarmMgmt.c (.../AlarmMgmt.c) (revision ebbb1f85550a1f9b8f946655f7b2b63f76fbf67d) +++ firmware/App/Services/AlarmMgmt.c (.../AlarmMgmt.c) (revision ea42ed9f07834acc921c934a2312e7fdd572dbd9) @@ -1,23 +1,28 @@ /************************************************************************** * -* Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. +* 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 AlarmMgmt.c +* @file AlarmMgmt.c * -* @author (last) Quang Nguyen -* @date (last) 26-Aug-2020 +* @author (last) Dara Navaei +* @date (last) 06-Jul-2022 * -* @author (original) Sean -* @date (original) 04-Feb-2020 +* @author (original) Sean +* @date (original) 04-Feb-2020 * ***************************************************************************/ + +#define __ALARM_MGMT_C__ #include "AlarmMgmt.h" +#include "CPLD.h" #include "OperationModes.h" #include "PersistentAlarm.h" +#include "SafetyShutdown.h" +#include "SystemComm.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "Timers.h" @@ -28,17 +33,38 @@ */ // ********** private definitions ********** + +/// Interval (ms/task time) at which the alarm information is published on the CAN bus. +#define ALARM_INFO_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) +#define DATA_PUBLISH_COUNTER_START_COUNT 12 ///< Data publish counter start count. +#define ALARM_DG_FAULT_LED_ON_INTERVAL ( MS_PER_SECOND / 4 / TASK_GENERAL_INTERVAL ) ///< LED Flash ON time interval time +#define ALARM_DG_FAULT_LED_OFF_INTERVAL ( ALARM_DG_FAULT_LED_ON_INTERVAL * 2 ) ///< LED Flash OFF time interval time + +// *** This declaration will cause a compiler error if ALARM_TABLE does not have same # of alarms as the Alarm_List enumeration. +U08 alarmTableSizeAssertion[ ( ( sizeof( ALARM_TABLE ) / sizeof( ALARM_T ) ) == NUM_OF_ALARM_IDS ? 1 : -1 ) ]; + +// *** This declaration will cause a compiler error if ALARM_RANK_TABLE does not have same # of alarms as the Alarm_List enumeration. +U08 alarmRankTableSizeAssertion[ ( ( sizeof( ALARM_RANK_TABLE ) / sizeof( ALARM_RANK_T ) ) == NUM_OF_ALARM_IDS ? 1 : -1 ) ]; + +U32 alarmLEDTimer; -const ALARM_DATA_T blankAlarmData = { ALARM_DATA_TYPE_NONE, 0 }; ///< A blank alarm data record for alarms that do not include alarm data when triggered. +const ALARM_DATA_T BLANK_ALARM_DATA = { ALARM_DATA_TYPE_NONE, 0 }; ///< A blank alarm data record for alarms that do not include alarm data when triggered. +#define SUPERVISOR_ALARM_KEY 0xD2C3B4A5 ///< 32-bit key required for clear all alarms request. + // ********** private data ********** -static OVERRIDE_U32_T alarmIsActive[ NUM_OF_ALARM_IDS ]; ///< Array of current state of each alarm +static BOOL alarmIsActive[ NUM_OF_ALARM_IDS ]; ///< Array of current state of each alarm static BOOL alarmConditionIsActive[ NUM_OF_ALARM_IDS ]; ///< Array of flag indicates if an alarm condition is active +static U32 alarmInfoPublicationTimerCounter; ///< Used to schedule alarm information publication to CAN bus. +/// Interval (in task intervals) at which to publish alarm information to CAN bus. +static OVERRIDE_U32_T alarmInfoPublishInterval = { ALARM_INFO_PUB_INTERVAL, ALARM_INFO_PUB_INTERVAL, ALARM_INFO_PUB_INTERVAL, 0 }; // ********** private function prototypes ********** static void activateAlarm( ALARM_ID_T alarm ); +static void publishAlarmInfo( void ); +static void alarmUserNotify( void ); /*********************************************************************//** * @brief @@ -49,16 +75,15 @@ *************************************************************************/ void initAlarmMgmt( void ) { - ALARM_ID_T alrm; + ALARM_ID_T alrm; + + alarmInfoPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; + alarmLEDTimer = 0; // initialize alarm states and start time stamps for ( alrm = ALARM_ID_NO_ALARM; alrm < NUM_OF_ALARM_IDS; alrm++ ) { - alarmIsActive[ alrm ].data = FALSE; - alarmIsActive[ alrm ].ovData = FALSE; - alarmIsActive[ alrm ].ovInitData = TRUE; - alarmIsActive[ alrm ].override = OVERRIDE_RESET; - + alarmIsActive[ alrm ] = FALSE; alarmConditionIsActive[ alrm ] = FALSE; } } @@ -72,7 +97,11 @@ *************************************************************************/ void execAlarmMgmt( void ) { - // TODO - any alarm audio or LED/lamp management for DG? + // Alarm audio and LED/lamp management for DG + alarmUserNotify(); + + // Publish alarm information at interval + publishAlarmInfo(); } /*********************************************************************//** @@ -89,11 +118,22 @@ if ( ( alarm > ALARM_ID_NO_ALARM ) && ( alarm < NUM_OF_ALARM_IDS ) ) { // no need to do anything if alarm is already active - if ( FALSE == isAlarmActive( alarm ) ) + if ( FALSE == alarmIsActive[ alarm ] ) { // activate alarm - alarmIsActive[ alarm ].data = TRUE; - alarmConditionIsActive[ alarm ] = TRUE; + alarmIsActive[ alarm ] = TRUE; + alarmConditionIsActive[ alarm ] = TRUE; + + // If alarm is a DG fault, request transition to fault mode + if ( ( TRUE == ALARM_TABLE[ alarm ].alarmIsDGFault ) && ( getCurrentOperationMode() != DG_MODE_SERV ) ) + { + requestNewOperationMode( DG_MODE_FAUL ); + } + // If alarm has clear condition immediately property, clear condition now + if ( TRUE == ALARM_TABLE[ alarm ].alarmConditionClearImmed ) + { + clearAlarmCondition( alarm ); + } } } else @@ -112,25 +152,8 @@ * @return none *************************************************************************/ void activateAlarmNoData( ALARM_ID_T alarm ) -{ - // broadcast alarm and data if alarm not already active - if ( FALSE == alarmIsActive[ alarm ].data ) - { - broadcastAlarmTriggered( alarm, blankAlarmData, blankAlarmData ); -#ifdef DEBUG_ENABLED -#ifdef ALARMS_DEBUG - { - // TODO - temporary debug code - remove later - char debugStr[ 256 ]; - sprintf( debugStr, "ALARM trig:%5d \n", alarm ); - sendDebugData( (U08*)debugStr, strlen(debugStr) ); - sendDebugDataToUI( (U08*)debugStr ); - } -#endif -#endif - } - - activateAlarm( alarm ); +{ + activateAlarm2Data( alarm, BLANK_ALARM_DATA, BLANK_ALARM_DATA ); } /*********************************************************************//** @@ -145,25 +168,8 @@ * @return none *************************************************************************/ void activateAlarm1Data( ALARM_ID_T alarm, ALARM_DATA_T alarmData ) -{ - // broadcast alarm and data if alarm not already active - if ( FALSE == alarmIsActive[ alarm ].data ) - { - broadcastAlarmTriggered( alarm, alarmData, blankAlarmData ); -#ifdef DEBUG_ENABLED -#ifdef ALARMS_DEBUG - { - // TODO - temporary debug code - remove later - char debugStr[ 256 ]; - sprintf( debugStr, "ALARM trig:%5d %8X \n", alarm, alarmData.data.uInt.data ); - sendDebugData( (U08*)debugStr, strlen(debugStr) ); - sendDebugDataToUI( (U08*)debugStr ); - } -#endif -#endif - } - - activateAlarm( alarm ); +{ + activateAlarm2Data( alarm, alarmData, BLANK_ALARM_DATA ); } /*********************************************************************//** @@ -181,22 +187,10 @@ void activateAlarm2Data( ALARM_ID_T alarm, ALARM_DATA_T alarmData1, ALARM_DATA_T alarmData2 ) { // broadcast alarm and data if alarm not already active - if ( FALSE == alarmIsActive[ alarm ].data ) + if ( ( FALSE == alarmIsActive[ alarm ] ) && ( TRUE == isHDCommunicating() ) ) { broadcastAlarmTriggered( alarm, alarmData1, alarmData2 ); -#ifdef DEBUG_ENABLED -#ifdef ALARMS_DEBUG - { - // TODO - temporary debug code - remove later - char debugStr[ 256 ]; - sprintf( debugStr, "ALARM trig:%5d %8X %8X \n", alarm, alarmData1.data.uInt.data, alarmData2.data.uInt.data ); - sendDebugData( (U08*)debugStr, strlen(debugStr) ); - sendDebugDataToUI( (U08*)debugStr ); - } -#endif -#endif } - activateAlarm( alarm ); } @@ -215,22 +209,14 @@ if ( ( alarm > ALARM_ID_NO_ALARM ) && ( alarm < NUM_OF_ALARM_IDS ) ) { // clear alarm and broadcast alarm clear if not already cleared - if ( TRUE == alarmIsActive[ alarm ].data ) - { - broadcastAlarmCleared( alarm ); - alarmIsActive[ alarm ].data = FALSE; - clearAlarmCondition( alarm ); -#ifdef DEBUG_ENABLED -#ifdef ALARMS_DEBUG + if ( TRUE == alarmIsActive[ alarm ] ) + { + if ( TRUE == isHDCommunicating() ) { - // TODO - temporary debug code - remove later - char debugStr[ 256 ]; - sprintf( debugStr, "ALARM cleared:%5d \n", alarm ); - sendDebugData( (U08*)debugStr, strlen(debugStr) ); - sendDebugDataToUI( (U08*)debugStr ); + broadcastAlarmCleared( alarm ); } -#endif -#endif + alarmIsActive[ alarm ] = FALSE; + clearAlarmCondition( alarm ); } } else @@ -256,7 +242,10 @@ // clear alarm and broadcast alarm clear if not already cleared if ( TRUE == alarmConditionIsActive[ alarm ] ) { - broadcastAlarmConditionCleared( alarm ); + if ( TRUE == isHDCommunicating() ) + { + broadcastAlarmConditionCleared( alarm ); + } alarmConditionIsActive[ alarm ] = FALSE; } } @@ -276,48 +265,91 @@ *************************************************************************/ BOOL isAlarmActive( ALARM_ID_T alarm ) { - BOOL result = TRUE; - if ( alarm < NUM_OF_ALARM_IDS ) + return alarmIsActive[ alarm ]; +} + +/*********************************************************************//** + * @brief + * The publishAlarmInfo function publishes alarm information at the set + * interval. + * @details Inputs: + * @details Outputs: alarm information are published to CAN bus. + * @return none + *************************************************************************/ +static void publishAlarmInfo( void ) +{ + // Publish voltages monitor data on interval + if ( ++alarmInfoPublicationTimerCounter >= getU32OverrideValue( &alarmInfoPublishInterval ) ) { - if ( OVERRIDE_KEY == alarmIsActive[ alarm ].override ) + SAFETY_SHUTDOWN_ACTIVATION_DATA_T data; + + data.safetyShutdownStatus = (U32)isSafetyShutdownActivated(); + + broadcastData( MSG_ID_DG_ALARM_INFO, COMM_BUFFER_OUT_CAN_DG_ALARM, (U08*)&data, sizeof( SAFETY_SHUTDOWN_ACTIVATION_DATA_T ) ); + broadcastCPLDStatus(); + alarmInfoPublicationTimerCounter = 0; + } +} + +/*********************************************************************//** + * @brief +* The handleResendActiveAlarmsRequest function processes the request to re-send +* all active alarms. +* @details Inputs: alarmIsActive[] +* @details Outputs: re-send active alarms to UI +* @return none +*************************************************************************/ +void handleResendActiveAlarmsRequest( void ) +{ + U32 index; + + for ( index = 0; index < NUM_OF_ALARM_IDS; index++ ) + { + if ( TRUE == isAlarmActive( (ALARM_ID_T)index ) ) { - result = (BOOL)alarmIsActive[ alarm ].ovData; + broadcastAlarmTriggered( index, BLANK_ALARM_DATA, BLANK_ALARM_DATA ); } - else - { - result = (BOOL)alarmIsActive[ alarm ].data; - } } - else - { - activateAlarmNoData( ALARM_ID_DG_SOFTWARE_FAULT ); - } +} - return result; -} - -/*********************************************************************//** +/************************************************************************* * @brief - * The checkPersistentAlarm function triggers/clears an alarm if an alarm condition - * has persisted/cleared over given time limit. + * The alarmUserNotify function activates Fault LED and Audio if FAULT exists. * @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 + * @details Outputs: LED and Audio control + * @param none + * @return none *************************************************************************/ -void checkPersistentAlarm( ALARM_ID_T alarm, BOOL const isErrorOccured, F32 const data, F32 const limit ) +static void alarmUserNotify( void ) { - if ( TRUE == isPersistentAlarmTriggered( alarm, isErrorOccured ) ) + if ( getCurrentOperationMode() == DG_MODE_FAUL ) { - SET_ALARM_WITH_2_F32_DATA( alarm, data, limit ); - } + alarmLEDTimer++; + // Flash Fault LED + if ( alarmLEDTimer <= ALARM_DG_FAULT_LED_ON_INTERVAL ) + { + setCPLDFaultLED( PIN_SIGNAL_HIGH, TRUE ); // Set Fault LED + } + else if ( alarmLEDTimer <= ALARM_DG_FAULT_LED_OFF_INTERVAL ) + { + setCPLDFaultLED( PIN_SIGNAL_LOW, TRUE ); // Clear Fault LED + } + else + { + alarmLEDTimer = 0; // restart timer + } - if ( TRUE == isPersistentAlarmConditionCleared( alarm, isErrorOccured ) ) + // If HD COM has failed, sound alarm + if ( FALSE == isHDCommunicating() ) + { + setCPLDFaultAudio( PIN_SIGNAL_HIGH ); // Set Fault Audio + } + } + else { - clearAlarmCondition( alarm ); + // No FAULTs + setCPLDFaultLED( PIN_SIGNAL_LOW, FALSE ); // Clear Fault LED + setCPLDFaultAudio( PIN_SIGNAL_LOW ); // Clear Fault Audio } } @@ -385,4 +417,93 @@ return result; } +/*********************************************************************//** + * @brief + * The testClearAllAlarms function clears all active alarms, even if they + * are non-recoverable or faults. The caller of this function must provide + * the correct 32-bit key. A Dialin user must also be logged into DG. + * @details Inputs: none + * @details Outputs: alarmIsActive[], alarmStartedAt[] + * @param key 32-bit supervior alarm key required to perform this function + * @return TRUE if override reset successful, FALSE if not + *************************************************************************/ +BOOL testClearAllAlarms( U32 key ) +{ + BOOL result = FALSE; + + // Verify key + if ( SUPERVISOR_ALARM_KEY == key ) + { + // Verify tester has logged in with HD + if ( TRUE == isTestingActivated() ) + { + ALARM_ID_T a; + + // Clear all active alarms + for ( a = ALARM_ID_NO_ALARM; a < NUM_OF_ALARM_IDS; a++ ) + { + if ( TRUE == alarmIsActive[ a ] ) + { + ALARM_NAME_DATA_T data; + + data.alarmName = (U32)a; + + broadcastData( MSG_ID_ALARM_CLEARED, COMM_BUFFER_OUT_CAN_DG_ALARM, (U08*)&data, sizeof( ALARM_NAME_DATA_T ) ); + alarmIsActive[ a ] = FALSE; + } + } + result = TRUE; + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetAlarmInfoPublishIntervalOverride function sets the override of the + * alarm information publication interval. + * @details Inputs: none + * @details Outputs: alarmInfoPublishInterval + * @param ms milliseconds between alarm info broadcasts + * @return TRUE if override set successful, FALSE if not + *************************************************************************/ +BOOL testSetAlarmInfoPublishIntervalOverride( U32 ms ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + U32 intvl = ms / TASK_GENERAL_INTERVAL; + + result = TRUE; + alarmInfoPublishInterval.ovData = intvl; + alarmInfoPublishInterval.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetAlarmInfoPublishIntervalOverride function resets the override of the + * alarm information publication interval. + * @details Inputs: none + * @details Outputs: alarmInfoPublishInterval + * @return TRUE if override reset successful, FALSE if not + *************************************************************************/ +BOOL testResetAlarmInfoPublishIntervalOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + alarmInfoPublishInterval.override = OVERRIDE_RESET; + alarmInfoPublishInterval.ovData = alarmInfoPublishInterval.ovInitData; + } + + return result; +} + /**@}*/