diff --git a/cmake/sample_defs/cpu1_platform_cfg.h b/cmake/sample_defs/cpu1_platform_cfg.h index 3e85be30c..167eedd53 100644 --- a/cmake/sample_defs/cpu1_platform_cfg.h +++ b/cmake/sample_defs/cpu1_platform_cfg.h @@ -565,7 +565,7 @@ ** in the error log. Any context information beyond this size will ** be truncated. */ -#define CFE_PLATFORM_ES_ER_LOG_MAX_CONTEXT_SIZE 128 +#define CFE_PLATFORM_ES_ER_LOG_MAX_CONTEXT_SIZE 256 /** @@ -1205,52 +1205,6 @@ */ #define CFE_PLATFORM_ES_DEFAULT_STACK_SIZE 8192 -/** -** \cfeescfg Define cFE Core Exception Function -** -** \par Description: -** This parameter defines the function-to-call when a CPU or floating point exception -** occurs. The parameter is defaulted to call the ES API function #CFE_ES_ProcessCoreException -** which handles the logging and reset from a system or cFE core exception. -** -** Note: Exception interrupts are trapped at the Platform Support Package (PSP) -** layer. In order to initiate the cFE platform defined response to an exception, this -** platform defined callback function must be prototyped and called from the PSP -** exception hook API function #CFE_PSP_ExceptionHook. For example: -** -** -- cfe_psp.h -- -** -** .... Prototype for exception ISR function implemented in CFE .... -** -** typedef void (*System_ExceptionFunc_t)(uint32 HostTaskId, -** const char *ReasonString, -** const uint32 *ContextPointer, -** uint32 ContextSize); -** -** -- cfe_pspexception.c -- -** -** .... Setup function pointer to CFE exception ISR callback .... -** -** static const System_ExceptionFunc_t CFE_ExceptionCallback = CFE_PLATFORM_ES_EXCEPTION_FUNCTION; -** -** void CFE_PSP_ExceptionHook (int task_id, int vector, uint8 *pEsf ) -** { -** .... platform-specific logic .... -** -** .... Use function pointer to call cFE routine to finish processing the exception .... -** -** CFE_ExceptionCallback((uint32)task_id, -** CFE_PSP_ExceptionReasonString, -** (uint32 *)&CFE_PSP_ExceptionContext, -** sizeof(CFE_PSP_ExceptionContext_t)); -** -** } -** -** \par Limits -** Must be a valid function name. -*/ -#define CFE_PLATFORM_ES_EXCEPTION_FUNCTION CFE_ES_ProcessCoreException - /** ** \cfeescfg Define EVS Task Priority ** diff --git a/cmake/target/inc/target_config.h b/cmake/target/inc/target_config.h index d88d512a5..71c6082cc 100644 --- a/cmake/target/inc/target_config.h +++ b/cmake/target/inc/target_config.h @@ -51,10 +51,15 @@ typedef void (*System_1HzISRFunc_t)(void); /** - * Prototype for exception ISR function implemented in CFE ES + * Prototype for notification function implemented in CFE ES * The PSP should call this when exceptions occur. + * + * NOTE: the PSP must call this routine only from a context where + * it is possible to use OSAL primitives. This means it must _not_ + * be called from an ISR/signal context on systems where these are + * restricted. */ -typedef void (*System_ExceptionFunc_t)(uint32 HostTaskId, const char *ReasonString, const uint32 *ContextPointer, uint32 ContextSize); +typedef void (*System_NotifyFunc_t)(void); /** * Abstract pointer to a module API @@ -87,9 +92,9 @@ typedef const struct System_MainFunc_t SystemMain; /** - * Exception handler function. Called from PSP during exception handling. + * Notification function. Called from PSP after async event handling. */ - System_ExceptionFunc_t SystemExceptionISR; + System_NotifyFunc_t SystemNotify; /* * Sizes of memory segments required by the CFE based on the current config diff --git a/cmake/target/src/target_config.c b/cmake/target/src/target_config.c index 1bde3d10b..f15233450 100644 --- a/cmake/target/src/target_config.c +++ b/cmake/target/src/target_config.c @@ -37,6 +37,7 @@ #include "cfe_platform_cfg.h" #include "cfe_es.h" #include "cfe_time.h" +#include "private/cfe_es_resetdata_typedef.h" #include "cfecfs_version_info.h" #include "cfecfs_build_info.h" @@ -61,7 +62,7 @@ Target_CfeConfigData GLOBAL_CFE_CONFIGDATA = */ .System1HzISR = CFE_TIME_Local1HzISR, .SystemMain = CFE_ES_Main, - .SystemExceptionISR = CFE_ES_ProcessCoreException, + .SystemNotify = CFE_ES_ProcessAsyncEvent, /* * Default values for Startup file. @@ -73,7 +74,7 @@ Target_CfeConfigData GLOBAL_CFE_CONFIGDATA = * Sizes of other memory segments */ .CdsSize = CFE_PLATFORM_ES_CDS_SIZE, - .ResetAreaSize = CFE_PLATFORM_ES_RESET_AREA_SIZE, + .ResetAreaSize = sizeof(CFE_ES_ResetData_t), .UserReservedSize = CFE_PLATFORM_ES_USER_RESERVED_SIZE, .RamDiskSectorSize = CFE_PLATFORM_ES_RAM_DISK_SECTOR_SIZE, diff --git a/docs/src/main.dox b/docs/src/main.dox index d3d583d84..d2cdf1efc 100644 --- a/docs/src/main.dox +++ b/docs/src/main.dox @@ -472,7 +472,7 @@ diff --git a/fsw/cfe-core/src/es/cfe_es_api.c b/fsw/cfe-core/src/es/cfe_es_api.c index b863f1f69..7c39418ec 100644 --- a/fsw/cfe-core/src/es/cfe_es_api.c +++ b/fsw/cfe-core/src/es/cfe_es_api.c @@ -43,6 +43,7 @@ #include "cfe_es_events.h" #include "cfe_es_cds.h" #include "cfe_es_cds_mempool.h" +#include "cfe_es_task.h" #include "cfe_psp.h" #include "cfe_es_log.h" @@ -96,7 +97,7 @@ int32 CFE_ES_ResetCFE(uint32 ResetType) */ CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_POWERON, CFE_PSP_RST_SUBTYPE_RESET_COMMAND, - "POWER ON RESET due to max proc resets (Commanded).", NULL,0 ); + "POWER ON RESET due to max proc resets (Commanded)."); /* ** Call the BSP reset routine */ @@ -116,7 +117,7 @@ int32 CFE_ES_ResetCFE(uint32 ResetType) */ CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_PROCESSOR, CFE_PSP_RST_SUBTYPE_RESET_COMMAND, - "PROCESSOR RESET called from CFE_ES_ResetCFE (Commanded).", NULL,0 ); + "PROCESSOR RESET called from CFE_ES_ResetCFE (Commanded)."); /* ** Call the BSP reset routine */ @@ -140,7 +141,7 @@ int32 CFE_ES_ResetCFE(uint32 ResetType) */ CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_POWERON, CFE_PSP_RST_SUBTYPE_RESET_COMMAND, - "POWERON RESET called from CFE_ES_ResetCFE (Commanded).", NULL,0 ); + "POWERON RESET called from CFE_ES_ResetCFE (Commanded)."); /* ** Call the BSP reset routine @@ -1716,126 +1717,13 @@ void CFE_ES_UnlockSharedData(const char *FunctionName, int32 LineNumber) }/* end CFE_ES_UnlockSharedData */ /****************************************************************************** -** Function: CFE_ES_ProcessCoreException() - See API and header file for details +** Function: CFE_ES_ProcessAsyncEvent() +** +** Purpose: +** Called by the PSP to notify CFE ES that an asynchronous event occurred. */ -void CFE_ES_ProcessCoreException(uint32 HostTaskId, const char *ReasonString, - const uint32 *ContextPointer, uint32 ContextSize) +void CFE_ES_ProcessAsyncEvent(void) { - uint32 i; - int32 Status; - OS_task_prop_t TaskProp; - CFE_ES_TaskInfo_t EsTaskInfo; - uint32 FoundExceptionTask = 0; - uint32 ExceptionTaskID = 0; - - /* - ** If a loadable cFE Application caused the reset and it's - ** exception action is set to Restart the App rather than cause a - ** processor reset, then just reset the App. - */ - - /* - ** We have the Host Task Id ( vxWorks, RTEMS, etc ). Search - ** the OSAPI to see if a match can be found. - */ - for ( i = 0; i < OS_MAX_TASKS; i++ ) - { - if (CFE_ES_Global.TaskTable[i].RecordUsed == true) - { - ExceptionTaskID = CFE_ES_Global.TaskTable[i].TaskId; - Status = OS_TaskGetInfo (ExceptionTaskID, &TaskProp); - - if ( Status == OS_SUCCESS && TaskProp.OStask_id == HostTaskId ) - { - FoundExceptionTask = 1; - break; - } - } - } - - /* - ** If the Task is found in the OS, see if the cFE App ID associated with it can be found. - */ - if ( FoundExceptionTask == 1 ) - { - Status = CFE_ES_GetTaskInfo( &EsTaskInfo, ExceptionTaskID ); - /* - ** The App ID was found, now see if the ExceptionAction is set for a reset - */ - if ( Status == CFE_SUCCESS ) - { - if ( CFE_ES_Global.AppTable[EsTaskInfo.AppId].StartParams.ExceptionAction == CFE_ES_ExceptionAction_RESTART_APP ) - { - - /* - ** Log the Application reset - */ - CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_ES_APP_RESTART, - CFE_PSP_RST_SUBTYPE_EXCEPTION, (char *)ReasonString, - ContextPointer, ContextSize ); - - /* - ** Finally restart the App! This call is just a request - ** to ES. - */ - CFE_ES_RestartApp(EsTaskInfo.AppId ); - - /* - ** Return to avoid the Processor Restart Logic - */ - return; - - } /* end if ExceptionAction */ - - } /* end if */ - - } /* End if FoundExceptionTask */ - - /* - ** If we made it here, which means that we need to do a processor reset - */ - - /* - ** Before doing a Processor reset, check to see - ** if the maximum number has been exceeded - */ - if ( CFE_ES_ResetDataPtr->ResetVars.ProcessorResetCount >= - CFE_ES_ResetDataPtr->ResetVars.MaxProcessorResetCount ) - { - /* - ** Log the reset in the ER Log. The log will be wiped out, but it's good to have - ** the entry just in case something fails. - */ - CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_POWERON, - CFE_PSP_RST_SUBTYPE_EXCEPTION, (char *)ReasonString, - ContextPointer, ContextSize ); - - /* - ** Call the BSP reset routine to do a Poweron Reset - */ - CFE_PSP_Restart(CFE_PSP_RST_TYPE_POWERON); - - } - else /* Do a processor reset */ - { - /* - ** Update the reset variables - */ - CFE_ES_ResetDataPtr->ResetVars.ProcessorResetCount++; - CFE_ES_ResetDataPtr->ResetVars.ES_CausedReset = true; - - /* - ** Log the reset in the ER Log - */ - CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_PROCESSOR, - CFE_PSP_RST_SUBTYPE_EXCEPTION, (char *)ReasonString, - ContextPointer, ContextSize ); - - /* - ** Need to do a processor reset - */ - CFE_PSP_Restart(CFE_PSP_RST_TYPE_PROCESSOR); - - } /* end if */ - -} /* End of CFE_ES_ProcessCoreException */ + /* This just wakes up the background task to log/handle the event. */ + CFE_ES_BackgroundWakeup(); +} diff --git a/fsw/cfe-core/src/es/cfe_es_apps.h b/fsw/cfe-core/src/es/cfe_es_apps.h index b9a2254c4..19ec02890 100644 --- a/fsw/cfe-core/src/es/cfe_es_apps.h +++ b/fsw/cfe-core/src/es/cfe_es_apps.h @@ -198,6 +198,16 @@ int32 CFE_ES_AppDumpAllInfo(void); */ bool CFE_ES_RunAppTableScan(uint32 ElapsedTime, void *Arg); +/* +** Scan for new exceptions stored in the PSP +*/ +bool CFE_ES_RunExceptionScan(uint32 ElapsedTime, void *Arg); + +/* +** Check if ER log dump request is pending +*/ +bool CFE_ES_RunERLogDump(uint32 ElapsedTime, void *Arg); + /* ** Perform the requested control action for an application */ diff --git a/fsw/cfe-core/src/es/cfe_es_backgroundtask.c b/fsw/cfe-core/src/es/cfe_es_backgroundtask.c index 5582fa8da..5b874679e 100644 --- a/fsw/cfe-core/src/es/cfe_es_backgroundtask.c +++ b/fsw/cfe-core/src/es/cfe_es_backgroundtask.c @@ -82,6 +82,18 @@ const CFE_ES_BackgroundJobEntry_t CFE_ES_BACKGROUND_JOB_TABLE[] = .JobArg = &CFE_ES_TaskData.BackgroundPerfDumpState, .ActivePeriod = CFE_PLATFORM_ES_PERF_CHILD_MS_DELAY, .IdlePeriod = CFE_PLATFORM_ES_PERF_CHILD_MS_DELAY * 1000 + }, + { /* Check for exceptions stored in the PSP */ + .RunFunc = CFE_ES_RunExceptionScan, + .JobArg = NULL, + .ActivePeriod = CFE_PLATFORM_ES_APP_SCAN_RATE, + .IdlePeriod = CFE_PLATFORM_ES_APP_SCAN_RATE + }, + { /* Check for ER log write requests */ + .RunFunc = CFE_ES_RunERLogDump, + .JobArg = &CFE_ES_TaskData.BackgroundERLogDumpState, + .ActivePeriod = CFE_PLATFORM_ES_APP_SCAN_RATE, + .IdlePeriod = CFE_PLATFORM_ES_APP_SCAN_RATE } }; diff --git a/fsw/cfe-core/src/es/cfe_es_erlog.c b/fsw/cfe-core/src/es/cfe_es_erlog.c index 51ca03105..d4bf207d5 100644 --- a/fsw/cfe-core/src/es/cfe_es_erlog.c +++ b/fsw/cfe-core/src/es/cfe_es_erlog.c @@ -43,36 +43,49 @@ #include "cfe_es_apps.h" #include "cfe_es_global.h" #include "cfe_es_log.h" +#include "cfe_es_task.h" #include "cfe_psp.h" #include #include #include +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* - * Confirm the size of the error log context buffer is at least what the user asked for. - * - * This is to catch errors such as if the CFE_PLATFORM_ES_ER_LOG_MAX_CONTEXT_SIZE was set to a value - * that is _not_ a multiple of sizeof(uint32) -- in this case the final size of the context - * buffer would end up being less than what the macro was set to. - */ -CompileTimeAssert(sizeof(CFE_ES_ResetDataPtr->ERLog[0].Context) == CFE_PLATFORM_ES_ER_LOG_MAX_CONTEXT_SIZE, CfeEsErLogContextSizeError); - - -/* -** Function: CFE_ES_WriteToERLog +** Function: CFE_ES_WriteToERLogWithContext ** ** Purpose: Create an entry in the ES Exception and Reset Log. +** This log API accepts extra context information (AppID and ContextID) +** and is used when the app/task invoking this API is not the same app +** as where the event occurred. ** */ -int32 CFE_ES_WriteToERLog( uint32 EntryType, uint32 ResetType, uint32 ResetSubtype, - const char *Description, const uint32 *Context, uint32 ContextSize ) +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +int32 CFE_ES_WriteToERLogWithContext( CFE_ES_LogEntryType_Enum_t EntryType, uint32 ResetType, uint32 ResetSubtype, + const char *Description, uint32 AppId, uint32 PspContextId) { uint32 LogIdx; + CFE_ES_ERLog_MetaData_t *EntryPtr; + CFE_TIME_SysTime_t PendingTime; /* - ** Code - */ + * Snapshot the time before locking (different subsystem) + */ + PendingTime = CFE_TIME_GetTime(); + + /* + * Ensure that description string is not NULL. + */ + if ( Description == NULL) + { + Description = "No Description String Given."; + } + + /* + * This routine needs to lock in case it is called + * from concurrent threads + */ + CFE_ES_LockSharedData(__func__,__LINE__); /* ** Try to clean up an invalid ER log index variable. @@ -96,89 +109,342 @@ int32 CFE_ES_WriteToERLog( uint32 EntryType, uint32 ResetType, uint32 ResetSu /* ** Clear out the log entry we are about to use. */ - memset( &(CFE_ES_ResetDataPtr->ERLog[LogIdx]), 0, - sizeof (CFE_ES_ERLog_t)); + EntryPtr = &CFE_ES_ResetDataPtr->ERLog[LogIdx]; + memset(EntryPtr, 0, sizeof (*EntryPtr)); /* ** Fill out the log fields */ - CFE_ES_ResetDataPtr->ERLog[LogIdx].LogEntryType = EntryType; - CFE_ES_ResetDataPtr->ERLog[LogIdx].ResetType = ResetType; - CFE_ES_ResetDataPtr->ERLog[LogIdx].ResetSubtype = ResetSubtype; - CFE_ES_ResetDataPtr->ERLog[LogIdx].BootSource = CFE_ES_ResetDataPtr->ResetVars.BootSource; - CFE_ES_ResetDataPtr->ERLog[LogIdx].ProcessorResetCount = + EntryPtr->BaseInfo.LogEntryType = EntryType; + EntryPtr->BaseInfo.ResetType = ResetType; + EntryPtr->BaseInfo.ResetSubtype = ResetSubtype; + EntryPtr->BaseInfo.BootSource = CFE_ES_ResetDataPtr->ResetVars.BootSource; + EntryPtr->BaseInfo.ProcessorResetCount = CFE_ES_ResetDataPtr->ResetVars.ProcessorResetCount; - CFE_ES_ResetDataPtr->ERLog[LogIdx].MaxProcessorResetCount = + EntryPtr->BaseInfo.MaxProcessorResetCount = CFE_ES_ResetDataPtr->ResetVars.MaxProcessorResetCount; /* ** Copy the ES Reset variables to the log (before they are modified by the log entry). */ - memcpy(&(CFE_ES_ResetDataPtr->ERLog[LogIdx].DebugVars), - (void *)&(CFE_ES_Global.DebugVars), - sizeof(CFE_ES_DebugVariables_t )); + memcpy(&EntryPtr->BaseInfo.DebugVars, &CFE_ES_Global.DebugVars, + sizeof(EntryPtr->BaseInfo.DebugVars)); /* - ** Time Stamp the log entry with the system time + ** Time Stamp the log entry with the system time */ - CFE_ES_ResetDataPtr->ERLog[LogIdx].TimeCode = CFE_TIME_GetTime(); + EntryPtr->BaseInfo.TimeCode = PendingTime; /* ** Copy the Description string to the log. */ - if ( Description == NULL) - { - strncpy(CFE_ES_ResetDataPtr->ERLog[LogIdx].Description, "No Description String Given.", 80); - } - else - { - strncpy(CFE_ES_ResetDataPtr->ERLog[LogIdx].Description, Description, 80); - } + strncpy(EntryPtr->BaseInfo.Description, Description, sizeof(EntryPtr->BaseInfo.Description)); /* - ** In the case of an exception, copy the processor context data to the log. - */ - if (Context != NULL && ContextSize > 0) - { - /* - ** Copy the processor context data (i.e. register dump). Make sure that - ** the passed-in context_size is not greater than the declared size in - ** the ER Log log entry. - */ - if ( ContextSize <= CFE_PLATFORM_ES_ER_LOG_MAX_CONTEXT_SIZE ) - { - memcpy ( (CFE_ES_ResetDataPtr->ERLog[LogIdx].Context), - (void *)Context, - ContextSize); - } - else - { - memcpy ( (CFE_ES_ResetDataPtr->ERLog[LogIdx].Context), - (void *)Context, - CFE_PLATFORM_ES_ER_LOG_MAX_CONTEXT_SIZE); - } - /* - ** Indicate that context is valid. - ** Using the original context size (not the truncated size) so it will be - ** evident if the context information was truncated. - */ - CFE_ES_ResetDataPtr->ERLog[LogIdx].ContextSize = ContextSize; - } - else - { - /* - ** Context is not valid - */ - CFE_ES_ResetDataPtr->ERLog[LogIdx].ContextSize = 0; - } /* end if */ + * Store the context info (if any) + */ + EntryPtr->AppID = AppId; + EntryPtr->PspContextId = PspContextId; /* ** Increment the number of ER log entries made */ CFE_ES_ResetDataPtr->ERLogEntries++; + /* + * Shared data update is complete + */ + CFE_ES_UnlockSharedData(__func__,__LINE__); + return(CFE_SUCCESS); + +} /* End of CFE_ES_WriteToERLogWithContext() */ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* +** Function: CFE_ES_WriteToERLog +** +** Purpose: Create an entry in the ES Exception and Reset Log. +** This log API is simplified for cases which do not have a separate context +** +*/ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +int32 CFE_ES_WriteToERLog( CFE_ES_LogEntryType_Enum_t EntryType, uint32 ResetType, uint32 ResetSubtype, + const char *Description) +{ + /* passing 0xFFFFFFFF as the appid avoids confusion with actual appid 0 */ + return CFE_ES_WriteToERLogWithContext(EntryType, ResetType, ResetSubtype, + Description, 0xFFFFFFFF, CFE_ES_ERLOG_NO_CONTEXT); } /* End of CFE_ES_WriteToERLog() */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* Function: CFE_ES_RunERLogDump() */ +/* */ +/* Purpose: */ +/* Write exception & reset log to a file. */ +/* */ +/* Implemented as an ES background job, but the entire file write is done */ +/* in a single invocation, as the file is expected to be relatively small. */ +/* */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +bool CFE_ES_RunERLogDump(uint32 ElapsedTime, void *Arg) +{ + CFE_ES_BackgroundLogDumpGlobal_t *State = (CFE_ES_BackgroundLogDumpGlobal_t *)Arg; + int32 WriteStat; + int32 PspStatus; + CFE_FS_Header_t FileHdr; + CFE_ES_ERLog_FileEntry_t FileEntry; + CFE_ES_ERLog_MetaData_t *EntryPtr; + uint32 FileSize; + uint32 i; + int32 fd; + + + if (!State->IsPending) + { + return false; + } + + FileSize = 0; + fd = OS_creat(State->DataFileName, OS_WRITE_ONLY); + if(fd < 0) + { + CFE_EVS_SendEvent(CFE_ES_ERLOG2_ERR_EID,CFE_EVS_EventType_ERROR, + "Error creating file %s, RC = 0x%08X", + State->DataFileName, (unsigned int)fd); + } + else + { + CFE_FS_InitHeader(&FileHdr, CFE_ES_ER_LOG_DESC, CFE_FS_SubType_ES_ERLOG); + + /* write the cFE header to the file */ + WriteStat = CFE_FS_WriteHeader(fd, &FileHdr); + if(WriteStat != sizeof(CFE_FS_Header_t)) + { + CFE_ES_FileWriteByteCntErr(State->DataFileName,sizeof(CFE_FS_Header_t),WriteStat); + } + else + { + FileSize += WriteStat; + + /* write a single ER log entry on each pass */ + for(i=0;iERLog[i]; + + /* The basic info comes directly from the ES log */ + FileEntry.BaseInfo = EntryPtr->BaseInfo; + + /* + * The context info, if available, comes from the PSP. + * This returns the actual size of the context info, or <0 on error. + */ + PspStatus = CFE_PSP_Exception_CopyContext(EntryPtr->PspContextId, &FileEntry.Context, sizeof(FileEntry.Context)); + if (PspStatus > 0) + { + FileEntry.ContextSize = PspStatus; + } + else + { + /* + * errors here are OK - just means there is no context available. + * Record a size of 0 in the log file. + */ + FileEntry.ContextSize = 0; + } + + /* + * any unused context space should be cleared. + * + * This is for binary compatibility with historical log files, where a fixed amount + * of space is given per-entry, regardless of the actual size. + */ + if (FileEntry.ContextSize < sizeof(FileEntry.Context)) + { + memset(&FileEntry.Context[FileEntry.ContextSize], 0, + sizeof(FileEntry.Context) - FileEntry.ContextSize); + } + + /* + * Now write to file + */ + WriteStat = OS_write(fd,&FileEntry,sizeof(FileEntry)); + + if(WriteStat != sizeof(FileEntry)) + { + CFE_ES_FileWriteByteCntErr(State->DataFileName,sizeof(FileEntry),WriteStat); + break; + }/* end if */ + + FileSize += WriteStat; + + } /* end for */ + + } /* end if */ + + OS_close(fd); + + CFE_EVS_SendEvent(CFE_ES_ERLOG2_EID, CFE_EVS_EventType_DEBUG, + "%s written:Size=%lu",State->DataFileName,(unsigned long)FileSize); + + } /* end if */ + + /* + * Always clear the "pending" flag whether successful or not. + * If unsuccessful, an operator needs to investigate the error and re-issue command. + */ + State->IsPending = false; + + return false; +}/* end CFE_ES_RunERLogDump */ + + +/* +**--------------------------------------------------------------------------------------- +** Name: CFE_ES_RunExceptionScan +** +** Purpose: This function pools the PSP to check if any exceptions have been logged +** since the last background cycle. If an exception is present, retreive +** the details, add it to the ER log, and trigger the action (e.g. app restart). +**--------------------------------------------------------------------------------------- +*/ +bool CFE_ES_RunExceptionScan(uint32 ElapsedTime, void *Arg) +{ + int32 Status; + uint32 PspContextId; + char ReasonString[CFE_ES_ERLOG_DESCRIPTION_MAX_LENGTH]; + CFE_ES_TaskInfo_t EsTaskInfo; + uint32 ExceptionTaskID; + uint32 ResetType; + CFE_ES_LogEntryType_Enum_t LogType; + + if (CFE_PSP_Exception_GetCount() == 0) + { + /* no exceptions pending, nothing to do */ + return false; + } + + /* + * Note a reset type of 0 is not defined by the PSP - + * the real values are all nonzero + */ + ResetType = 0; + memset(&EsTaskInfo, 0, sizeof(EsTaskInfo)); + Status = CFE_PSP_Exception_GetSummary(&PspContextId, &ExceptionTaskID, ReasonString, sizeof(ReasonString)); + if (Status != CFE_PSP_SUCCESS) + { + /* reason string is not available - populate with something for the log */ + snprintf(ReasonString, sizeof(ReasonString), "Unknown - CFE_PSP_ExceptionGetSummary() error %ld", (long)Status); + PspContextId = 0; + ExceptionTaskID = 0; + } /* end if */ + + /* + * Note that writes to the ES ER log actually do not get propagated to the debug console. + * so by writing to SysLog here it becomes visible in both places. + */ + CFE_ES_WriteToSysLog("ExceptionID 0x%lx in TaskID %lu: %s\n", + (unsigned long)PspContextId, (unsigned long)ExceptionTaskID, ReasonString); + + /* + * If task ID is 0, this means it was a system level exception and + * not associated with a specific task. + * + * Otherwise, if it was related to a task, determine the associated AppID + * so the exception action can be checked. + */ + if (ExceptionTaskID != 0) + { + Status = CFE_ES_GetTaskInfo( &EsTaskInfo, ExceptionTaskID ); + + /* + * The App ID was found, now see if the ExceptionAction is set for a reset + */ + if (Status == CFE_SUCCESS && + CFE_ES_Global.AppTable[EsTaskInfo.AppId].StartParams.ExceptionAction == CFE_ES_ExceptionAction_RESTART_APP) + { + /* + * Log the Application reset + */ + ResetType = CFE_ES_APP_RESTART; + } + } + + do + { + /* + * If no disposition is identified yet, then trigger a PSP reset. + * Need to determine if a processor or poweron reset is needed. + */ + if (ResetType == 0) + { + if ( CFE_ES_ResetDataPtr->ResetVars.ProcessorResetCount >= + CFE_ES_ResetDataPtr->ResetVars.MaxProcessorResetCount ) + { + CFE_ES_WriteToSysLog("Maximum Processor Reset count reached (%u)", + (unsigned int)CFE_ES_ResetDataPtr->ResetVars.MaxProcessorResetCount); + + ResetType = CFE_PSP_RST_TYPE_POWERON; + } + else + { + CFE_ES_WriteToSysLog("Processor Reset count not reached (%u/%u)", + (unsigned int)CFE_ES_ResetDataPtr->ResetVars.ProcessorResetCount, + (unsigned int)CFE_ES_ResetDataPtr->ResetVars.MaxProcessorResetCount); + + + /* + ** Update the reset variables + */ + CFE_ES_ResetDataPtr->ResetVars.ProcessorResetCount++; + CFE_ES_ResetDataPtr->ResetVars.ES_CausedReset = true; + + ResetType = CFE_PSP_RST_TYPE_PROCESSOR; + } + } + + if (ResetType == CFE_ES_APP_RESTART) + { + LogType = CFE_ES_LogEntryType_APPLICATION; + } + else + { + LogType = CFE_ES_LogEntryType_CORE; + } + + + CFE_ES_WriteToERLogWithContext(LogType, ResetType, + CFE_PSP_RST_SUBTYPE_EXCEPTION, ReasonString, + EsTaskInfo.AppId, + PspContextId); + + if (ResetType == CFE_ES_APP_RESTART) + { + /* + * Restart the App. This call is just a request + * to ES, but the request could fail. If that happens, + * proceed to a processor reset. + */ + Status = CFE_ES_RestartApp(EsTaskInfo.AppId); + if (Status != CFE_SUCCESS) + { + ResetType = 0; + snprintf(ReasonString, sizeof(ReasonString), "App Restart Failed"); + } + } + else + { + /* normally this will not return */ + CFE_PSP_Restart(ResetType); + } + } + while(ResetType == 0); + + + return true; /* returning true because there was an exception to deal with */ +} + + + /* end of file */ diff --git a/fsw/cfe-core/src/es/cfe_es_log.h b/fsw/cfe-core/src/es/cfe_es_log.h index c595be3e7..f02bc902a 100644 --- a/fsw/cfe-core/src/es/cfe_es_log.h +++ b/fsw/cfe-core/src/es/cfe_es_log.h @@ -108,6 +108,14 @@ } +/** + * \brief Indicates no context information Error Logs + * + * For use with the CFE_ES_WriteToERLog() function when no context + * information is available. + */ +#define CFE_ES_ERLOG_NO_CONTEXT (0) + /* ** Type Definitions */ @@ -328,8 +336,35 @@ void CFE_ES_PerfLogDump(void); /* ** Exception and Reset Log API */ -int32 CFE_ES_WriteToERLog( uint32 EntryType, uint32 ResetType, uint32 ResetSubtype, - const char *Description, const uint32 *Context, uint32 ContextSize ); -int32 CFE_ES_ERLogDump(const char *Filename); + +/** + * \brief Create an entry in the ES Exception and Reset Log. + * + * The exception and reset log is used to track significant system-level events and anomalies + * for later analysis. + * + * \param EntryType Whether the event is relevant to the CORE or an APPLICATION (#CFE_ES_LogEntryType_Enum_t) + * \param ResetType The type of the last reset + * \param ResetSubType The subtype of the last reset + * \param Description A summary of the event + * + * \return CFE_SUCCESS if successful, or an appropriate error code from cfe_error.h + */ +int32 CFE_ES_WriteToERLog( CFE_ES_LogEntryType_Enum_t EntryType, uint32 ResetType, uint32 ResetSubtype, + const char *Description); + + +/** + * \copydoc CFE_ES_WriteToERLog() + * + * This log API accepts extra context information (AppID and ContextID) + * and is used when the app/task invoking this API is not the same app + * as where the event occurred. + * + * \param AppId The Application ID associated with the task that caused the exception + * \param PspContextId Identifier of extended context info stored in the PSP (if available) + */ +int32 CFE_ES_WriteToERLogWithContext( CFE_ES_LogEntryType_Enum_t EntryType, uint32 ResetType, uint32 ResetSubtype, + const char *Description, uint32 AppId, uint32 PspContextId); #endif /* _cfe_es_log_ */ diff --git a/fsw/cfe-core/src/es/cfe_es_start.c b/fsw/cfe-core/src/es/cfe_es_start.c index e1ccc24a9..5d73fc64c 100644 --- a/fsw/cfe-core/src/es/cfe_es_start.c +++ b/fsw/cfe-core/src/es/cfe_es_start.c @@ -91,20 +91,6 @@ void CFE_ES_Main(uint32 StartType, uint32 StartSubtype, uint32 ModeId, const cha */ CFE_ES_Global.SystemState = CFE_ES_SystemState_EARLY_INIT; - /* - ** Initialize the Reset variables. This call is required - ** Before most of the ES functions can be used including the - ** ES System log. - */ - CFE_ES_SetupResetVariables(StartType, StartSubtype, ModeId); - - /* - ** Initialize the Logic Perf variables - ** Because this is in the ES Reset area, it must be called after - ** CFE_ES_SetupResetVariables. - */ - CFE_ES_SetupPerfVariables(StartType); - /* ** Create the ES Shared Data Mutex ** This must be done before ANY calls to CFE_ES_WriteToSysLog(), since this uses the mutex @@ -131,6 +117,20 @@ void CFE_ES_Main(uint32 StartType, uint32 StartSubtype, uint32 ModeId, const cha return; } /* end if */ + /* + ** Initialize the Reset variables. This call is required + ** Before most of the ES functions can be used including the + ** ES System log. + */ + CFE_ES_SetupResetVariables(StartType, StartSubtype, ModeId); + + /* + ** Initialize the Logic Perf variables + ** Because this is in the ES Reset area, it must be called after + ** CFE_ES_SetupResetVariables. + */ + CFE_ES_SetupPerfVariables(StartType); + /* ** Also Create the ES Performance Data Mutex ** This is to separately protect against concurrent writes to the global performance log data @@ -366,19 +366,19 @@ void CFE_ES_SetupResetVariables(uint32 StartType, uint32 StartSubtype, uint32 Bo { CFE_ES_SysLogWrite_Unsync("POWER ON RESET due to Power Cycle (Power Cycle).\n"); CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_POWERON, StartSubtype, - "POWER ON RESET due to Power Cycle (Power Cycle)", NULL,0 ); + "POWER ON RESET due to Power Cycle (Power Cycle)"); } else if ( StartSubtype == CFE_PSP_RST_SUBTYPE_HW_SPECIAL_COMMAND ) { CFE_ES_SysLogWrite_Unsync("POWER ON RESET due to HW Special Cmd (Hw Spec Cmd).\n"); CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_POWERON, StartSubtype, - "POWER ON RESET due to HW Special Cmd (Hw Spec Cmd)", NULL,0 ); + "POWER ON RESET due to HW Special Cmd (Hw Spec Cmd)"); } else { CFE_ES_SysLogWrite_Unsync("POWER ON RESET due to other cause (See Subtype).\n"); CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_POWERON, StartSubtype, - "POWER ON RESET due to other cause (See Subtype)", NULL,0 ); + "POWER ON RESET due to other cause (See Subtype)"); } /* @@ -418,7 +418,7 @@ void CFE_ES_SetupResetVariables(uint32 StartType, uint32 StartSubtype, uint32 Bo ** the entry just in case something fails. */ CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_POWERON, StartSubtype, - "POWER ON RESET due to max proc resets (HW Spec Cmd).", NULL,0 ); + "POWER ON RESET due to max proc resets (HW Spec Cmd)."); } else { @@ -430,7 +430,7 @@ void CFE_ES_SetupResetVariables(uint32 StartType, uint32 StartSubtype, uint32 Bo ** the entry just in case something fails. */ CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_POWERON, StartSubtype, - "POWER ON RESET due to max proc resets (Watchdog).", NULL,0 ); + "POWER ON RESET due to max proc resets (Watchdog)."); } /* ** Call the BSP reset routine @@ -454,7 +454,7 @@ void CFE_ES_SetupResetVariables(uint32 StartType, uint32 StartSubtype, uint32 Bo ** Log the watchdog reset */ CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_PROCESSOR, StartSubtype, - "PROCESSOR RESET due to Hardware Special Command (Hw Spec Cmd).", NULL,0 ); + "PROCESSOR RESET due to Hardware Special Command (Hw Spec Cmd)."); } else @@ -466,7 +466,7 @@ void CFE_ES_SetupResetVariables(uint32 StartType, uint32 StartSubtype, uint32 Bo ** Log the watchdog reset */ CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_PROCESSOR, StartSubtype, - "PROCESSOR RESET due to Watchdog (Watchdog).", NULL,0 ); + "PROCESSOR RESET due to Watchdog (Watchdog)."); } diff --git a/fsw/cfe-core/src/es/cfe_es_task.c b/fsw/cfe-core/src/es/cfe_es_task.c index 2f750536e..303ccfb2c 100644 --- a/fsw/cfe-core/src/es/cfe_es_task.c +++ b/fsw/cfe-core/src/es/cfe_es_task.c @@ -1589,94 +1589,30 @@ int32 CFE_ES_ClearERLogCmd(const CFE_ES_ClearERLog_t *data) int32 CFE_ES_WriteERLogCmd(const CFE_ES_WriteERLog_t *data) { const CFE_ES_FileNameCmd_Payload_t *CmdPtr = &data->Payload; - int32 Stat; - char LogFilename[OS_MAX_PATH_LEN]; - CFE_SB_MessageStringGet(LogFilename, (char *)CmdPtr->FileName, - CFE_PLATFORM_ES_DEFAULT_ER_LOG_FILE, OS_MAX_PATH_LEN, sizeof(CmdPtr->FileName)); - - Stat = CFE_ES_ERLogDump(LogFilename); - - if(Stat == CFE_SUCCESS) + if (CFE_ES_TaskData.BackgroundERLogDumpState.IsPending) { - CFE_ES_TaskData.CommandCounter++; + CFE_EVS_SendEvent(CFE_ES_ERLOG_PENDING_ERR_EID,CFE_EVS_EventType_ERROR, + "Error log write to file %s already in progress", + CFE_ES_TaskData.BackgroundERLogDumpState.DataFileName); + + /* background dump already running, consider this an error */ + CFE_ES_TaskData.CommandErrorCounter++; } else { - CFE_ES_TaskData.CommandErrorCounter++; - }/* end if */ - - return CFE_SUCCESS; -}/* end CFE_ES_WriteERLogCmd */ - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* */ -/* CFE_ES_ERLogDump() -- Write exception & reset log to a file. */ -/* */ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -int32 CFE_ES_ERLogDump(const char *Filename) -{ - - int32 fd; - int32 WriteStat,BspStat; - uint32 FileSize,i,ResetAreaSize; - CFE_FS_Header_t FileHdr; - cpuaddr ResetDataAddr; - - fd = OS_creat(Filename, OS_WRITE_ONLY); - if(fd < 0) - { - CFE_EVS_SendEvent(CFE_ES_ERLOG2_ERR_EID,CFE_EVS_EventType_ERROR, - "Error creating file %s, RC = 0x%08X", - Filename,(unsigned int)fd); - return CFE_ES_FILE_IO_ERR; - }/* end if */ - - CFE_FS_InitHeader(&FileHdr, CFE_ES_ER_LOG_DESC, CFE_FS_SubType_ES_ERLOG); - - /* write the cFE header to the file */ - WriteStat = CFE_FS_WriteHeader(fd, &FileHdr); - if(WriteStat != sizeof(CFE_FS_Header_t)) - { - CFE_ES_FileWriteByteCntErr(Filename,sizeof(CFE_FS_Header_t),WriteStat); - OS_close(fd); - return CFE_ES_FILE_IO_ERR; - }/* end if */ - FileSize = WriteStat; + CFE_SB_MessageStringGet(CFE_ES_TaskData.BackgroundERLogDumpState.DataFileName, (char *)CmdPtr->FileName, + CFE_PLATFORM_ES_DEFAULT_ER_LOG_FILE, + sizeof(CFE_ES_TaskData.BackgroundERLogDumpState.DataFileName), sizeof(CmdPtr->FileName)); - /* Get the pointer to the Reset Log from the BSP */ - BspStat = CFE_PSP_GetResetArea (&ResetDataAddr, &ResetAreaSize); - if(BspStat != CFE_PSP_SUCCESS) - { - CFE_EVS_SendEvent(CFE_ES_RST_ACCESS_EID, CFE_EVS_EventType_ERROR, - "Error accessing ER Log,%s not written. RC = 0x%08X",Filename,(unsigned int)BspStat); - OS_close(fd); - return CFE_ES_RST_ACCESS_ERR; - }/* end if */ - - /* write a single ER log entry on each pass */ - for(i=0;i UINT32_MAX - #error CFE_PLATFORM_ES_RESET_AREA_SIZE cannot be greater than UINT32_MAX (4 Gigabytes)! -#endif - /* ** The size of a command to the OS that lies under the cFE */ diff --git a/fsw/cfe-core/src/inc/cfe_es.h b/fsw/cfe-core/src/inc/cfe_es.h index 4f81babbd..b52d0cbe9 100644 --- a/fsw/cfe-core/src/inc/cfe_es.h +++ b/fsw/cfe-core/src/inc/cfe_es.h @@ -979,22 +979,21 @@ uint32 CFE_ES_CalculateCRC(const void *DataPtr, uint32 DataLength, uint32 InputC /*****************************************************************************/ /** ** \ingroup CFEAPIESMisc -** \brief Process an exception detected by the underlying OS/PSP +** \brief Notification that an asynchronous event was detected by the underlying OS/PSP ** ** \par Description -** This hook routine is called from the PSP when an exception occurs +** This hook routine is called from the PSP when an exception or +** other asynchronous system event occurs ** ** \par Assumptions, External Events, and Notes: -** None. +** The PSP must guarantee that this function is only invoked from a +** context which may use OSAL primitives. In general this means that +** it shouldn't be _directly_ invoked from an ISR/signal context. ** -** \param[in] HostTaskId The OS (not OSAL) task ID -** \param[in] ReasonString Identifier from PSP -** \param[in] ContextPointer Context data from PSP -** \param[in] ContextSize Size of context data from PSP ** ******************************************************************************/ -void CFE_ES_ProcessCoreException(uint32 HostTaskId, const char *ReasonString, - const uint32 *ContextPointer, uint32 ContextSize); +void CFE_ES_ProcessAsyncEvent(void); + /**@}*/ /** @defgroup CFEAPIESCritData cFE Critical Data Store APIs diff --git a/fsw/cfe-core/src/inc/cfe_es_events.h b/fsw/cfe-core/src/inc/cfe_es_events.h index 78464a871..03da2eb37 100644 --- a/fsw/cfe-core/src/inc/cfe_es_events.h +++ b/fsw/cfe-core/src/inc/cfe_es_events.h @@ -1214,21 +1214,6 @@ **/ #define CFE_ES_FILEWRITE_ERR_EID 74 -/** \brief 'Error accessing ER Log,\%s not written.Stat=0x\%08x' -** \event 'Error accessing ER Log,\%s not written.Stat=0x\%08x' -** -** \par Type: ERROR -** -** \par Cause: -** -** This event message is generated in response to an Exception Reset Log Dump command and there is -** an error obtaining the contents of the ER Log. -** -** The \c 's' field identifies the filename of the file to which the data failed to write, -** the \c Stat field specifies, in hex, the error status returned from #CFE_PSP_GetResetArea. -**/ -#define CFE_ES_RST_ACCESS_EID 75 - /** \brief 'Error while deleting '\%s' from CDS, See SysLog.(Err=0x\%08X)' ** \event 'Error while deleting '\%s' from CDS, See SysLog.(Err=0x\%08X)' ** @@ -1518,6 +1503,19 @@ #define CFE_ES_BUILD_INF_EID 92 +/** \brief 'Error log write to file \%s already in progress' +** \event 'Error log write to file \%s already in progress' +** +** \par Type: ERROR +** +** \par Cause: +** +** This event message is generated when an Executive Services \link #CFE_ES_WRITE_ER_LOG_CC Dump Exception Reset Log +** Command \endlink is received before a previously-issued command has finished executing +** +**/ +#define CFE_ES_ERLOG_PENDING_ERR_EID 93 + #endif /* _cfe_es_events_ */ diff --git a/fsw/cfe-core/src/inc/cfe_evs_msg.h b/fsw/cfe-core/src/inc/cfe_evs_msg.h index 477b6caa8..a6fe29872 100644 --- a/fsw/cfe-core/src/inc/cfe_evs_msg.h +++ b/fsw/cfe-core/src/inc/cfe_evs_msg.h @@ -37,6 +37,7 @@ /********************************** Include Files ************************************/ #include "common_types.h" /* Basic data types */ +#include "cfe_evs_extern_typedefs.h" /* for EVS-specific types such as CFE_EVS_LogMode_Enum_t */ #include "cfe_time.h" /* Time library function definitions */ #include "cfe_sb.h" #include "cfe_es.h" diff --git a/fsw/cfe-core/src/inc/private/cfe_es_erlog_typedef.h b/fsw/cfe-core/src/inc/private/cfe_es_erlog_typedef.h index d10f9c8ec..b93fba5d4 100644 --- a/fsw/cfe-core/src/inc/private/cfe_es_erlog_typedef.h +++ b/fsw/cfe-core/src/inc/private/cfe_es_erlog_typedef.h @@ -34,6 +34,8 @@ #include #include /* Needed for CFE_TIME_SysTime_t */ +#define CFE_ES_ERLOG_DESCRIPTION_MAX_LENGTH 80 + /* ** Debug variables type */ @@ -47,7 +49,9 @@ typedef struct } CFE_ES_DebugVariables_t; /* -** Exception and Reset Log Structure +** Exception and Reset Log Base Structure +** +** This is the common data structure that is stored in RAM and log files */ typedef struct { @@ -59,11 +63,42 @@ typedef struct uint32 MaxProcessorResetCount; /* The maximum number before a Power On */ CFE_ES_DebugVariables_t DebugVars; /* ES Debug variables */ CFE_TIME_SysTime_t TimeCode; /* Time code */ - char Description[80]; /* The ascii data for the event */ - uint32 ContextSize; /* Indicates the context data is valid */ - uint32 AppID; /* The application ID */ - uint32 Context[CFE_PLATFORM_ES_ER_LOG_MAX_CONTEXT_SIZE / sizeof(uint32)]; /* cpu context */ -} CFE_ES_ERLog_t; + char Description[CFE_ES_ERLOG_DESCRIPTION_MAX_LENGTH]; /* The ascii data for the event */ +} CFE_ES_ERLog_BaseInfo_t; + + +/* +** Exception and Reset Log File Structure +** +** This is the "export" data structure that gets written to a log file +** It is intended to be binary-compatible with the historical definition of this +** structure, to work with existing tools that may read log files. +** +** Note that "AppID" really belongs in the base info, but it is kept here +** for backward compatibility. +*/ +typedef struct +{ + CFE_ES_ERLog_BaseInfo_t BaseInfo; /* basic info about the event */ + uint32 ContextSize; /* Indicates the context data is valid */ + uint32 AppID; /* The application ID */ + uint8 Context[CFE_PLATFORM_ES_ER_LOG_MAX_CONTEXT_SIZE]; /* cpu context */ +} CFE_ES_ERLog_FileEntry_t; + + +/* +** Exception and Reset Log Metadata Structure +** This is stored in ES RAM, not _directly_ written to ER log files. +*/ +typedef struct +{ + CFE_ES_ERLog_BaseInfo_t BaseInfo; /**< Core Log Data */ + uint32 AppID; /* The application ID */ + uint32 PspContextId; /**< Reference to context information stored in PSP */ +} CFE_ES_ERLog_MetaData_t; + + + diff --git a/fsw/cfe-core/src/inc/private/cfe_es_resetdata_typedef.h b/fsw/cfe-core/src/inc/private/cfe_es_resetdata_typedef.h index 872dcf3bb..aec73b459 100644 --- a/fsw/cfe-core/src/inc/private/cfe_es_resetdata_typedef.h +++ b/fsw/cfe-core/src/inc/private/cfe_es_resetdata_typedef.h @@ -63,7 +63,7 @@ typedef struct /* ** Exception and Reset log declaration */ - CFE_ES_ERLog_t ERLog[CFE_PLATFORM_ES_ER_LOG_ENTRIES]; + CFE_ES_ERLog_MetaData_t ERLog[CFE_PLATFORM_ES_ER_LOG_ENTRIES]; uint32 ERLogIndex; uint32 ERLogEntries; uint32 LastAppId; diff --git a/fsw/cfe-core/unit-test/es_UT.c b/fsw/cfe-core/unit-test/es_UT.c index e0a7a7ab3..125415600 100644 --- a/fsw/cfe-core/unit-test/es_UT.c +++ b/fsw/cfe-core/unit-test/es_UT.c @@ -2186,8 +2186,6 @@ void TestApps(void) void TestERLog(void) { int Return; - uint32 Context = 4; - char Context2[1000]; #ifdef UT_VERBOSE UT_Text("Begin Test Exception and Reset Log\n"); @@ -2199,65 +2197,18 @@ void TestERLog(void) */ ES_ResetUnitTest(); CFE_ES_ResetDataPtr->ERLogIndex = CFE_PLATFORM_ES_ER_LOG_ENTRIES + 1; - CFE_ES_ResetDataPtr->ERLog[0].ContextSize = 0; Return = CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_POWERON, 1, - NULL, - &Context, - sizeof(int)); + NULL); UT_Report(__FILE__, __LINE__, Return == CFE_SUCCESS && - !strcmp(CFE_ES_ResetDataPtr->ERLog[0].Description, + !strcmp(CFE_ES_ResetDataPtr->ERLog[0].BaseInfo.Description, "No Description String Given.") && - CFE_ES_ResetDataPtr->ERLogIndex == 1 && - CFE_ES_ResetDataPtr->ERLog[0].ContextSize == sizeof(int), + CFE_ES_ResetDataPtr->ERLogIndex == 1, "CFE_ES_WriteToERLog", "Log entries exceeded; no description; valid context size"); - /* Test initial rolling over log entry, - * null description, - * and non-null context with zero size - */ - ES_ResetUnitTest(); - CFE_ES_ResetDataPtr->ERLogIndex = 0; - CFE_ES_ResetDataPtr->ERLog[0].ContextSize = 0; - Return = CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, - CFE_PSP_RST_TYPE_POWERON, - 1, - NULL, - &Context, - 0); - UT_Report(__FILE__, __LINE__, - Return == CFE_SUCCESS && - CFE_ES_ResetDataPtr->ERLogIndex == 1 && - CFE_ES_ResetDataPtr->ERLog[0].ContextSize == 0, - "CFE_ES_WriteToERLog", - "Log entries exceeded; no description; invalid context size"); - - /* Test rolling over log entry at end, - * non-null description, - * and non-null context with large size - */ - ES_ResetUnitTest(); - CFE_ES_ResetDataPtr->ERLogIndex = CFE_PLATFORM_ES_ER_LOG_ENTRIES - 1; - CFE_ES_ResetDataPtr->ERLog[CFE_PLATFORM_ES_ER_LOG_ENTRIES - 1].ContextSize = 0; - Return = CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, - CFE_PSP_RST_TYPE_POWERON, - 1, - "LogDescription", - (uint32 *) &Context2, - 9999999); - UT_Report(__FILE__, __LINE__, - Return == CFE_SUCCESS && - !strcmp(CFE_ES_ResetDataPtr->ERLog[ - CFE_PLATFORM_ES_ER_LOG_ENTRIES - 1].Description, - "LogDescription") && - CFE_ES_ResetDataPtr->ERLogIndex == 0 && - CFE_ES_ResetDataPtr->ERLog[ - CFE_PLATFORM_ES_ER_LOG_ENTRIES - 1].ContextSize == 9999999, - "CFE_ES_WriteToERLog", - "Log entries at maximum; description; oversized context"); /* Test non-rolling over log entry, * null description, @@ -2265,17 +2216,13 @@ void TestERLog(void) */ ES_ResetUnitTest(); CFE_ES_ResetDataPtr->ERLogIndex = 0; - CFE_ES_ResetDataPtr->ERLog[0].ContextSize = 0; Return = CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_POWERON, 1, - NULL, - NULL, - 1); + NULL); UT_Report(__FILE__, __LINE__, Return == CFE_SUCCESS && - CFE_ES_ResetDataPtr->ERLogIndex == 1 && - CFE_ES_ResetDataPtr->ERLog[0].ContextSize == 0, + CFE_ES_ResetDataPtr->ERLogIndex == 1, "CFE_ES_WriteToERLog", "No log entry rollover; no description; no context"); } @@ -2460,6 +2407,7 @@ void TestTask(void) uint32 Id; uint32 TestObjId; uint32 ResetType; + uint32 UT_ContextBuffer; union { CFE_SB_Msg_t Msg; @@ -3264,64 +3212,157 @@ void TestTask(void) "Clear E&R log"); /* Test successful writing of the E&R log */ + /* In the current implementation, it does not directly write the file, + * this just sets a flag for the background task */ ES_ResetUnitTest(); memset(&CmdBuf, 0, sizeof(CmdBuf)); strncpy(CmdBuf.WriteERlogCmd.Payload.FileName, "filename", sizeof(CmdBuf.WriteERlogCmd.Payload.FileName)); + CFE_ES_TaskData.BackgroundERLogDumpState.IsPending = false; + UT_CallTaskPipe(CFE_ES_TaskPipe, &CmdBuf.Msg, sizeof(CFE_ES_WriteERLog_t), + UT_TPID_CFE_ES_CMD_WRITE_ER_LOG_CC); + UT_Report(__FILE__, __LINE__, + CFE_ES_TaskData.BackgroundERLogDumpState.IsPending, + "CFE_ES_WriteERLogCmd", + "Write E&R log command; pending"); + UT_Report(__FILE__, __LINE__, + !UT_EventIsInHistory(CFE_ES_ERLOG_PENDING_ERR_EID), + "CFE_ES_WriteERLogCmd", + "Write E&R log command; no events"); + + /* sending the same command a second time should fail with an event + * indicating a file write is already pending. */ UT_CallTaskPipe(CFE_ES_TaskPipe, &CmdBuf.Msg, sizeof(CFE_ES_WriteERLog_t), UT_TPID_CFE_ES_CMD_WRITE_ER_LOG_CC); UT_Report(__FILE__, __LINE__, - UT_EventIsInHistory(CFE_ES_ERLOG2_EID), + UT_EventIsInHistory(CFE_ES_ERLOG_PENDING_ERR_EID), + "CFE_ES_WriteERLogCmd", + "Write E&R log command; already pending event"); + + /* calling the background job when no write pending should immediately return false, no event */ + ES_ResetUnitTest(); + memset(&CFE_ES_TaskData.BackgroundERLogDumpState, 0, sizeof(CFE_ES_TaskData.BackgroundERLogDumpState)); + UT_Report(__FILE__, __LINE__, + !CFE_ES_RunERLogDump(0, &CFE_ES_TaskData.BackgroundERLogDumpState), + "CFE_ES_RunERLogDump", + "Write E&R log; not pending"); + UT_Report(__FILE__, __LINE__, + !UT_EventIsInHistory(CFE_ES_ERLOG2_EID), + "CFE_ES_WriteERLogCmd", + "Write E&R log command; no file written event"); + + /* nominal condition - still returns false, but generates event */ + ES_ResetUnitTest(); + UT_ContextBuffer = 42; + UT_SetDataBuffer(UT_KEY(CFE_PSP_Exception_CopyContext),&UT_ContextBuffer, sizeof(UT_ContextBuffer), false); + CFE_ES_TaskData.BackgroundERLogDumpState.IsPending = true; + CFE_ES_RunERLogDump(0, &CFE_ES_TaskData.BackgroundERLogDumpState); + UT_Report(__FILE__, __LINE__, + !CFE_ES_TaskData.BackgroundERLogDumpState.IsPending, + "CFE_ES_RunERLogDump", + "Write E&R log; nominal, clear flag"); + UT_Report(__FILE__, __LINE__, + UT_EventIsInHistory(CFE_ES_ERLOG2_EID), "CFE_ES_WriteERLogCmd", - "Write E&R log; success"); + "Write E&R log command; file written event"); /* Test writing the E&R log with an OS create failure */ ES_ResetUnitTest(); - memset(&CmdBuf, 0, sizeof(CmdBuf)); + CFE_ES_TaskData.BackgroundERLogDumpState.IsPending = true; UT_SetForceFail(UT_KEY(OS_creat), OS_ERROR); - strncpy((char *) CmdBuf.WriteERlogCmd.Payload.FileName, "", - sizeof(CmdBuf.WriteERlogCmd.Payload.FileName)); - UT_CallTaskPipe(CFE_ES_TaskPipe, &CmdBuf.Msg, sizeof(CFE_ES_WriteERLog_t), - UT_TPID_CFE_ES_CMD_WRITE_ER_LOG_CC); + CFE_ES_RunERLogDump(0, &CFE_ES_TaskData.BackgroundERLogDumpState); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_ERLOG2_ERR_EID), - "CFE_ES_WriteERLogCmd", + "CFE_ES_RunERLogDump", "Write E&R log; OS create"); /* Test writing the E&R log with an OS write failure */ ES_ResetUnitTest(); - memset(&CmdBuf, 0, sizeof(CmdBuf)); + CFE_ES_TaskData.BackgroundERLogDumpState.IsPending = true; UT_SetForceFail(UT_KEY(OS_write), OS_ERROR); - strncpy((char *) CmdBuf.WriteERlogCmd.Payload.FileName, "n", - sizeof(CmdBuf.WriteERlogCmd.Payload.FileName)); - UT_CallTaskPipe(CFE_ES_TaskPipe, &CmdBuf.Msg, sizeof(CFE_ES_WriteERLog_t), - UT_TPID_CFE_ES_CMD_WRITE_ER_LOG_CC); + CFE_ES_RunERLogDump(0, &CFE_ES_TaskData.BackgroundERLogDumpState); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_FILEWRITE_ERR_EID), - "CFE_ES_WriteERLogCmd", + "CFE_ES_RunERLogDump", "Write E&R log; OS write"); /* Test writing the E&R log with a write header failure */ ES_ResetUnitTest(); - memset(&CmdBuf, 0, sizeof(CmdBuf)); + CFE_ES_TaskData.BackgroundERLogDumpState.IsPending = true; UT_SetDeferredRetcode(UT_KEY(CFE_FS_WriteHeader), 1, OS_ERROR); - UT_CallTaskPipe(CFE_ES_TaskPipe, &CmdBuf.Msg, sizeof(CFE_ES_WriteERLog_t), - UT_TPID_CFE_ES_CMD_WRITE_ER_LOG_CC); + CFE_ES_RunERLogDump(0, &CFE_ES_TaskData.BackgroundERLogDumpState); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_FILEWRITE_ERR_EID), "CFE_ES_WriteERLogCmd", "Write E&R log; write header"); - /* Test writing the E&R log with a reset area failure */ + /* Test scan for exceptions in the PSP, should invoke a Processor Reset */ ES_ResetUnitTest(); - memset(&CmdBuf, 0, sizeof(CmdBuf)); - UT_SetStatusBSPResetArea(OS_ERROR, 0, CFE_TIME_ToneSignalSelect_PRIMARY); - UT_CallTaskPipe(CFE_ES_TaskPipe, &CmdBuf.Msg, sizeof(CFE_ES_WriteERLog_t), - UT_TPID_CFE_ES_CMD_WRITE_ER_LOG_CC); + UT_SetForceFail(UT_KEY(CFE_PSP_Exception_GetCount), 1); + CFE_ES_RunExceptionScan(0, NULL); UT_Report(__FILE__, __LINE__, - UT_EventIsInHistory(CFE_ES_RST_ACCESS_EID), - "CFE_ES_WriteERLogCmd", - "Write E&R log; reset area"); + UT_GetStubCount(UT_KEY(CFE_PSP_Restart)) == 1, + "CFE_ES_RunExceptionScan", + "Scan for exceptions; processor restart"); + + ES_ResetUnitTest(); + CFE_ES_ResetDataPtr->ResetVars.ProcessorResetCount = 0; + CFE_ES_ResetDataPtr->ResetVars.MaxProcessorResetCount = 1; + UT_SetForceFail(UT_KEY(CFE_PSP_Exception_GetCount), 1); + CFE_ES_RunExceptionScan(0, NULL); + /* first time should do a processor restart (limit reached) */ + UT_Report(__FILE__, __LINE__, + UT_GetStubCount(UT_KEY(CFE_PSP_Restart)) == 1, + "CFE_ES_RunExceptionScan", + "Scan for exceptions; processor restart"); + /* next time should do a poweron restart (limit reached) */ + CFE_ES_RunExceptionScan(0, NULL); + UT_Report(__FILE__, __LINE__, + UT_GetStubCount(UT_KEY(CFE_PSP_Restart)) == 2, + "CFE_ES_RunExceptionScan", + "Scan for exceptions; poweron restart"); + + /* nominal for app restart - associate exception with a task ID */ + OS_TaskCreate(&UT_ContextBuffer, "UT", NULL, NULL, 0, 0, 0); + UT_SetDataBuffer(UT_KEY(CFE_PSP_Exception_GetSummary), &UT_ContextBuffer, sizeof(UT_ContextBuffer), false); + CFE_ES_Global.TaskTable[1].RecordUsed = true; + CFE_ES_Global.TaskTable[1].AppId = 0; + CFE_ES_Global.TaskTable[1].TaskId = UT_ContextBuffer; + CFE_ES_Global.AppTable[0].AppState = CFE_ES_AppState_RUNNING; + CFE_ES_Global.AppTable[0].ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_RUN; + CFE_ES_Global.AppTable[0].ControlReq.AppTimerMsec = 0; + CFE_ES_Global.AppTable[0].Type = CFE_ES_AppType_EXTERNAL; + CFE_ES_Global.AppTable[0].StartParams.ExceptionAction = CFE_ES_ExceptionAction_RESTART_APP; + CFE_ES_RunExceptionScan(0, NULL); + /* should have changed AppControlRequest from RUN to SYS_RESTART, + * and the call to CFE_PSP_Restart should NOT increment */ + UT_Report(__FILE__, __LINE__, + CFE_ES_Global.AppTable[0].ControlReq.AppControlRequest == CFE_ES_RunStatus_SYS_RESTART, + "CFE_ES_RunExceptionScan", + "Scan for exceptions; app restart request pending"); + + UT_Report(__FILE__, __LINE__, + UT_GetStubCount(UT_KEY(CFE_PSP_Restart)) == 2, + "CFE_ES_RunExceptionScan", + "Scan for exceptions; no psp restart"); + + /* repeat, but for a CORE app, which cannot be restarted */ + UT_SetDataBuffer(UT_KEY(CFE_PSP_Exception_GetSummary), &UT_ContextBuffer, sizeof(UT_ContextBuffer), false); + CFE_ES_Global.AppTable[0].ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_RUN; + CFE_ES_Global.AppTable[0].Type = CFE_ES_AppType_CORE; + CFE_ES_RunExceptionScan(0, NULL); + UT_Report(__FILE__, __LINE__, + UT_GetStubCount(UT_KEY(CFE_PSP_Restart)) == 3, + "CFE_ES_RunExceptionScan", + "Scan for exceptions; core app, psp restart"); + + /* check failure of getting summary data */ + UT_SetForceFail(UT_KEY(CFE_PSP_Exception_GetSummary), CFE_PSP_NO_EXCEPTION_DATA); + CFE_ES_RunExceptionScan(0, NULL); + UT_Report(__FILE__, __LINE__, + UT_GetStubCount(UT_KEY(CFE_PSP_Restart)) == 4, + "CFE_ES_RunExceptionScan", + "Scan for exceptions; fail to get context"); /* Test clearing the log with a bad size in the verify command * length call @@ -4338,13 +4379,12 @@ void TestPerf(void) void TestAPI(void) { - uint32 Id, Id2; - uint32 TestObjId, TestObjId2; + uint32 Id; + uint32 TestObjId; char AppName[32]; char CounterName[11]; char CDSName[CFE_MISSION_ES_CDS_MAX_NAME_LENGTH + 2]; int i; - uint32 ExceptionContext = 0; int32 Return; uint8 Data[12]; uint32 ResetType; @@ -5328,86 +5368,6 @@ void TestAPI(void) (CounterCount == 5), "CFE_ES_SetGenCount", "Check value for counter set"); - /* Test handling of logging and reset after a core exception using - * a non-running app - */ - ES_ResetUnitTest(); - OS_TaskCreate(&TestObjId, "UT", NULL, NULL, 0, 0, 0); - Id = ES_UT_OSALID_TO_ARRAYIDX(TestObjId); - OS_TaskCreate(&TestObjId2, "UT", NULL, NULL, 0, 0, 0); - Id2 = ES_UT_OSALID_TO_ARRAYIDX(TestObjId2); - strncpy((char *)CFE_ES_Global.AppTable[Id].StartParams.Name, "appName", - sizeof(CFE_ES_Global.AppTable[Id].StartParams.Name)); - CFE_ES_Global.TaskTable[Id].RecordUsed = true; - CFE_ES_Global.AppTable[Id].Type = CFE_ES_AppType_EXTERNAL; - CFE_ES_Global.AppTable[Id].AppState = CFE_ES_AppState_EARLY_INIT; - CFE_ES_Global.TaskTable[Id2].RecordUsed = true; - CFE_ES_Global.TaskTable[Id2].AppId = Id; - OS_TaskCreate(&CFE_ES_Global.TaskTable[Id2].TaskId, NULL, NULL, NULL, - 0, 0, 0); - CFE_ES_Global.AppTable[Id].StartParams.ExceptionAction = - CFE_ES_ExceptionAction_RESTART_APP; - CFE_ES_ProcessCoreException(TestObjId & 0xFFFF, - "Reason String", - &ExceptionContext, - sizeof(ExceptionContext)); - UT_Report(__FILE__, __LINE__, - UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_CANNOT_RESTART_APP]) && - UT_GetStubCount(UT_KEY(OS_printf)) == 1, - "CFE_ES_ProcessCoreException", - "Cannot restart a non-running application"); - - /* Test handling of logging and reset after a core exception; processor - * reset with no app restart - */ - ES_ResetUnitTest(); - UT_SetDataBuffer(UT_KEY(CFE_PSP_Restart), &ResetType, sizeof(ResetType), false); - OS_TaskCreate(&TestObjId, "UT", NULL, NULL, 0, 0, 0); - Id = ES_UT_OSALID_TO_ARRAYIDX(TestObjId); - OS_TaskCreate(&TestObjId2, "UT", NULL, NULL, 0, 0, 0); - Id2 = ES_UT_OSALID_TO_ARRAYIDX(TestObjId2); -// memset(CFE_ES_Global.TaskTable, 0, sizeof(CFE_ES_Global.TaskTable)); -// memset(CFE_ES_Global.AppTable, 0, sizeof(CFE_ES_Global.AppTable)); - strncpy((char *)CFE_ES_Global.AppTable[Id].StartParams.Name, "appName", - sizeof(CFE_ES_Global.AppTable[Id].StartParams.Name)); - CFE_ES_Global.TaskTable[Id2].RecordUsed = true; - CFE_ES_Global.TaskTable[Id2].AppId = Id; - OS_TaskCreate(&CFE_ES_Global.TaskTable[Id2].TaskId, NULL, NULL, NULL, - 0, 0, 0); - CFE_ES_Global.AppTable[Id].AppState = CFE_ES_AppState_RUNNING; - CFE_ES_ResetDataPtr->ResetVars.ProcessorResetCount = 0; - CFE_ES_ResetDataPtr->ResetVars.MaxProcessorResetCount = 5; - CFE_ES_Global.AppTable[3].StartParams.ExceptionAction = - CFE_ES_ExceptionAction_RESTART_APP + 1; - CFE_ES_ProcessCoreException(TestObjId2 & 0xFFFF, - "Reason String", - &ExceptionContext, - sizeof(ExceptionContext)); - UT_Report(__FILE__, __LINE__, - ResetType == CFE_PSP_RST_TYPE_PROCESSOR && - UT_GetStubCount(UT_KEY(CFE_PSP_Restart)) == 1, - "CFE_ES_ProcessCoreException", - "Processor reset with no application restart"); - - /* Test handling of logging and reset after a core exception; power on - * reset with no app restart - */ - ES_ResetUnitTest(); - UT_SetDataBuffer(UT_KEY(CFE_PSP_Restart), &ResetType, sizeof(ResetType), false); - CFE_ES_ResetDataPtr->ResetVars.ProcessorResetCount = 100; - CFE_ES_ResetDataPtr->ResetVars.MaxProcessorResetCount = 5; - CFE_ES_Global.AppTable[3].StartParams.ExceptionAction = - CFE_ES_ExceptionAction_RESTART_APP + 1; - CFE_ES_ProcessCoreException(OS_MAX_TASKS - 1, - "Reason String", - &ExceptionContext, - sizeof(ExceptionContext)); - UT_Report(__FILE__, __LINE__, - ResetType == CFE_PSP_RST_TYPE_POWERON && - UT_GetStubCount(UT_KEY(CFE_PSP_Restart)) == 1, - "CFE_ES_ProcessCoreException", - "Power on reset with no application restart"); - /* Test waiting for apps to initialize before continuing; transition from * initializing to running */ @@ -5601,68 +5561,6 @@ void TestAPI(void) "CFE_ES_GetGenCounterIDByName", "Null name"); - /* Test handling of logging and reset after failure to get the task info - * from the OS - */ - ES_ResetUnitTest(); - UT_SetDeferredRetcode(UT_KEY(OS_TaskGetInfo), 1, OS_INVALID_POINTER); - CFE_ES_ResetDataPtr->ResetVars.ProcessorResetCount = 0; - CFE_ES_ResetDataPtr->ResetVars.MaxProcessorResetCount = 5; - CFE_ES_ProcessCoreException(0xFFFFFFFF, - "Reason String", - &ExceptionContext, - sizeof(ExceptionContext)); - UT_Report(__FILE__, __LINE__, - CFE_ES_ResetDataPtr->ResetVars.ProcessorResetCount == 1 && - CFE_ES_ResetDataPtr->ResetVars.ES_CausedReset == true, - "CFE_ES_ProcessCoreException", - "Failure to get task info from OS"); - - /* Test handling of logging and reset where the host ID doesn't match - * the OS task ID - */ - ES_ResetUnitTest(); - OS_TaskCreate(&TestObjId, "UT", NULL, NULL, 0, 0, 0); - Id = ES_UT_OSALID_TO_ARRAYIDX(TestObjId); - CFE_ES_Global.TaskTable[Id].RecordUsed = true; - CFE_ES_Global.TaskTable[Id].AppId = Id; - CFE_ES_ResetDataPtr->ResetVars.ProcessorResetCount = 0; - CFE_ES_ResetDataPtr->ResetVars.MaxProcessorResetCount = 5; - CFE_ES_Global.AppTable[Id].StartParams.ExceptionAction = - CFE_ES_ExceptionAction_RESTART_APP; - CFE_ES_ProcessCoreException(0, - "Reason String", - &ExceptionContext, - sizeof(ExceptionContext)); - UT_Report(__FILE__, __LINE__, - UT_GetStubCount(UT_KEY(OS_printf)) == 0, - "CFE_ES_ProcessCoreException", - "Host ID doesn't match OS task ID"); - - /* Test handling of logging and reset where CFE_ES_GetTaskInfo fails */ - ES_ResetUnitTest(); - OS_TaskCreate(&TestObjId, "UT", NULL, NULL, 0, 0, 0); - Id = ES_UT_OSALID_TO_ARRAYIDX(TestObjId); - OS_TaskCreate(&TestObjId2, "UT", NULL, NULL, 0, 0, 0); - Id2 = ES_UT_OSALID_TO_ARRAYIDX(TestObjId2); - CFE_ES_Global.TaskTable[Id].RecordUsed = true; - CFE_ES_Global.TaskTable[Id].AppId = Id; - CFE_ES_ResetDataPtr->ResetVars.ProcessorResetCount = 0; - CFE_ES_ResetDataPtr->ResetVars.MaxProcessorResetCount = 5; - CFE_ES_Global.TaskTable[Id].RecordUsed = true; - CFE_ES_Global.TaskTable[Id].AppId = Id2; - CFE_ES_Global.AppTable[Id2].AppState = CFE_ES_AppState_UNDEFINED; - CFE_ES_Global.AppTable[Id2].StartParams.ExceptionAction = - CFE_ES_ExceptionAction_RESTART_APP; - CFE_ES_ProcessCoreException(Id, - "Reason String", - &ExceptionContext, - sizeof(ExceptionContext)); - UT_Report(__FILE__, __LINE__, - UT_GetStubCount(UT_KEY(OS_printf)) == 1, - "CFE_ES_ProcessCoreException", - "CFE_ES_GetTaskInfo failure"); - /* Test unsuccessful CDS registering */ ES_ResetUnitTest(); OS_TaskCreate(&TestObjId, "UT", NULL, NULL, 0, 0, 0);