From 51a614c2ff2f173781e5c515fe11df56f3471bd0 Mon Sep 17 00:00:00 2001 From: Joseph Hickey Date: Fri, 5 Feb 2021 16:45:05 -0500 Subject: [PATCH 1/7] Fix #790, allow directories and symlinks in FILELIST. Checks a name-based subdirectory under ${MISSION_DEFS} for files listed in the FILELIST for that target. If file is a symlink, the link should be followed so the correct content is installed, not a symlink. --- cmake/arch_build.cmake | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cmake/arch_build.cmake b/cmake/arch_build.cmake index e569f500b..d42ea9958 100644 --- a/cmake/arch_build.cmake +++ b/cmake/arch_build.cmake @@ -474,7 +474,9 @@ function(process_arch SYSVAR) add_subdirectory(cmake/target ${TGTNAME}) foreach(INSTFILE ${${TGTNAME}_FILELIST}) - if(EXISTS ${MISSION_DEFS}/${TGTNAME}_${INSTFILE}) + if(EXISTS ${MISSION_DEFS}/${TGTNAME}/${INSTFILE}) + set(FILESRC ${MISSION_DEFS}/${TGTNAME}/${INSTFILE}) + elseif(EXISTS ${MISSION_DEFS}/${TGTNAME}_${INSTFILE}) set(FILESRC ${MISSION_DEFS}/${TGTNAME}_${INSTFILE}) elseif(EXISTS ${MISSION_DEFS}/${INSTFILE}) set(FILESRC ${MISSION_DEFS}/${INSTFILE}) @@ -482,6 +484,9 @@ function(process_arch SYSVAR) set(FILESRC) endif() if (FILESRC) + # In case the file is a symlink, follow it to get to the actual file + get_filename_component(FILESRC "${FILESRC}" REALPATH) + message("NOTE: Selected ${FILESRC} as source for ${INSTFILE} on ${TGTNAME}") install(FILES ${FILESRC} DESTINATION ${TGTNAME}/${INSTALL_SUBDIR} RENAME ${INSTFILE}) else(FILESRC) message("WARNING: Install file ${INSTFILE} for ${TGTNAME} not found") From 81cbc46c0df5de0264ec9f6c6a8bfb7caceb7fbf Mon Sep 17 00:00:00 2001 From: Joseph Hickey Date: Mon, 1 Feb 2021 14:56:26 -0500 Subject: [PATCH 2/7] Fix #139, move file writes to background task Implements a generic asynchronous "file write request" facility in the FS subsystem. Given a metadata/control block with the file details and writer state and appropriate callbacks,, this will execute the file write job as part of the ES background task. The following file requests are changed to use this facility: - ES ER Log dump - SB Pipe Info - SB Message Map - SB Route Info - TBL Registry Dump --- fsw/cfe-core/src/es/cfe_es_apps.h | 11 +- fsw/cfe-core/src/es/cfe_es_backgroundtask.c | 6 +- fsw/cfe-core/src/es/cfe_es_erlog.c | 186 +++--- fsw/cfe-core/src/es/cfe_es_task.c | 45 +- fsw/cfe-core/src/es/cfe_es_task.h | 6 +- fsw/cfe-core/src/fs/cfe_fs_api.c | 245 ++++++++ fsw/cfe-core/src/fs/cfe_fs_priv.h | 87 +++ fsw/cfe-core/src/inc/cfe_error.h | 9 + fsw/cfe-core/src/inc/cfe_es.h | 20 + fsw/cfe-core/src/inc/cfe_fs.h | 117 ++++ fsw/cfe-core/src/inc/cfe_sb_msg.h | 6 +- fsw/cfe-core/src/sb/cfe_sb_api.c | 16 +- fsw/cfe-core/src/sb/cfe_sb_priv.h | 59 +- fsw/cfe-core/src/sb/cfe_sb_task.c | 661 ++++++++++---------- fsw/cfe-core/src/tbl/cfe_tbl_internal.h | 9 + fsw/cfe-core/src/tbl/cfe_tbl_task.h | 18 + fsw/cfe-core/src/tbl/cfe_tbl_task_cmds.c | 352 ++++++----- fsw/cfe-core/unit-test/es_UT.c | 121 ++-- fsw/cfe-core/unit-test/fs_UT.c | 141 +++++ fsw/cfe-core/unit-test/fs_UT.h | 13 + fsw/cfe-core/unit-test/sb_UT.c | 346 +++++----- fsw/cfe-core/unit-test/sb_UT.h | 139 +--- fsw/cfe-core/unit-test/tbl_UT.c | 142 +++-- fsw/cfe-core/ut-stubs/ut_es_stubs.c | 5 + fsw/cfe-core/ut-stubs/ut_fs_stubs.c | 37 ++ 25 files changed, 1764 insertions(+), 1033 deletions(-) diff --git a/fsw/cfe-core/src/es/cfe_es_apps.h b/fsw/cfe-core/src/es/cfe_es_apps.h index abe038378..ed2d1a67a 100644 --- a/fsw/cfe-core/src/es/cfe_es_apps.h +++ b/fsw/cfe-core/src/es/cfe_es_apps.h @@ -249,9 +249,14 @@ bool CFE_ES_RunAppTableScan(uint32 ElapsedTime, void *Arg); bool CFE_ES_RunExceptionScan(uint32 ElapsedTime, void *Arg); /* -** Check if ER log dump request is pending -*/ -bool CFE_ES_RunERLogDump(uint32 ElapsedTime, void *Arg); + * Background file write data getter for ER log entry + */ +bool CFE_ES_BackgroundERLogFileDataGetter(void *Meta, uint32 RecordNum, void **Buffer, size_t *BufSize); + +/* + * Background file write event handler for ER log entry + */ +void CFE_ES_BackgroundERLogFileEventHandler(void *Meta, CFE_FS_FileWriteEvent_t Event, int32 Status, uint32 RecordNum, size_t BlockSize, size_t Position); /* ** 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 e72be0a28..93b70867e 100644 --- a/fsw/cfe-core/src/es/cfe_es_backgroundtask.c +++ b/fsw/cfe-core/src/es/cfe_es_backgroundtask.c @@ -89,9 +89,9 @@ const CFE_ES_BackgroundJobEntry_t CFE_ES_BACKGROUND_JOB_TABLE[] = .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, + { /* Call FS to handle background file writes */ + .RunFunc = CFE_FS_RunBackgroundFileDump, + .JobArg = NULL, .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 f132d918b..1ebd390ef 100644 --- a/fsw/cfe-core/src/es/cfe_es_erlog.c +++ b/fsw/cfe-core/src/es/cfe_es_erlog.c @@ -181,126 +181,118 @@ int32 CFE_ES_WriteToERLog( CFE_ES_LogEntryType_Enum_t EntryType, uint32 Reset } /* End of CFE_ES_WriteToERLog() */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* Function: CFE_ES_RunERLogDump() */ +/* Function: CFE_ES_BackgroundERLogFileDataGetter() */ /* */ /* 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. */ +/* Gets a single record from exception & reset log to write to a file. */ /* */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -bool CFE_ES_RunERLogDump(uint32 ElapsedTime, void *Arg) +bool CFE_ES_BackgroundERLogFileDataGetter(void *Meta, uint32 RecordNum, void **Buffer, size_t *BufSize) { - CFE_ES_BackgroundLogDumpGlobal_t *State = (CFE_ES_BackgroundLogDumpGlobal_t *)Arg; - int32 Status; - int32 PspStatus; - CFE_FS_Header_t FileHdr; - CFE_ES_ERLog_FileEntry_t FileEntry; + CFE_ES_BackgroundLogDumpGlobal_t *BgFilePtr; + CFE_ES_ERLog_FileEntry_t *FileBufferPtr; CFE_ES_ERLog_MetaData_t *EntryPtr; - uint32 FileSize; - uint32 i; - osal_id_t fd; - + int32 PspStatus; + + BgFilePtr = (CFE_ES_BackgroundLogDumpGlobal_t *)Meta; + FileBufferPtr = &BgFilePtr->EntryBuffer; - if (!State->IsPending) + if (RecordNum < CFE_PLATFORM_ES_ER_LOG_ENTRIES) { - return false; - } + EntryPtr = &CFE_ES_ResetDataPtr->ERLog[RecordNum]; - FileSize = 0; - Status = OS_OpenCreate(&fd, State->DataFileName, OS_FILE_FLAG_CREATE | OS_FILE_FLAG_TRUNCATE, OS_WRITE_ONLY); - if(Status < 0) - { - CFE_EVS_SendEvent(CFE_ES_ERLOG2_ERR_EID,CFE_EVS_EventType_ERROR, - "Error creating file %s, RC = %d", - State->DataFileName, (int)Status); - } - else - { - CFE_FS_InitHeader(&FileHdr, CFE_ES_ER_LOG_DESC, CFE_FS_SubType_ES_ERLOG); + /* First wipe the buffer before re-use */ + memset(FileBufferPtr, 0, sizeof(*FileBufferPtr)); + + CFE_ES_LockSharedData(__func__,__LINE__); + + /* The basic info comes directly from the ES log */ + FileBufferPtr->BaseInfo = EntryPtr->BaseInfo; - /* write the cFE header to the file */ - Status = CFE_FS_WriteHeader(fd, &FileHdr); - if(Status != sizeof(CFE_FS_Header_t)) + /* + * 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, &FileBufferPtr->Context, + sizeof(FileBufferPtr->Context)); + if (PspStatus > 0) { - CFE_ES_FileWriteByteCntErr(State->DataFileName,sizeof(CFE_FS_Header_t),Status); + FileBufferPtr->ContextSize = PspStatus; } else { - FileSize += Status; - - /* 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 - */ - Status = OS_write(fd,&FileEntry,sizeof(FileEntry)); - - if(Status != sizeof(FileEntry)) - { - CFE_ES_FileWriteByteCntErr(State->DataFileName,sizeof(FileEntry),Status); - break; - }/* end if */ + /* + * errors here are OK - just means there is no context available. + * Record a size of 0 in the log file. + */ + FileBufferPtr->ContextSize = 0; + } - FileSize += Status; + CFE_ES_UnlockSharedData(__func__,__LINE__); - } /* end for */ + /* + * Export data to caller for actual write + */ + *Buffer = FileBufferPtr; + *BufSize = sizeof(*FileBufferPtr); + } + else + { + *Buffer = NULL; + *BufSize = 0; + } - } /* end if */ + /* Check for EOF (last entry) */ + return (RecordNum >= (CFE_PLATFORM_ES_ER_LOG_ENTRIES-1)); +} - OS_close(fd); - CFE_EVS_SendEvent(CFE_ES_ERLOG2_EID, CFE_EVS_EventType_DEBUG, - "%s written:Size=%lu",State->DataFileName,(unsigned long)FileSize); +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* Function: CFE_ER_BackgroundERLogFileEventHandler() */ +/* */ +/* Purpose: */ +/* Report events during writing exception & reset log to a file. */ +/* */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +void CFE_ES_BackgroundERLogFileEventHandler(void *Meta, CFE_FS_FileWriteEvent_t Event, int32 Status, uint32 RecordNum, size_t BlockSize, size_t Position) +{ + CFE_ES_BackgroundLogDumpGlobal_t *BgFilePtr; - } /* end if */ + BgFilePtr = (CFE_ES_BackgroundLogDumpGlobal_t *)Meta; /* - * Always clear the "pending" flag whether successful or not. - * If unsuccessful, an operator needs to investigate the error and re-issue command. + * Note that this runs in the context of ES background task (file writer background job) + * It does NOT run in the context of the CFE_TBL app task. + * + * Events should use CFE_EVS_SendEventWithAppID() rather than CFE_EVS_SendEvent() + * to get proper association with TBL task. */ - State->IsPending = false; - - return false; -}/* end CFE_ES_RunERLogDump */ - + switch(Event) + { + case CFE_FS_FileWriteEvent_COMPLETE: + CFE_EVS_SendEvent(CFE_ES_ERLOG2_EID, CFE_EVS_EventType_DEBUG, + "%s written:Size=%lu", + BgFilePtr->FileWrite.FileName,(unsigned long)Position); + break; + + case CFE_FS_FileWriteEvent_HEADER_WRITE_ERROR: + case CFE_FS_FileWriteEvent_RECORD_WRITE_ERROR: + CFE_EVS_SendEvent(CFE_ES_FILEWRITE_ERR_EID,CFE_EVS_EventType_ERROR, + "File write,byte cnt err,file %s,request=%u,actual=%u", + BgFilePtr->FileWrite.FileName, (int)BlockSize, (int)Status); + break; + + case CFE_FS_FileWriteEvent_CREATE_ERROR: + CFE_EVS_SendEvent(CFE_ES_ERLOG2_ERR_EID,CFE_EVS_EventType_ERROR, + "Error creating file %s, RC = %d", + BgFilePtr->FileWrite.FileName, (int)Status); + break; + + default: + /* unhandled event - ignore */ + break; + } +} /* **--------------------------------------------------------------------------------------- diff --git a/fsw/cfe-core/src/es/cfe_es_task.c b/fsw/cfe-core/src/es/cfe_es_task.c index 3f7696876..06365bfa3 100644 --- a/fsw/cfe-core/src/es/cfe_es_task.c +++ b/fsw/cfe-core/src/es/cfe_es_task.c @@ -1612,26 +1612,51 @@ int32 CFE_ES_ClearERLogCmd(const CFE_ES_ClearERLogCmd_t *data) int32 CFE_ES_WriteERLogCmd(const CFE_ES_WriteERLogCmd_t *data) { const CFE_ES_FileNameCmd_Payload_t *CmdPtr = &data->Payload; + CFE_ES_BackgroundLogDumpGlobal_t *StatePtr; + int32 Status; + + StatePtr = &CFE_ES_TaskData.BackgroundERLogDumpState; + + /* check if pending before overwriting fields in the structure */ + if (CFE_FS_BackgroundFileDumpIsPending(&StatePtr->FileWrite)) + { + Status = CFE_STATUS_REQUEST_ALREADY_PENDING; + } + else + { + /* Reset the entire state object (just for good measure, ensure no stale data) */ + memset(StatePtr, 0, sizeof(*StatePtr)); + + /* + * Fill out the remainder of meta data. + * This data is currently the same for every request + */ + StatePtr->FileWrite.FileSubType = CFE_FS_SubType_ES_ERLOG; + snprintf(StatePtr->FileWrite.Description, sizeof(StatePtr->FileWrite.Description), CFE_ES_ER_LOG_DESC); + + StatePtr->FileWrite.GetData = CFE_ES_BackgroundERLogFileDataGetter; + StatePtr->FileWrite.OnEvent = CFE_ES_BackgroundERLogFileEventHandler; - if (CFE_ES_TaskData.BackgroundERLogDumpState.IsPending) + CFE_SB_MessageStringGet(StatePtr->FileWrite.FileName, CmdPtr->FileName, + CFE_PLATFORM_ES_DEFAULT_ER_LOG_FILE, + sizeof(StatePtr->FileWrite.FileName), sizeof(CmdPtr->FileName)); + + Status = CFE_FS_BackgroundFileDumpRequest(&StatePtr->FileWrite); + } + + if (Status != CFE_SUCCESS) { 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); + StatePtr->FileWrite.FileName); /* background dump already running, consider this an error */ CFE_ES_TaskData.CommandErrorCounter++; - } + } else { - 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)); - - CFE_ES_TaskData.BackgroundERLogDumpState.IsPending = true; CFE_ES_TaskData.CommandCounter++; - CFE_ES_BackgroundWakeup(); - } + } return CFE_SUCCESS; }/* end CFE_ES_WriteERLogCmd */ diff --git a/fsw/cfe-core/src/es/cfe_es_task.h b/fsw/cfe-core/src/es/cfe_es_task.h index 479799d80..fb8d69cf6 100644 --- a/fsw/cfe-core/src/es/cfe_es_task.h +++ b/fsw/cfe-core/src/es/cfe_es_task.h @@ -44,6 +44,7 @@ #include "cfe_es_events.h" #include "cfe_es_msg.h" #include "cfe_es_perf.h" +#include "private/cfe_es_erlog_typedef.h" /*************************************************************************/ @@ -90,8 +91,8 @@ */ typedef struct { - volatile bool IsPending; - char DataFileName[OS_MAX_PATH_LEN]; + CFE_FS_FileWriteMetaData_t FileWrite; /**< FS state data - must be first */ + CFE_ES_ERLog_FileEntry_t EntryBuffer; /**< Temp holding area for record to write */ } CFE_ES_BackgroundLogDumpGlobal_t; /* @@ -164,7 +165,6 @@ void CFE_ES_TaskPipe(CFE_SB_Buffer_t *SBBufPtr); */ int32 CFE_ES_BackgroundInit(void); void CFE_ES_BackgroundTask(void); -void CFE_ES_BackgroundWakeup(void); void CFE_ES_BackgroundCleanup(void); /* diff --git a/fsw/cfe-core/src/fs/cfe_fs_api.c b/fsw/cfe-core/src/fs/cfe_fs_api.c index 4f83e5f13..7638472e9 100644 --- a/fsw/cfe-core/src/fs/cfe_fs_api.c +++ b/fsw/cfe-core/src/fs/cfe_fs_api.c @@ -328,6 +328,251 @@ int32 CFE_FS_ExtractFilenameFromPath(const char *OriginalPath, char *FileNameOnl return(ReturnCode); } +/* +** CFE_FS_RunBackgroundFileDump - See API and header file for details +*/ +bool CFE_FS_RunBackgroundFileDump(uint32 ElapsedTime, void *Arg) +{ + CFE_FS_CurrentFileState_t *State; + CFE_FS_BackgroundFileDumpEntry_t *Curr; + CFE_FS_FileWriteMetaData_t *Meta; + int32 Status; + CFE_FS_Header_t FileHdr; + void *RecordPtr; + size_t RecordSize; + bool IsEOF; + + State = &CFE_FS_Global.FileDump.Current; + Curr = NULL; + IsEOF = false; + RecordPtr = NULL; + RecordSize = 0; + + State->Credit += (ElapsedTime * CFE_FS_BACKGROUND_CREDIT_PER_SECOND) / 1000; + if (State->Credit > CFE_FS_BACKGROUND_MAX_CREDIT) + { + State->Credit = CFE_FS_BACKGROUND_MAX_CREDIT; + } + + /* + * Lock shared data. + * Not strictly necessary as the "CompleteCount" is only updated + * by this task but this helps in case the access isn't atomic. + */ + CFE_FS_LockSharedData(__func__); + + if (CFE_FS_Global.FileDump.CompleteCount != CFE_FS_Global.FileDump.RequestCount) + { + Curr = &CFE_FS_Global.FileDump.Entries[CFE_FS_Global.FileDump.CompleteCount & (CFE_FS_MAX_BACKGROUND_FILE_WRITES - 1)]; + } + + CFE_FS_UnlockSharedData(__func__); + + if (Curr == NULL) + { + return false; + } + + Meta = Curr->Meta; + + if (!OS_ObjectIdDefined(State->Fd) && Meta->IsPending) + { + /* First time processing this entry - open the file */ + Status = OS_OpenCreate(&State->Fd, Meta->FileName, OS_FILE_FLAG_CREATE | OS_FILE_FLAG_TRUNCATE, OS_WRITE_ONLY); + if(Status < 0) + { + State->Fd = OS_OBJECT_ID_UNDEFINED; + Meta->OnEvent(Meta, CFE_FS_FileWriteEvent_CREATE_ERROR, Status, 0, 0, 0); + } + else + { + CFE_FS_InitHeader(&FileHdr, Meta->Description, Meta->FileSubType); + + /* write the cFE header to the file */ + Status = CFE_FS_WriteHeader(State->Fd, &FileHdr); + if (Status != sizeof(CFE_FS_Header_t)) + { + OS_close(State->Fd); + State->Fd = OS_OBJECT_ID_UNDEFINED; + Meta->OnEvent(Meta, CFE_FS_FileWriteEvent_HEADER_WRITE_ERROR, Status, State->RecordNum, sizeof(CFE_FS_Header_t), State->FileSize); + } + else + { + State->FileSize = sizeof(CFE_FS_Header_t); + State->Credit -= sizeof(CFE_FS_Header_t); + State->RecordNum = 0; + } + } + } + + while (OS_ObjectIdDefined(State->Fd) && State->Credit > 0 && !IsEOF) + { + /* + * Getter should return false on EOF (last record), true if more data is still waiting + */ + IsEOF = Meta->GetData(Meta, State->RecordNum, &RecordPtr, &RecordSize); + + /* + * if the getter outputs a record size of 0, this means there is no data for + * this entry, but the cycle keeps going (in case of "holes" or unused table entries + * in the database). + */ + if (RecordSize > 0) + { + State->Credit -= RecordSize; + + /* + * Now write to file + */ + Status = OS_write(State->Fd,RecordPtr,RecordSize); + + if (Status != RecordSize) + { + /* end the file early (cannot set "IsEOF" as this would cause the complete event to be generated too) */ + OS_close(State->Fd); + State->Fd = OS_OBJECT_ID_UNDEFINED; + + /* generate write error event */ + Meta->OnEvent(Meta, CFE_FS_FileWriteEvent_RECORD_WRITE_ERROR, Status, State->RecordNum, RecordSize, State->FileSize); + break; + } + else + { + State->FileSize += RecordSize; + } + } + + ++State->RecordNum; + + } /* end if */ + + /* On normal EOF close the file and generate the complete event */ + if (IsEOF) + { + OS_close(State->Fd); + State->Fd = OS_OBJECT_ID_UNDEFINED; + + /* generate complete event */ + Meta->OnEvent(Meta, CFE_FS_FileWriteEvent_COMPLETE, CFE_SUCCESS, State->RecordNum, 0, State->FileSize); + } + + /* + * if the file is not open, consider this file complete, and advance the head position. + * (done this way so it also catches the case where the file failed to create, not just EOF) + */ + if (!OS_ObjectIdDefined(State->Fd)) + { + CFE_FS_LockSharedData(__func__); + + /* Wipe the entry structure, as it will be reused */ + memset(Curr, 0, sizeof(*Curr)); + ++CFE_FS_Global.FileDump.CompleteCount; + + /* Set the "IsPending" flag to false - this indicates that the originator may re-post now */ + Meta->IsPending = false; + + CFE_FS_UnlockSharedData(__func__); + + } /* end if */ + + return !IsEOF; +} + +/* +** CFE_FS_BackgroundFileDumpRequest - See API and header file for details +*/ +int32 CFE_FS_BackgroundFileDumpRequest(CFE_FS_FileWriteMetaData_t *Meta) +{ + CFE_FS_BackgroundFileDumpEntry_t *Curr; + int32 Status; + uint32 PendingRequestCount; + + /* Pre-validate inputs */ + if (Meta == NULL) + { + return CFE_FS_BAD_ARGUMENT; + } + + /* getter and event functions must be set */ + if (Meta->GetData == NULL || Meta->OnEvent == NULL) + { + return CFE_FS_BAD_ARGUMENT; + } + + /* filename cannot be empty */ + if (Meta->FileName[0] == 0) + { + return CFE_FS_INVALID_PATH; + } + + /* request must not already be pending */ + if (Meta->IsPending) + { + return CFE_STATUS_REQUEST_ALREADY_PENDING; + } + + + CFE_FS_LockSharedData(__func__); + + PendingRequestCount = CFE_FS_Global.FileDump.RequestCount + 1; + + /* Check if queue is full before writing to tail position */ + if (PendingRequestCount == (CFE_FS_Global.FileDump.CompleteCount + CFE_FS_MAX_BACKGROUND_FILE_WRITES)) + { + Status = CFE_STATUS_REQUEST_ALREADY_PENDING; + } + else + { + Curr = &CFE_FS_Global.FileDump.Entries[CFE_FS_Global.FileDump.RequestCount & (CFE_FS_MAX_BACKGROUND_FILE_WRITES - 1)]; + + /* + * store the meta object - note this retains the pointer that was submitted + * (caller must not reuse/change this object until request is completed) + */ + Curr->Meta = Meta; + + /* + * The "IsPending" Flag will be set true whenever while this is waiting in the request queue. + * It will be set false when the file is done. + * + * The requester can check this flag to determine if/when the request is complete + */ + Meta->IsPending = true; + + /* update tail position */ + CFE_FS_Global.FileDump.RequestCount = PendingRequestCount; + + Status = CFE_SUCCESS; + } + + CFE_FS_UnlockSharedData(__func__); + + if (Status == CFE_SUCCESS) + { + /* + * If successfully added to write queue, then wake the ES background task to get started. + * + * This may reduce the overall latency between request and completion (depending on other + * background task work). If this is the only pending job, this should get it started faster. + */ + CFE_ES_BackgroundWakeup(); + } + + return Status; +} + +/* +** CFE_FS_ExtractFilenameFromPath - See API and header file for details +*/ +bool CFE_FS_BackgroundFileDumpIsPending(const CFE_FS_FileWriteMetaData_t *Meta) +{ + if (Meta == NULL) + { + return false; + } + + return Meta->IsPending; +} /************************/ /* End of File Comment */ diff --git a/fsw/cfe-core/src/fs/cfe_fs_priv.h b/fsw/cfe-core/src/fs/cfe_fs_priv.h index c4772bad5..c2826b466 100644 --- a/fsw/cfe-core/src/fs/cfe_fs_priv.h +++ b/fsw/cfe-core/src/fs/cfe_fs_priv.h @@ -44,11 +44,93 @@ ** Macro Definitions */ +/* + * Max Number of file write requests that can be queued + * + * This needs to be a power of two to simplify the masking/wraparound (bitwise AND). + */ +#define CFE_FS_MAX_BACKGROUND_FILE_WRITES 4 + + +/* + * Background file credit accumulation rate + * + * The background file writer will limit the total bytes written over time. This + * controls the amount of "credit" (bytes that can be written) per second + * of elapsed time. + * + * This permits a file writing rate of up to 10kbytes/sec. + */ +#define CFE_FS_BACKGROUND_CREDIT_PER_SECOND 10000 + +/* + * Maximum credit that the background write task can accumulate + * + * The background file writer will limit the total bytes written over time, and + * will accumulate credit against this limit while no writes are in progress. + * This is an upper cap on the amount of credit that can be accumulated. + * + * Without this limit, after a long period of inactivity without any file + * writes, a large credit would essentially bypass the rate limiting for + * the next file write command(s) once they are issued. + */ +#define CFE_FS_BACKGROUND_MAX_CREDIT 10000 /* ** Type Definitions */ +/* + * Background file dump entry structure + * + * This structure is stored in global memory and keeps the state + * of the file dump from one iteration to the next. + */ +typedef struct +{ + CFE_ES_AppId_t RequestorAppId; + CFE_FS_FileWriteMetaData_t *Meta; +} CFE_FS_BackgroundFileDumpEntry_t; + +typedef struct +{ + osal_id_t Fd; + int32 Credit; + uint32 RecordNum; + size_t FileSize; +} CFE_FS_CurrentFileState_t; + + +/** + * \brief Background file dump queue structure + * + * This structure is stored in global memory and keeps the state + * of the file dump from one iteration to the next. + * + * Normally when idle the "RequestCount" and "CompleteCount" are the + * same value. When an application requests a background file dump, + * the "RequestCount" is incremented accordingly, and when the background + * job finishes, the "CompleteCount" is incremented accordingly. + */ +typedef struct +{ + uint32 RequestCount; /**< Total Number of background file writes requested */ + uint32 CompleteCount; /**< Total Number of background file writes completed */ + + /** + * Data related to each background file write request + */ + CFE_FS_BackgroundFileDumpEntry_t Entries[CFE_FS_MAX_BACKGROUND_FILE_WRITES]; + + /** + * Persistent storage for the current file write + * (reused for each file) + */ + CFE_FS_CurrentFileState_t Current; + +} CFE_FS_BackgroundFileDumpState_t; + + /****************************************************************************** ** Typedef: CFE_FS_Global_t ** @@ -59,8 +141,13 @@ typedef struct { osal_id_t SharedDataMutexId; + CFE_FS_BackgroundFileDumpState_t FileDump; + } CFE_FS_Global_t; + +extern CFE_FS_Global_t CFE_FS_Global; + /* ** FS Function Prototypes */ diff --git a/fsw/cfe-core/src/inc/cfe_error.h b/fsw/cfe-core/src/inc/cfe_error.h index 872c89f03..98b82dc26 100644 --- a/fsw/cfe-core/src/inc/cfe_error.h +++ b/fsw/cfe-core/src/inc/cfe_error.h @@ -172,6 +172,15 @@ typedef int32 CFE_Status_t; */ #define CFE_STATUS_EXTERNAL_RESOURCE_FAIL ((int32)0xc8000005) +/** + * @brief Request already pending + * + * Commands or requests are already pending or the pending request + * limit has been reached. No more requests can be made until + * the current request(s) complete. + */ +#define CFE_STATUS_REQUEST_ALREADY_PENDING ((int32)0xc8000006) + /** * @brief Not Implemented * diff --git a/fsw/cfe-core/src/inc/cfe_es.h b/fsw/cfe-core/src/inc/cfe_es.h index 499fe397f..2837aaf05 100644 --- a/fsw/cfe-core/src/inc/cfe_es.h +++ b/fsw/cfe-core/src/inc/cfe_es.h @@ -1105,6 +1105,26 @@ void CFE_ES_ExitChildTask(void); * @{ */ +/*****************************************************************************/ +/** +** \brief Wakes up the CFE background task +** +** \par Description +** Normally the ES background task wakes up at a periodic interval. +** Whenever new background work is added, this can be used to wake the task early, +** which may reduce the delay between adding the job and the job getting processed. +** +** \par Assumptions, External Events, and Notes: +** Note the amount of work that the background task will perform is pro-rated +** based on the amount of time elapsed since the last wakeup. Waking the task +** early will not cause the background task to do more work than it otherwise +** would - it just reduces the delay before work starts initially. +** +** +******************************************************************************/ +void CFE_ES_BackgroundWakeup(void); + + /*****************************************************************************/ /** ** \brief Write a string to the cFE System Log diff --git a/fsw/cfe-core/src/inc/cfe_fs.h b/fsw/cfe-core/src/inc/cfe_fs.h index d6230ab77..91d4b98af 100644 --- a/fsw/cfe-core/src/inc/cfe_fs.h +++ b/fsw/cfe-core/src/inc/cfe_fs.h @@ -42,6 +42,66 @@ #include "common_types.h" #include "cfe_time.h" +/* + * Because FS is a library not an app, it does not have its own context or + * event IDs. The file writer runs in the context of the ES background task + * on behalf of whatever App requested the file write. + * + * This is a list of abstract events associated with background file write jobs. + * An app requesting the file write must supply a callback function to translate + * these into its own event IDs for feedback (i.e. file complete, error conditions, etc). + */ +typedef enum +{ + CFE_FS_FileWriteEvent_UNDEFINED, /* placeholder, no-op, keep as 0 */ + + CFE_FS_FileWriteEvent_COMPLETE, /**< File is completed successfully */ + CFE_FS_FileWriteEvent_CREATE_ERROR, /**< Unable to create/open file */ + CFE_FS_FileWriteEvent_HEADER_WRITE_ERROR, /**< Unable to write FS header */ + CFE_FS_FileWriteEvent_RECORD_WRITE_ERROR, /**< Unable to write data record */ + + CFE_FS_FileWriteEvent_MAX /* placeholder, no-op, keep last */ + +} CFE_FS_FileWriteEvent_t; + + +/** + * Data Getter routine provided by requester + * + * Outputs a data block. Should return true if the file is complete (last record/EOF), otherwise return false. + */ +typedef bool (*CFE_FS_FileWriteGetData_t)(void *Meta, uint32 RecordNum, void **Buffer, size_t *BufSize); + +/** + * Event generator routine provided by requester + * + * Invoked from certain points in the file write process. Implementation may invoke CFE_EVS_SendEvent() appropriately + * to inform of progress. + */ +typedef void (*CFE_FS_FileWriteOnEvent_t)(void *Meta, CFE_FS_FileWriteEvent_t Event, int32 Status, uint32 RecordNum, size_t BlockSize, size_t Position); + +/** + * \brief External Metadata/State object associated with background file writes + * + * Applications intending to schedule background file write jobs should instantiate + * this object in static/global data memory. This keeps track of the state of the + * file write request(s). + */ +typedef struct CFE_FS_FileWriteMetaData +{ + volatile bool IsPending; /**< Whether request is pending (volatile as it may be checked outside lock) */ + + char FileName[OS_MAX_PATH_LEN]; /**< Name of file to write */ + + /* Data for FS header */ + uint32 FileSubType; /**< Type of file to write (for FS header) */ + char Description[CFE_FS_HDR_DESC_MAX_LEN]; /**< Description of file (for FS header) */ + + CFE_FS_FileWriteGetData_t GetData; /**< Application callback to get a data record */ + CFE_FS_FileWriteOnEvent_t OnEvent; /**< Application callback for abstract event processing */ + +} CFE_FS_FileWriteMetaData_t; + /** @defgroup CFEAPIFSHeader cFE File Header Management APIs * @{ @@ -183,6 +243,63 @@ CFE_Status_t CFE_FS_SetTimestamp(osal_id_t FileDes, CFE_TIME_SysTime_t NewTimest ** ******************************************************************************/ CFE_Status_t CFE_FS_ExtractFilenameFromPath(const char *OriginalPath, char *FileNameOnly); + +/*****************************************************************************/ +/** +** \brief Register a background file dump request +** +** \par Description +** Puts the previously-initialized metadata into the pending request queue +** +** \par Assumptions, External Events, and Notes: +** Metadata structure should be stored in a static memory area (not on heap) as it +** must persist and be accessible by the file writer task throughout the asynchronous +** job operation. +** +** \param[inout] Meta The background file write persistent state object +** +** \return Execution status, see \ref CFEReturnCodes +** +******************************************************************************/ +int32 CFE_FS_BackgroundFileDumpRequest(CFE_FS_FileWriteMetaData_t *Meta); + +/*****************************************************************************/ +/** +** \brief Query if a background file write request is currently pending +** +** \par Description +** This returns "true" while the request is on the background work queue +** This returns "false" once the request is complete and removed from the queue. +** +** \par Assumptions, External Events, and Notes: +** None +** +** \param[inout] Meta The background file write persistent state object +** +** \return true if request is already pending, false if not +** +******************************************************************************/ +bool CFE_FS_BackgroundFileDumpIsPending(const CFE_FS_FileWriteMetaData_t *Meta); + +/*****************************************************************************/ +/** +** \brief Execute the background file write job(s) +** +** \par Description +** Runs the state machine associated with background file write requests +** +** \par Assumptions, External Events, and Notes: +** This should only be invoked as a background job from the ES background task, +** it should not be invoked directly. +** +** \param[in] ElapsedTime The amount of time passed since last invocation (ms) +** \param[in] Arg Not used/ignored +** +** \return true if jobs are pending, false if idle +** +******************************************************************************/ +bool CFE_FS_RunBackgroundFileDump(uint32 ElapsedTime, void *Arg); + /**@}*/ #endif /* _cfe_fs_ */ diff --git a/fsw/cfe-core/src/inc/cfe_sb_msg.h b/fsw/cfe-core/src/inc/cfe_sb_msg.h index a9ed6f0e5..e504f4b37 100644 --- a/fsw/cfe-core/src/inc/cfe_sb_msg.h +++ b/fsw/cfe-core/src/inc/cfe_sb_msg.h @@ -591,11 +591,11 @@ typedef struct CFE_SB_PipeDepthStats { CFE_SB_PipeId_t PipeId;/**< \cfetlmmnemonic \SB_PDPIPEID \brief Pipe Id associated with the stats below */ - uint16 Depth;/**< \cfetlmmnemonic \SB_PDDEPTH + uint16 MaxQueueDepth;/**< \cfetlmmnemonic \SB_PDDEPTH \brief Number of messages the pipe can hold */ - uint16 InUse;/**< \cfetlmmnemonic \SB_PDINUSE + uint16 CurrentQueueDepth;/**< \cfetlmmnemonic \SB_PDINUSE \brief Number of messages currently on the pipe */ - uint16 PeakInUse;/**< \cfetlmmnemonic \SB_PDPKINUSE + uint16 PeakQueueDepth;/**< \cfetlmmnemonic \SB_PDPKINUSE \brief Peak number of messages that have been on the pipe */ uint16 Spare;/**< \cfetlmmnemonic \SB_PDSPARE \brief Spare word to ensure alignment */ diff --git a/fsw/cfe-core/src/sb/cfe_sb_api.c b/fsw/cfe-core/src/sb/cfe_sb_api.c index 772a84e53..8a1b33a98 100644 --- a/fsw/cfe-core/src/sb/cfe_sb_api.c +++ b/fsw/cfe-core/src/sb/cfe_sb_api.c @@ -194,9 +194,9 @@ int32 CFE_SB_CreatePipe(CFE_SB_PipeId_t *PipeIdPtr, uint16 Depth, const char * if (Status == CFE_SUCCESS) { /* fill in the pipe table fields */ - PipeDscPtr->SysQueueId = SysQueueId; - PipeDscPtr->QueueDepth = Depth; - PipeDscPtr->AppId = AppId; + PipeDscPtr->SysQueueId = SysQueueId; + PipeDscPtr->MaxQueueDepth = Depth; + PipeDscPtr->AppId = AppId; CFE_SB_PipeDescSetUsed(PipeDscPtr, PendingPipeId); @@ -1692,10 +1692,10 @@ int32 CFE_SB_TransmitBufferFull(CFE_SB_BufferD_t *BufDscPtr, DestPtr->BuffCount++; /* used for checking MsgId2PipeLimit */ DestPtr->DestCnt++; /* used for statistics */ - ++PipeDscPtr->QueueDepth; - if (PipeDscPtr->QueueDepth >= PipeDscPtr->PeakDepth) + ++PipeDscPtr->CurrentQueueDepth; + if (PipeDscPtr->CurrentQueueDepth >= PipeDscPtr->PeakQueueDepth) { - PipeDscPtr->PeakDepth = PipeDscPtr->QueueDepth; + PipeDscPtr->PeakQueueDepth = PipeDscPtr->CurrentQueueDepth; } Status = CFE_SUCCESS; @@ -2001,9 +2001,9 @@ int32 CFE_SB_ReceiveBuffer(CFE_SB_Buffer_t **BufPtr, DestPtr->BuffCount--; } - if (PipeDscPtr->CurrentDepth > 0) + if (PipeDscPtr->CurrentQueueDepth > 0) { - --PipeDscPtr->CurrentDepth; + --PipeDscPtr->CurrentQueueDepth; } } else diff --git a/fsw/cfe-core/src/sb/cfe_sb_priv.h b/fsw/cfe-core/src/sb/cfe_sb_priv.h index 23abe02ec..d01ab0b5d 100644 --- a/fsw/cfe-core/src/sb/cfe_sb_priv.h +++ b/fsw/cfe-core/src/sb/cfe_sb_priv.h @@ -149,10 +149,10 @@ typedef struct { uint8 Spare; CFE_ES_AppId_t AppId; osal_id_t SysQueueId; - uint16 QueueDepth; uint16 SendErrors; - uint16 CurrentDepth; - uint16 PeakDepth; + uint16 MaxQueueDepth; + uint16 CurrentQueueDepth; + uint16 PeakQueueDepth; CFE_SB_BufferD_t *LastBuffer; } CFE_SB_PipeD_t; @@ -169,6 +169,43 @@ typedef struct { } CFE_SB_MemParams_t; +/*******************************************************************************/ +/** +** \brief SB route info temporary structure +** +** This tracks the number of desinations along with destination data for 1 route. +** Each route may contain zero or more desinations (variable length). +*/ +typedef struct +{ + uint32 NumDestinations; + CFE_SB_RoutingFileEntry_t DestEntries[CFE_PLATFORM_SB_MAX_DEST_PER_PKT]; /**< Actual data written to file */ +} CFE_SB_BackgroundRouteInfoBuffer_t; + +/** + * \brief Temporary holding buffer for records being written to a file. + * + * This is shared/reused between all file types (msg map, route info, pipe info). + */ +typedef union +{ + CFE_SB_BackgroundRouteInfoBuffer_t RouteInfo; + CFE_SB_PipeInfoEntry_t PipeInfo; + CFE_SB_MsgMapFileEntry_t MsgMapInfo; +} CFE_SB_BackgroundFileBuffer_t; + +/** + * \brief SB Background file write state information + * + * Must be stored in persistent memory (e.g. global). + */ +typedef struct +{ + CFE_FS_FileWriteMetaData_t FileWrite; /**< FS state data - must be first */ + CFE_SB_BackgroundFileBuffer_t Buffer; /**< Temporary holding area for file record */ +} CFE_SB_BackgroundFileStateInfo_t; + + /****************************************************************************** ** Typedef: CFE_SB_Global_t @@ -192,6 +229,8 @@ typedef struct CFE_EVS_BinFilter_t EventFilters[CFE_SB_MAX_CFG_FILE_EVENTS_TO_FILTER]; CFE_SB_Qos_t Default_Qos; CFE_ResourceId_t LastPipeId; + + CFE_SB_BackgroundFileStateInfo_t BackgroundFile; } CFE_SB_Global_t; @@ -261,9 +300,6 @@ int32 CFE_SB_TransmitMsgValidate(CFE_MSG_Message_t *MsgPtr, CFE_SB_MsgId_t *MsgIdPtr, CFE_MSG_Size_t *SizePtr, CFE_SBR_RouteId_t *RouteIdPtr); -int32 CFE_SB_WriteRtgInfo(const char *Filename); -int32 CFE_SB_WritePipeInfo(const char *Filename); -int32 CFE_SB_WriteMapInfo(const char *Filename); int32 CFE_SB_ZeroCopyReleaseDesc(CFE_SB_Buffer_t *Ptr2Release, CFE_SB_ZeroCopyHandle_t BufferHandle); int32 CFE_SB_ZeroCopyReleaseAppId(CFE_ES_AppId_t AppId); void CFE_SB_IncrBufUseCnt(CFE_SB_BufferD_t *bd); @@ -271,7 +307,6 @@ void CFE_SB_DecrBufUseCnt(CFE_SB_BufferD_t *bd); int32 CFE_SB_ValidateMsgId(CFE_SB_MsgId_t MsgId); int32 CFE_SB_ValidatePipeId(CFE_SB_PipeId_t PipeId); void CFE_SB_IncrCmdCtr(int32 status); -void CFE_SB_FileWriteByteCntErr(const char *Filename,uint32 Requested,uint32 Actual); void CFE_SB_SetSubscriptionReporting(uint32 state); int32 CFE_SB_SendSubscriptionReport(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId, CFE_SB_Qos_t Quality); uint32 CFE_SB_RequestToSendEvent(CFE_ES_TaskId_t TaskId, uint32 Bit); @@ -470,6 +505,16 @@ static inline bool CFE_SB_PipeDescIsMatch(const CFE_SB_PipeD_t *PipeDscPtr, CFE_ bool CFE_SB_CheckPipeDescSlotUsed(CFE_ResourceId_t CheckId); +/* + * Helper functions for background file write requests (callbacks) + */ +void CFE_SB_CollectMsgMapInfo(CFE_SBR_RouteId_t RouteId, void *ArgPtr); +bool CFE_SB_WriteMsgMapInfoDataGetter(void *Meta, uint32 RecordNum, void **Buffer, size_t *BufSize); +void CFE_SB_CollectRouteInfo(CFE_SBR_RouteId_t RouteId, void *ArgPtr); +bool CFE_SB_WriteRouteInfoDataGetter(void *Meta, uint32 RecordNum, void **Buffer, size_t *BufSize); +bool CFE_SB_WritePipeInfoDataGetter(void *Meta, uint32 RecordNum, void **Buffer, size_t *BufSize); +void CFE_SB_BackgroundFileEventHandler(void *Meta, CFE_FS_FileWriteEvent_t Event, int32 Status, uint32 RecordNum, size_t BlockSize, size_t Position); + /* * External variables private to the software bus module */ diff --git a/fsw/cfe-core/src/sb/cfe_sb_task.c b/fsw/cfe-core/src/sb/cfe_sb_task.c index 623b5d205..5c24e5fe6 100644 --- a/fsw/cfe-core/src/sb/cfe_sb_task.c +++ b/fsw/cfe-core/src/sb/cfe_sb_task.c @@ -806,9 +806,11 @@ int32 CFE_SB_SendStatsCmd(const CFE_SB_SendSbStatsCmd_t *data) if (CFE_SB_PipeDescIsUsed(PipeDscPtr)) { PipeStatPtr->PipeId = PipeDscPtr->PipeId; - PipeStatPtr->InUse = PipeDscPtr->CurrentDepth; - PipeStatPtr->PeakInUse = PipeDscPtr->PeakDepth; - PipeStatPtr->Depth = PipeDscPtr->QueueDepth; + + /* Copy depth info */ + PipeStatPtr->CurrentQueueDepth = PipeDscPtr->CurrentQueueDepth; + PipeStatPtr->PeakQueueDepth = PipeDscPtr->PeakQueueDepth; + PipeStatPtr->MaxQueueDepth = PipeDscPtr->MaxQueueDepth; ++PipeStatPtr; --PipeStatCount; @@ -839,156 +841,79 @@ int32 CFE_SB_SendStatsCmd(const CFE_SB_SendSbStatsCmd_t *data) return CFE_SUCCESS; }/* CFE_SB_SendStatsCmd */ - -/****************************************************************************** - * \brief SB internal function to handle processing of 'Write Routing Info' Cmd - * - * \param[in] data Pointer to command structure - * - * \return Execution status, see \ref CFEReturnCodes - */ -int32 CFE_SB_WriteRoutingInfoCmd(const CFE_SB_WriteRoutingInfoCmd_t *data) -{ - char LocalFilename[OS_MAX_PATH_LEN]; - int32 Stat; - - CFE_SB_MessageStringGet(LocalFilename, data->Payload.Filename, CFE_PLATFORM_SB_DEFAULT_ROUTING_FILENAME, - sizeof(LocalFilename), sizeof(data->Payload.Filename)); - - Stat = CFE_SB_WriteRtgInfo(LocalFilename); - CFE_SB_IncrCmdCtr(Stat); - - return CFE_SUCCESS; -} - - -/****************************************************************************** - * \brief SB internal function to handle processing of 'Write Pipe Info' Cmd - * - * \param[in] data Pointer to command structure - * - * \return Execution status, see \ref CFEReturnCodes - */ -int32 CFE_SB_WritePipeInfoCmd(const CFE_SB_WritePipeInfoCmd_t *data) -{ - char LocalFilename[OS_MAX_PATH_LEN]; - int32 Stat; - - CFE_SB_MessageStringGet(LocalFilename, data->Payload.Filename, CFE_PLATFORM_SB_DEFAULT_PIPE_FILENAME, - sizeof(LocalFilename), sizeof(data->Payload.Filename)); - - Stat = CFE_SB_WritePipeInfo(LocalFilename); - CFE_SB_IncrCmdCtr(Stat); - - return CFE_SUCCESS; -} - - -/****************************************************************************** - * \brief SB internal function to handle processing of 'Write Map Info' Cmd - * - * \param[in] data Pointer to command structure - * - * \return Execution status, see \ref CFEReturnCodes - */ -int32 CFE_SB_WriteMapInfoCmd(const CFE_SB_WriteMapInfoCmd_t *data) -{ - char LocalFilename[OS_MAX_PATH_LEN]; - int32 Stat; - - CFE_SB_MessageStringGet(LocalFilename, data->Payload.Filename, CFE_PLATFORM_SB_DEFAULT_MAP_FILENAME, - sizeof(LocalFilename), sizeof(data->Payload.Filename)); - - Stat = CFE_SB_WriteMapInfo(LocalFilename); - - CFE_SB_IncrCmdCtr(Stat); - - return CFE_SUCCESS; -} - /****************************************************************************** * Local callback helper for writing routing info to a file */ -void CFE_SB_WriteRouteToFile(CFE_SBR_RouteId_t RouteId, void *ArgPtr) +void CFE_SB_CollectRouteInfo(CFE_SBR_RouteId_t RouteId, void *ArgPtr) { - struct RouteInfo - { - CFE_SB_PipeId_t PipeId; - uint8 Active; - uint16 DestCnt; - }; - - CFE_SB_FileWriteCallback_t *args; - CFE_SB_DestinationD_t *destptr; - CFE_SB_PipeD_t *pipedptr; - int32 status; - CFE_SB_RoutingFileEntry_t entry; - struct RouteInfo RouteInfo[CFE_PLATFORM_SB_MAX_DEST_PER_PKT]; - struct RouteInfo *RouteInfoPtr; - uint32 NumDest; + CFE_SB_DestinationD_t *DestPtr; + CFE_SB_PipeD_t *PipeDscPtr; + CFE_SB_MsgId_t RouteMsgId; + CFE_SB_BackgroundRouteInfoBuffer_t *RouteBufferPtr; + CFE_SB_RoutingFileEntry_t *FileEntryPtr; + CFE_ES_AppId_t DestAppId[CFE_PLATFORM_SB_MAX_DEST_PER_PKT]; + uint32 i; /* Cast arguments for local use */ - args = (CFE_SB_FileWriteCallback_t *)ArgPtr; - - NumDest = 0; + RouteBufferPtr = (CFE_SB_BackgroundRouteInfoBuffer_t *)ArgPtr; + /* Extract data from runtime info, write into the temporary buffer */ /* Data must be locked to snapshot the route info */ CFE_SB_LockSharedData(__FILE__, __LINE__); - destptr = CFE_SBR_GetDestListHeadPtr(RouteId); - entry.MsgId = CFE_SBR_GetMsgId(RouteId); - RouteInfoPtr = RouteInfo; + RouteMsgId = CFE_SBR_GetMsgId(RouteId); + RouteBufferPtr->NumDestinations = 0; - while((destptr != NULL) && NumDest < CFE_PLATFORM_SB_MAX_DEST_PER_PKT) + /* If this is a valid route, get the destinations */ + if (CFE_SB_IsValidMsgId(RouteMsgId)) { - pipedptr = CFE_SB_LocatePipeDescByID(destptr->PipeId); + DestPtr = CFE_SBR_GetDestListHeadPtr(RouteId); - /* If invalid id, continue on to next entry */ - if (CFE_SB_PipeDescIsMatch(pipedptr,destptr->PipeId)) + /* copy relevant data from the destination list into the temp buffer */ + while(DestPtr != NULL && RouteBufferPtr->NumDestinations < CFE_PLATFORM_SB_MAX_DEST_PER_PKT) { - RouteInfoPtr->PipeId = destptr->PipeId; - RouteInfoPtr->Active = destptr->Active; - RouteInfoPtr->DestCnt = destptr->DestCnt; - ++RouteInfoPtr; - ++NumDest; - } + PipeDscPtr = CFE_SB_LocatePipeDescByID(DestPtr->PipeId); - destptr = destptr->Next; + /* If invalid id, continue on to next entry */ + if (CFE_SB_PipeDescIsMatch(PipeDscPtr,DestPtr->PipeId)) + { + FileEntryPtr = &RouteBufferPtr->DestEntries[RouteBufferPtr->NumDestinations]; + + /* clear all fields in the temp buffer before re-use */ + memset(FileEntryPtr, 0, sizeof(*FileEntryPtr)); + + FileEntryPtr->PipeId = DestPtr->PipeId; + FileEntryPtr->State = DestPtr->Active; + FileEntryPtr->MsgCnt = DestPtr->DestCnt; + + /* Stash the Pipe Owner AppId - App Name is looked up later (comes from ES) */ + DestAppId[RouteBufferPtr->NumDestinations] = PipeDscPtr->AppId; + + ++RouteBufferPtr->NumDestinations; + } + + DestPtr = DestPtr->Next; + } } CFE_SB_UnlockSharedData(__FILE__, __LINE__); - RouteInfoPtr = RouteInfo; - while (NumDest > 0) + /* Go through the temp buffer and fill in the remaining info for each dest */ + FileEntryPtr = RouteBufferPtr->DestEntries; + for(i = 0; i < RouteBufferPtr->NumDestinations; ++i) { - entry.PipeId = RouteInfoPtr->PipeId; - entry.State = RouteInfoPtr->Active; - entry.MsgCnt = RouteInfoPtr->DestCnt; - - entry.AppName[0] = 0; + /* All dest entries refer to the same MsgId (based on the route) */ + FileEntryPtr->MsgId = RouteMsgId; /* - * NOTE: as long as CFE_ES_GetAppName() returns success, then it - * guarantees null termination of the output. Return code is not - * checked here (bad) but in case of error it does not seem to touch - * the buffer, therefore the initialization above will protect for now + * NOTE: as long as CFE_ES_GetAppName() is given a nonzero-length + * output buffer, it guarantees null termination of the output, even + * if the AppID is invalid - in which case it returns an empty string. */ - CFE_ES_GetAppName(entry.AppName, pipedptr->AppId, sizeof(entry.AppName)); - CFE_SB_GetPipeName(entry.PipeName, sizeof(entry.PipeName), entry.PipeId); - - status = OS_write (args->Fd, &entry, sizeof(CFE_SB_RoutingFileEntry_t)); - if(status != sizeof(CFE_SB_RoutingFileEntry_t)) - { - CFE_SB_FileWriteByteCntErr(args->Filename, sizeof(CFE_SB_RoutingFileEntry_t), status); - OS_close(args->Fd); - args->Status = CFE_SB_FILE_IO_ERR; - } + CFE_ES_GetAppName(FileEntryPtr->AppName, DestAppId[i], sizeof(FileEntryPtr->AppName)); + CFE_SB_GetPipeName(FileEntryPtr->PipeName, sizeof(FileEntryPtr->PipeName), FileEntryPtr->PipeId); - args->FileSize += status; - args->EntryCount++; - - ++RouteInfoPtr; - --NumDest; + ++FileEntryPtr; } } @@ -1033,169 +958,257 @@ int32 CFE_SB_SendSubscriptionReport(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId return Status; } +bool CFE_SB_WriteRouteInfoDataGetter(void *Meta, uint32 RecordNum, void **Buffer, size_t *BufSize) +{ + CFE_SB_BackgroundFileStateInfo_t *BgFilePtr; + CFE_SBR_Throttle_t Throttle; + + /* Cast arguments for local use */ + BgFilePtr = (CFE_SB_BackgroundFileStateInfo_t *)Meta; + + Throttle.StartIndex = RecordNum; + Throttle.MaxLoop = 1; + Throttle.NextIndex = 0; + + /* Reset NumDestinations to 0, just in case the CFE_SBR_ForEachRouteId() is a no-op */ + BgFilePtr->Buffer.RouteInfo.NumDestinations = 0; + + /* Collect info on the next route (limited to one per cycle via throttle) */ + CFE_SBR_ForEachRouteId(CFE_SB_CollectRouteInfo, &BgFilePtr->Buffer.RouteInfo, &Throttle); + + /* Pass the output of CFE_SB_CollectRouteInfo() back to be written */ + *Buffer = &BgFilePtr->Buffer.RouteInfo.DestEntries; + *BufSize = sizeof(CFE_SB_RoutingFileEntry_t) * BgFilePtr->Buffer.RouteInfo.NumDestinations; + + /* Check for EOF (last entry) - NextIndex is nonzero if more records left, zero at the end of the route table */ + return (Throttle.NextIndex == 0); +} + +void CFE_SB_BackgroundFileEventHandler(void *Meta, CFE_FS_FileWriteEvent_t Event, int32 Status, uint32 RecordNum, size_t BlockSize, size_t Position) +{ + CFE_SB_BackgroundFileStateInfo_t *BgFilePtr; + + BgFilePtr = (CFE_SB_BackgroundFileStateInfo_t *)Meta; + + /* + * Note that this runs in the context of ES background task (file writer background job) + * It does NOT run in the context of the CFE_TBL app task. + * + * Events should use CFE_EVS_SendEventWithAppID() rather than CFE_EVS_SendEvent() + * to get proper association with TBL task. + */ + switch(Event) + { + case CFE_FS_FileWriteEvent_COMPLETE: + CFE_EVS_SendEventWithAppID(CFE_SB_SND_RTG_EID,CFE_EVS_EventType_DEBUG, + CFE_SB_Global.AppId, + "%s written:Size=%d,Entries=%d", + BgFilePtr->FileWrite.FileName, (int)Position, (int)RecordNum); + break; + + case CFE_FS_FileWriteEvent_HEADER_WRITE_ERROR: + case CFE_FS_FileWriteEvent_RECORD_WRITE_ERROR: + CFE_EVS_SendEventWithAppID(CFE_SB_FILEWRITE_ERR_EID,CFE_EVS_EventType_ERROR, + CFE_SB_Global.AppId, + "File write,byte cnt err,file %s,request=%d,actual=%d", + BgFilePtr->FileWrite.FileName, (int)BlockSize, (int)Status); + break; + + case CFE_FS_FileWriteEvent_CREATE_ERROR: + CFE_EVS_SendEventWithAppID(CFE_SB_SND_RTG_ERR1_EID, CFE_EVS_EventType_ERROR, + CFE_SB_Global.AppId, + "Error creating file %s, stat=0x%x", + BgFilePtr->FileWrite.FileName, (int)Status); + break; + + default: + /* unhandled event - ignore */ + break; + } +} /****************************************************************************** - * \brief SB internal function to write the routing information to a file + * \brief SB internal function to handle processing of 'Write Routing Info' Cmd * - * \param[in] Filename Pointer the file name to write + * \param[in] data Pointer to command structure * * \return Execution status, see \ref CFEReturnCodes - * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS - * \retval #CFE_SB_FILE_IO_ERR \copybrief CFE_SB_FILE_IO_ERR */ -int32 CFE_SB_WriteRtgInfo(const char *Filename) +int32 CFE_SB_WriteRoutingInfoCmd(const CFE_SB_WriteRoutingInfoCmd_t *data) { - CFE_SB_FileWriteCallback_t args = {0}; + const CFE_SB_WriteFileInfoCmd_Payload_t *CmdPtr; + CFE_SB_BackgroundFileStateInfo_t *StatePtr; int32 Status; - CFE_FS_Header_t FileHdr; - Status = OS_OpenCreate(&args.Fd, Filename, OS_FILE_FLAG_CREATE | OS_FILE_FLAG_TRUNCATE, OS_WRITE_ONLY); - if(Status < OS_SUCCESS) - { - CFE_EVS_SendEvent(CFE_SB_SND_RTG_ERR1_EID, CFE_EVS_EventType_ERROR, - "Error creating file %s, stat=0x%x", - Filename, (unsigned int)Status); - return CFE_SB_FILE_IO_ERR; - } - - /* clear out the cfe file header fields, then populate description and subtype */ - CFE_FS_InitHeader(&FileHdr, "SB Routing Information", CFE_FS_SubType_SB_ROUTEDATA); + StatePtr = &CFE_SB_Global.BackgroundFile; + CmdPtr = &data->Payload; - Status = CFE_FS_WriteHeader(args.Fd, &FileHdr); - if(Status != sizeof(CFE_FS_Header_t)) + /* If a routing info dump was already pending, do not overwrite the current request */ + if (!CFE_FS_BackgroundFileDumpIsPending(&StatePtr->FileWrite)) { - CFE_SB_FileWriteByteCntErr(Filename,sizeof(CFE_FS_Header_t),Status); - OS_close(args.Fd); - return CFE_SB_FILE_IO_ERR; - } + /* Reset the entire state object (just for good measure, ensure no stale data) */ + memset(StatePtr, 0, sizeof(*StatePtr)); - /* Initialize the reset of the nonzero callback argument elements */ - args.FileSize = Status; - args.Filename = Filename; + /* Copy the commanded filename into local buffer to ensure size limitation and to allow for modification */ + CFE_SB_MessageStringGet(StatePtr->FileWrite.FileName, CmdPtr->Filename, CFE_PLATFORM_SB_DEFAULT_ROUTING_FILENAME, + sizeof(StatePtr->FileWrite.FileName), sizeof(CmdPtr->Filename)); - /* Write route info to file */ - CFE_SBR_ForEachRouteId(CFE_SB_WriteRouteToFile, &args, NULL); + /* + * Fill out the remainder of meta data. + * This data is currently the same for every request + */ + StatePtr->FileWrite.FileSubType = CFE_FS_SubType_SB_ROUTEDATA; + snprintf(StatePtr->FileWrite.Description, sizeof(StatePtr->FileWrite.Description), "SB Routing Information"); - if (args.Status != 0) - { - return args.Status; + StatePtr->FileWrite.GetData = CFE_SB_WriteRouteInfoDataGetter; + StatePtr->FileWrite.OnEvent = CFE_SB_BackgroundFileEventHandler; + + Status = CFE_FS_BackgroundFileDumpRequest(&StatePtr->FileWrite); } else { - OS_close(args.Fd); - CFE_EVS_SendEvent(CFE_SB_SND_RTG_EID,CFE_EVS_EventType_DEBUG, - "%s written:Size=%d,Entries=%d", - Filename, (int)args.FileSize, (int)args.EntryCount); - return CFE_SUCCESS; + Status = CFE_STATUS_REQUEST_ALREADY_PENDING; } - -} + + if (Status != CFE_SUCCESS) + { + /* generate the same event as is generated when unable to create the file (same thing, really) */ + CFE_SB_BackgroundFileEventHandler(StatePtr, CFE_FS_FileWriteEvent_CREATE_ERROR, Status, 0, 0, 0); + } + + CFE_SB_IncrCmdCtr(Status); + + return CFE_SUCCESS; +}/* end CFE_SB_WriteRoutingInfoCmd */ -/****************************************************************************** - * \brief SB internal function to write the Pipe table to a file - * - * \param[in] Filename Pointer the file name to write - * - * \return Execution status, see \ref CFEReturnCodes - * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS - * \retval #CFE_SB_FILE_IO_ERR \copybrief CFE_SB_FILE_IO_ERR - */ -int32 CFE_SB_WritePipeInfo(const char *Filename) +bool CFE_SB_WritePipeInfoDataGetter(void *Meta, uint32 RecordNum, void **Buffer, size_t *BufSize) { - uint16 i; - osal_id_t fd; - int32 Status; - uint32 FileSize = 0; - uint32 EntryCount = 0; - CFE_FS_Header_t FileHdr; + CFE_SB_BackgroundFileStateInfo_t *BgFilePtr; + CFE_SB_PipeInfoEntry_t *PipeBufferPtr; CFE_SB_PipeD_t *PipeDscPtr; - CFE_SB_PipeInfoEntry_t FileEntry; osal_id_t SysQueueId; + bool PipeIsValid; - Status = OS_OpenCreate(&fd, Filename, OS_FILE_FLAG_CREATE | OS_FILE_FLAG_TRUNCATE, OS_WRITE_ONLY); + BgFilePtr = (CFE_SB_BackgroundFileStateInfo_t *)Meta; + PipeDscPtr = NULL; + PipeIsValid = false; - if(Status < OS_SUCCESS){ - CFE_EVS_SendEvent(CFE_SB_SND_RTG_ERR1_EID,CFE_EVS_EventType_ERROR, - "Error creating file %s, stat=0x%x", - Filename,(unsigned int)Status); - return CFE_SB_FILE_IO_ERR; - }/* end if */ + PipeBufferPtr = &BgFilePtr->Buffer.PipeInfo; - /* clear out the cfe file header fields, then populate description and subtype */ - CFE_FS_InitHeader(&FileHdr, "SB Pipe Information", CFE_FS_SubType_SB_PIPEDATA); - - Status = CFE_FS_WriteHeader(fd, &FileHdr); - if(Status != sizeof(CFE_FS_Header_t)){ - CFE_SB_FileWriteByteCntErr(Filename,sizeof(CFE_FS_Header_t),Status); - OS_close(fd); - return CFE_SB_FILE_IO_ERR; - }/* end if */ + if (RecordNum < CFE_PLATFORM_SB_MAX_PIPES) + { + PipeDscPtr = &CFE_SB_Global.PipeTbl[RecordNum]; - FileSize = Status; + CFE_SB_LockSharedData(__FILE__,__LINE__); - /* loop through the pipe table */ - CFE_SB_LockSharedData(__FILE__,__LINE__); - PipeDscPtr = CFE_SB_Global.PipeTbl; + PipeIsValid = CFE_SB_PipeDescIsUsed(PipeDscPtr); - for (i=0;iAppId; - FileEntry.MaxQueueDepth = PipeDscPtr->QueueDepth; - FileEntry.CurrentQueueDepth = PipeDscPtr->CurrentDepth; - FileEntry.PeakQueueDepth = PipeDscPtr->PeakDepth; - FileEntry.SendErrors = PipeDscPtr->SendErrors; - FileEntry.Opts = PipeDscPtr->Opts; + PipeBufferPtr->PipeId = CFE_SB_PipeDescGetID(PipeDscPtr); + PipeBufferPtr->AppId = PipeDscPtr->AppId; + PipeBufferPtr->Opts = PipeDscPtr->Opts; + + /* copy stats info */ + PipeBufferPtr->SendErrors = PipeDscPtr->SendErrors; + PipeBufferPtr->MaxQueueDepth = PipeDscPtr->MaxQueueDepth; + PipeBufferPtr->CurrentQueueDepth = PipeDscPtr->CurrentQueueDepth; + PipeBufferPtr->PeakQueueDepth = PipeDscPtr->PeakQueueDepth; + SysQueueId = PipeDscPtr->SysQueueId; + } + else + { + SysQueueId = OS_OBJECT_ID_UNDEFINED; + } + + CFE_SB_UnlockSharedData(__FILE__,__LINE__); + } - CFE_SB_UnlockSharedData(__FILE__,__LINE__); + if (PipeIsValid) + { + /* + * Gather data from other subsystems while unlocked. + * This might fail if the pipe is deleted simultaneously while this runs, but in + * the unlikely event that happens, the name data will simply be blank as the ID(s) + * will not validate. + */ + OS_GetResourceName(SysQueueId, PipeBufferPtr->PipeName, sizeof(PipeBufferPtr->PipeName)); + CFE_ES_GetAppName(PipeBufferPtr->AppName, PipeBufferPtr->AppId, sizeof(PipeBufferPtr->AppName)); - /* - * Gather data from other subsystems while unlocked. - * This might fail if the pipe is deleted simultaneously while this runs, but in - * the unlikely event that happens, the name data will simply be blank as the ID(s) - * will not validate. - */ - OS_GetResourceName(SysQueueId, FileEntry.PipeName, sizeof(FileEntry.PipeName)); - CFE_ES_GetAppName(FileEntry.AppName, FileEntry.AppId, sizeof(FileEntry.AppName)); + *Buffer = PipeBufferPtr; + *BufSize = sizeof(*PipeBufferPtr); + } + else + { + *Buffer = NULL; + *BufSize = 0; + } + + /* Check for EOF (last entry) */ + return (RecordNum >= (CFE_PLATFORM_SB_MAX_PIPES-1)); +} - Status = OS_write (fd, &FileEntry, sizeof(FileEntry)); - if (Status != sizeof(FileEntry)) - { - CFE_SB_FileWriteByteCntErr(Filename,sizeof(FileEntry),Status); - OS_close(fd); - return CFE_SB_FILE_IO_ERR; - }/* end if */ - FileSize += Status; - EntryCount ++; +/****************************************************************************** + * \brief SB internal function to handle processing of 'Write Pipe Info' Cmd + * + * \param[in] data Pointer to command structure + * + * \return Execution status, see \ref CFEReturnCodes + */ +int32 CFE_SB_WritePipeInfoCmd(const CFE_SB_WritePipeInfoCmd_t *data) +{ + const CFE_SB_WriteFileInfoCmd_Payload_t *CmdPtr; + CFE_SB_BackgroundFileStateInfo_t *StatePtr; + int32 Status; - CFE_SB_LockSharedData(__FILE__,__LINE__); + StatePtr = &CFE_SB_Global.BackgroundFile; + CmdPtr = &data->Payload; - }/* end if */ + /* If a pipe info dump was already pending, do not overwrite the current request */ + if (!CFE_FS_BackgroundFileDumpIsPending(&StatePtr->FileWrite)) + { + /* Reset the entire state object (just for good measure, ensure no stale data) */ + memset(StatePtr, 0, sizeof(*StatePtr)); - ++PipeDscPtr; + /* Copy the commanded filename into local buffer to ensure size limitation and to allow for modification */ + CFE_SB_MessageStringGet(StatePtr->FileWrite.FileName, CmdPtr->Filename, CFE_PLATFORM_SB_DEFAULT_PIPE_FILENAME, + sizeof(StatePtr->FileWrite.FileName), sizeof(CmdPtr->Filename)); - }/* end for */ + /* + * Fill out the remainder of meta data. + * This data is currently the same for every request + */ + StatePtr->FileWrite.FileSubType = CFE_FS_SubType_SB_PIPEDATA; + snprintf(StatePtr->FileWrite.Description, sizeof(StatePtr->FileWrite.Description), "SB Pipe Information"); - CFE_SB_UnlockSharedData(__FILE__,__LINE__); + StatePtr->FileWrite.GetData = CFE_SB_WritePipeInfoDataGetter; + StatePtr->FileWrite.OnEvent = CFE_SB_BackgroundFileEventHandler; - OS_close(fd); + Status = CFE_FS_BackgroundFileDumpRequest(&StatePtr->FileWrite); + } + else + { + Status = CFE_STATUS_REQUEST_ALREADY_PENDING; + } + + if (Status != CFE_SUCCESS) + { + /* generate the same event as is generated when unable to create the file (same thing, really) */ + CFE_SB_BackgroundFileEventHandler(StatePtr, CFE_FS_FileWriteEvent_CREATE_ERROR, Status, 0, 0, 0); + } - CFE_EVS_SendEvent(CFE_SB_SND_RTG_EID,CFE_EVS_EventType_DEBUG, - "%s written:Size=%d,Entries=%d", - Filename,(int)FileSize,(int)EntryCount); + CFE_SB_IncrCmdCtr(Status); return CFE_SUCCESS; @@ -1204,91 +1217,112 @@ int32 CFE_SB_WritePipeInfo(const char *Filename) /****************************************************************************** * Local callback helper for writing map info to a file */ -void CFE_SB_WriteMapToFile(CFE_SBR_RouteId_t RouteId, void *ArgPtr) +void CFE_SB_CollectMsgMapInfo(CFE_SBR_RouteId_t RouteId, void *ArgPtr) { - CFE_SB_FileWriteCallback_t *args; - int32 status; - CFE_SB_MsgMapFileEntry_t entry; + CFE_SB_MsgMapFileEntry_t *BufferPtr; /* Cast arguments for local use */ - args = (CFE_SB_FileWriteCallback_t *)ArgPtr; + BufferPtr = (CFE_SB_MsgMapFileEntry_t *)ArgPtr; - if(args->Status != CFE_SB_FILE_IO_ERR) - { - CFE_SB_LockSharedData(__FILE__,__LINE__); - entry.MsgId = CFE_SBR_GetMsgId(RouteId); - entry.Index = CFE_SBR_RouteIdToValue(RouteId); - CFE_SB_UnlockSharedData(__FILE__,__LINE__); + /* Extract data from runtime info, write into the temporary buffer */ + /* Data must be locked to snapshot the route info */ + CFE_SB_LockSharedData(__FILE__, __LINE__); - status = OS_write (args->Fd, &entry, sizeof(CFE_SB_MsgMapFileEntry_t)); - if(status != sizeof(CFE_SB_MsgMapFileEntry_t)) - { - CFE_SB_FileWriteByteCntErr(args->Filename, sizeof(CFE_SB_MsgMapFileEntry_t), status); - OS_close(args->Fd); - args->Status = CFE_SB_FILE_IO_ERR; - } + BufferPtr->MsgId = CFE_SBR_GetMsgId(RouteId); + BufferPtr->Index = CFE_SBR_RouteIdToValue(RouteId); + + CFE_SB_UnlockSharedData(__FILE__,__LINE__); +} + + +bool CFE_SB_WriteMsgMapInfoDataGetter(void *Meta, uint32 RecordNum, void **Buffer, size_t *BufSize) +{ + CFE_SB_BackgroundFileStateInfo_t *BgFilePtr; + CFE_SBR_Throttle_t Throttle; + + /* Cast arguments for local use */ + BgFilePtr = (CFE_SB_BackgroundFileStateInfo_t *)Meta; + + Throttle.StartIndex = RecordNum; + Throttle.MaxLoop = 1; + Throttle.NextIndex = 0; + + /* Set the MsgId intially - will be overwritten with real info in CFE_SB_CollectMsgMapInfo */ + BgFilePtr->Buffer.MsgMapInfo.MsgId = CFE_SB_INVALID_MSG_ID; - args->FileSize += status; - args->EntryCount++; + /* Collect info on the next route (limited to one per cycle via throttle) */ + CFE_SBR_ForEachRouteId(CFE_SB_CollectMsgMapInfo, &BgFilePtr->Buffer.MsgMapInfo, &Throttle); + + /* If Map was valid, pass the output of CFE_SB_CollectMsgMapInfo() back to be written */ + if (CFE_SB_IsValidMsgId(BgFilePtr->Buffer.MsgMapInfo.MsgId)) + { + *Buffer = &BgFilePtr->Buffer.MsgMapInfo; + *BufSize = sizeof(CFE_SB_MsgMapFileEntry_t); } + else + { + *Buffer = NULL; + *BufSize = 0; + } + + /* Check for EOF (last entry) - NextIndex is nonzero if more records left, zero at the end of the route table */ + return (Throttle.NextIndex == 0); } + /****************************************************************************** - * \brief SB internal function to write the Message Map to a file + * \brief SB internal function to handle processing of 'Write Map Info' Cmd * - * \param[in] Filename Pointer the file name to write + * \param[in] data Pointer to command structure * * \return Execution status, see \ref CFEReturnCodes - * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS - * \retval #CFE_SB_FILE_IO_ERR \copybrief CFE_SB_FILE_IO_ERR */ -int32 CFE_SB_WriteMapInfo(const char *Filename) +int32 CFE_SB_WriteMapInfoCmd(const CFE_SB_WriteMapInfoCmd_t *data) { - CFE_SB_FileWriteCallback_t args = {0}; - int32 Status; - CFE_FS_Header_t FileHdr; + const CFE_SB_WriteFileInfoCmd_Payload_t *CmdPtr; + CFE_SB_BackgroundFileStateInfo_t *StatePtr; + int32 Status; - Status = OS_OpenCreate(&args.Fd, Filename, OS_FILE_FLAG_CREATE | OS_FILE_FLAG_TRUNCATE, OS_WRITE_ONLY); + StatePtr = &CFE_SB_Global.BackgroundFile; + CmdPtr = &data->Payload; - if (Status < OS_SUCCESS) + /* If a pipe info dump was already pending, do not overwrite the current request */ + if (!CFE_FS_BackgroundFileDumpIsPending(&StatePtr->FileWrite)) { - CFE_EVS_SendEvent(CFE_SB_SND_RTG_ERR1_EID, CFE_EVS_EventType_ERROR, - "Error creating file %s, stat=0x%x", - Filename, (unsigned int)Status); - return CFE_SB_FILE_IO_ERR; - } + /* Reset the entire state object (just for good measure, ensure no stale data) */ + memset(StatePtr, 0, sizeof(*StatePtr)); - /* clear out the cfe file header fields, then populate description and subtype */ - CFE_FS_InitHeader(&FileHdr, "SB Message Map Information", CFE_FS_SubType_SB_MAPDATA); + /* Copy the commanded filename into local buffer to ensure size limitation and to allow for modification */ + CFE_SB_MessageStringGet(StatePtr->FileWrite.FileName, CmdPtr->Filename, CFE_PLATFORM_SB_DEFAULT_MAP_FILENAME, + sizeof(StatePtr->FileWrite.FileName), sizeof(CmdPtr->Filename)); - Status = CFE_FS_WriteHeader(args.Fd, &FileHdr); - if(Status != sizeof(CFE_FS_Header_t)) - { - CFE_SB_FileWriteByteCntErr(Filename, sizeof(CFE_FS_Header_t), Status); - OS_close(args.Fd); - return CFE_SB_FILE_IO_ERR; - } - - /* Initialize the reset of the nonzero callback argument elements */ - args.FileSize = Status; - args.Filename = Filename; + /* + * Fill out the remainder of meta data. + * This data is currently the same for every request + */ + StatePtr->FileWrite.FileSubType = CFE_FS_SubType_SB_MAPDATA; + snprintf(StatePtr->FileWrite.Description, sizeof(StatePtr->FileWrite.Description), "SB Map Information"); - /* Write route info to file */ - CFE_SBR_ForEachRouteId(CFE_SB_WriteMapToFile, &args, NULL); + StatePtr->FileWrite.GetData = CFE_SB_WriteMsgMapInfoDataGetter; + StatePtr->FileWrite.OnEvent = CFE_SB_BackgroundFileEventHandler; - if (args.Status != 0) - { - return args.Status; + Status = CFE_FS_BackgroundFileDumpRequest(&StatePtr->FileWrite); } else { - OS_close(args.Fd); - CFE_EVS_SendEvent(CFE_SB_SND_RTG_EID, CFE_EVS_EventType_DEBUG, - "%s written:Size=%d,Entries=%d", - Filename, (int)args.FileSize, (int)args.EntryCount); - return CFE_SUCCESS; + Status = CFE_STATUS_REQUEST_ALREADY_PENDING; } -} + + if (Status != CFE_SUCCESS) + { + /* generate the same event as is generated when unable to create the file (same thing, really) */ + CFE_SB_BackgroundFileEventHandler(StatePtr, CFE_FS_FileWriteEvent_CREATE_ERROR, Status, 0, 0, 0); + } + + CFE_SB_IncrCmdCtr(Status); + + return CFE_SUCCESS; +}/* end CFE_SB_WriteMapInfoCmd */ /****************************************************************************** * Local callback helper for sending route subscriptions @@ -1410,29 +1444,6 @@ void CFE_SB_IncrCmdCtr(int32 status){ }/* end CFE_SB_IncrCmdCtr */ - - -/****************************************************************************** -** Function: CFE_SB_FileWriteByteCntErr() -** -** Purpose: -** SB internal function to report a file write error -** -** Arguments: -** -** -** Return: -** None -*/ -void CFE_SB_FileWriteByteCntErr(const char *Filename,uint32 Requested,uint32 Actual){ - - CFE_EVS_SendEvent(CFE_SB_FILEWRITE_ERR_EID,CFE_EVS_EventType_ERROR, - "File write,byte cnt err,file %s,request=%d,actual=%d", - Filename,(int)Requested,(int)Actual); - -}/* end CFE_SB_FileWriteByteCntErr() */ - - /****************************************************************************** ** Function: CFE_SB_SetSubscriptionReporting() ** diff --git a/fsw/cfe-core/src/tbl/cfe_tbl_internal.h b/fsw/cfe-core/src/tbl/cfe_tbl_internal.h index 21cbfaee2..7fbdb25c3 100644 --- a/fsw/cfe-core/src/tbl/cfe_tbl_internal.h +++ b/fsw/cfe-core/src/tbl/cfe_tbl_internal.h @@ -578,6 +578,15 @@ int32 CFE_TBL_SendNotificationMsg(CFE_TBL_RegistryRec_t *RegRecPtr); ******************************************************************************/ extern void CFE_TBL_ByteSwapUint32(uint32 *Uint32ToSwapPtr); +/* + * Internal helper functions for Table Registry dump + * + * These callbacks are used with the FS background write request API + * and are implemented per that specification. + */ +void CFE_TBL_DumpRegistryEventHandler(void *Meta, CFE_FS_FileWriteEvent_t Event, int32 Status, uint32 RecordNum, size_t BlockSize, size_t Position); +bool CFE_TBL_DumpRegistryGetter(void *Meta, uint32 RecordNum, void **Buffer, size_t *BufSize); + /* ** Globals specific to the TBL module diff --git a/fsw/cfe-core/src/tbl/cfe_tbl_task.h b/fsw/cfe-core/src/tbl/cfe_tbl_task.h index 6ad6611f0..e17ddf804 100644 --- a/fsw/cfe-core/src/tbl/cfe_tbl_task.h +++ b/fsw/cfe-core/src/tbl/cfe_tbl_task.h @@ -271,6 +271,19 @@ typedef struct bool CriticalTable; /**< \brief Identifies whether table is Critical or Not */ } CFE_TBL_RegDumpRec_t; +/*******************************************************************************/ +/** \brief Table Registry Dump background state information +** +** State info for background table registry dump process and one temporary data record. +*/ +typedef struct +{ + CFE_FS_FileWriteMetaData_t FileWrite; /**< FS state data - must be first */ + + bool FileExisted; /**< Set true if the file already existed at the time of request */ + CFE_TBL_RegDumpRec_t DumpRecord; /**< Current record buffer (reused each entry) */ +} CFE_TBL_RegDumpStateInfo_t; + /*******************************************************************************/ /** \brief Table Task Global Data ** @@ -336,6 +349,11 @@ typedef struct CFE_TBL_ValidationResult_t ValidationResults[CFE_PLATFORM_TBL_MAX_NUM_VALIDATIONS]; /**< \brief Array of Table Validation Requests */ CFE_TBL_DumpControl_t DumpControlBlocks[CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS]; /**< \brief Array of Dump-Only Dump Control Blocks */ + /* + * Registry dump state info (background job) + */ + CFE_TBL_RegDumpStateInfo_t RegDumpState; + } CFE_TBL_Global_t; diff --git a/fsw/cfe-core/src/tbl/cfe_tbl_task_cmds.c b/fsw/cfe-core/src/tbl/cfe_tbl_task_cmds.c index 21952d79e..5ac2b95d0 100644 --- a/fsw/cfe-core/src/tbl/cfe_tbl_task_cmds.c +++ b/fsw/cfe-core/src/tbl/cfe_tbl_task_cmds.c @@ -1114,183 +1114,237 @@ int32 CFE_TBL_ActivateCmd(const CFE_TBL_ActivateCmd_t *data) /******************************************************************* ** -** CFE_TBL_DumpRegistryCmd() -- Process Dump Table Registry to file Command Message +** CFE_TBL_DumpRegistryGetter() -- Helper function for dumping table registry ** -** NOTE: For complete prolog information, see 'cfe_tbl_task_cmds.h' ********************************************************************/ -int32 CFE_TBL_DumpRegistryCmd(const CFE_TBL_DumpRegistryCmd_t *data) +bool CFE_TBL_DumpRegistryGetter(void *Meta, uint32 RecordNum, void **Buffer, size_t *BufSize) { - CFE_TBL_CmdProcRet_t ReturnCode = CFE_TBL_INC_ERR_CTR; /* Assume failure */ - bool FileExistedPrev = false; - CFE_FS_Header_t StdFileHeader; - osal_id_t FileDescriptor; - int32 Status; - int16 RegIndex=0; - const CFE_TBL_DumpRegistryCmd_Payload_t *CmdPtr = &data->Payload; - char DumpFilename[OS_MAX_PATH_LEN]; + CFE_TBL_RegDumpStateInfo_t *StatePtr = (CFE_TBL_RegDumpStateInfo_t *)Meta; CFE_TBL_RegistryRec_t *RegRecPtr; CFE_TBL_Handle_t HandleIterator; - CFE_TBL_RegDumpRec_t DumpRecord; - int32 FileSize=0; - int32 NumEntries=0; - - /* Copy the commanded filename into local buffer to ensure size limitation and to allow for modification */ - CFE_SB_MessageStringGet(DumpFilename, (char *)CmdPtr->DumpFilename, CFE_PLATFORM_TBL_DEFAULT_REG_DUMP_FILE, - sizeof(DumpFilename), sizeof(CmdPtr->DumpFilename)); + CFE_ES_AppId_t OwnerAppId; + bool IsValidEntry; - /* Check to see if the dump file already exists */ - Status = OS_OpenCreate(&FileDescriptor, DumpFilename, OS_FILE_FLAG_NONE, OS_READ_ONLY); + IsValidEntry = false; + OwnerAppId = CFE_ES_APPID_UNDEFINED; - if (Status >= 0) + if (RecordNum < CFE_PLATFORM_TBL_MAX_NUM_TABLES) { - FileExistedPrev = true; - OS_close(FileDescriptor); - } + /* Make a pointer to simplify code look and to remove redundant indexing into registry */ + RegRecPtr = &CFE_TBL_Global.Registry[RecordNum]; - /* Create a new dump file, overwriting anything that may have existed previously */ - Status = OS_OpenCreate(&FileDescriptor, DumpFilename, - OS_FILE_FLAG_CREATE | OS_FILE_FLAG_TRUNCATE, OS_WRITE_ONLY); + /* should lock registry while copying out data to ensure its in consistent state */ + CFE_TBL_LockRegistry(); - if (Status >= OS_SUCCESS) - { - /* Initialize the standard cFE File Header for the Dump File */ - CFE_FS_InitHeader(&StdFileHeader, "Table Registry", CFE_FS_SubType_TBL_REG); + /* Check to see if the Registry entry is empty */ + if (!CFE_RESOURCEID_TEST_EQUAL(RegRecPtr->OwnerAppId, CFE_TBL_NOT_OWNED) || + (RegRecPtr->HeadOfAccessList != CFE_TBL_END_OF_LIST)) + { + IsValidEntry = true; + OwnerAppId = RegRecPtr->OwnerAppId; + + /* Fill Registry Dump Record with relevant information */ + StatePtr->DumpRecord.Size = CFE_ES_MEMOFFSET_C(RegRecPtr->Size); + StatePtr->DumpRecord.TimeOfLastUpdate = RegRecPtr->TimeOfLastUpdate; + StatePtr->DumpRecord.LoadInProgress = RegRecPtr->LoadInProgress; + StatePtr->DumpRecord.ValidationFunc = (RegRecPtr->ValidationFuncPtr != NULL); + StatePtr->DumpRecord.TableLoadedOnce = RegRecPtr->TableLoadedOnce; + StatePtr->DumpRecord.LoadPending = RegRecPtr->LoadPending; + StatePtr->DumpRecord.DumpOnly = RegRecPtr->DumpOnly; + StatePtr->DumpRecord.DoubleBuffered = RegRecPtr->DoubleBuffered; + StatePtr->DumpRecord.FileCreateTimeSecs = RegRecPtr->Buffers[RegRecPtr->ActiveBufferIndex].FileCreateTimeSecs; + StatePtr->DumpRecord.FileCreateTimeSubSecs = RegRecPtr->Buffers[RegRecPtr->ActiveBufferIndex].FileCreateTimeSubSecs; + StatePtr->DumpRecord.Crc = RegRecPtr->Buffers[RegRecPtr->ActiveBufferIndex].Crc; + StatePtr->DumpRecord.CriticalTable = RegRecPtr->CriticalTable; + + /* Convert LoadInProgress flag into more meaningful information */ + /* When a load is in progress, identify which buffer is being used as the inactive buffer */ + if (StatePtr->DumpRecord.LoadInProgress != CFE_TBL_NO_LOAD_IN_PROGRESS) + { + if (StatePtr->DumpRecord.DoubleBuffered) + { + /* For double buffered tables, the value of LoadInProgress, when a load is actually in progress, */ + /* should identify either buffer #0 or buffer #1. Convert these to enumerated value for ground */ + /* display. LoadInProgress = -2 means Buffer #1, LoadInProgress = -3 means Buffer #0. */ + StatePtr->DumpRecord.LoadInProgress = StatePtr->DumpRecord.LoadInProgress - 3; + } + /* For single buffered tables, the value of LoadInProgress, when a load is actually in progress, */ + /* indicates which shared buffer is allocated for the inactive buffer. Since the number of inactive */ + /* buffers is a platform configuration parameter, then 0 on up merely identifies the buffer number. */ + /* No translation is necessary for single buffered tables. */ + } + + strncpy(StatePtr->DumpRecord.Name, RegRecPtr->Name, sizeof(StatePtr->DumpRecord.Name)-1); + StatePtr->DumpRecord.Name[sizeof(StatePtr->DumpRecord.Name)-1] = 0; + + strncpy(StatePtr->DumpRecord.LastFileLoaded, RegRecPtr->LastFileLoaded, sizeof(StatePtr->DumpRecord.LastFileLoaded)-1); + StatePtr->DumpRecord.LastFileLoaded[sizeof(StatePtr->DumpRecord.LastFileLoaded)-1] = 0; - /* Output the Standard cFE File Header to the Dump File */ - Status = CFE_FS_WriteHeader(FileDescriptor, &StdFileHeader); - - /* Maintain statistics of amount of data written to file */ - FileSize += Status; + /* Walk the access descriptor list to determine the number of users */ + StatePtr->DumpRecord.NumUsers = 0; + HandleIterator = RegRecPtr->HeadOfAccessList; + while (HandleIterator != CFE_TBL_END_OF_LIST) + { + StatePtr->DumpRecord.NumUsers++; + HandleIterator = CFE_TBL_Global.Handles[HandleIterator].NextLink; + } + } - if (Status == sizeof(CFE_FS_Header_t)) + /* Unlock now - remainder of data gathering uses ES */ + CFE_TBL_UnlockRegistry(); + } + + /* + * If table record had data, then export now. + * Need to also get the App name from ES to complete the record. + */ + if (IsValidEntry) + { + /* Determine the name of the owning application */ + if (!CFE_RESOURCEID_TEST_EQUAL(OwnerAppId, CFE_TBL_NOT_OWNED)) { - Status = sizeof(CFE_TBL_RegDumpRec_t); - while ((RegIndex < CFE_PLATFORM_TBL_MAX_NUM_TABLES) && (Status == sizeof(CFE_TBL_RegDumpRec_t))) - { - /* Make a pointer to simplify code look and to remove redundant indexing into registry */ - RegRecPtr = &CFE_TBL_Global.Registry[RegIndex]; + CFE_ES_GetAppName(StatePtr->DumpRecord.OwnerAppName, OwnerAppId, sizeof(StatePtr->DumpRecord.OwnerAppName)); + } + else + { + strncpy(StatePtr->DumpRecord.OwnerAppName, "--UNOWNED--", sizeof(StatePtr->DumpRecord.OwnerAppName)-1); + StatePtr->DumpRecord.OwnerAppName[sizeof(StatePtr->DumpRecord.OwnerAppName)-1] = 0; + } - /* Check to see if the Registry entry is empty */ - if (!CFE_RESOURCEID_TEST_EQUAL(RegRecPtr->OwnerAppId, CFE_TBL_NOT_OWNED) || - (RegRecPtr->HeadOfAccessList != CFE_TBL_END_OF_LIST)) - { - /* Fill Registry Dump Record with relevant information */ - DumpRecord.Size = CFE_ES_MEMOFFSET_C(RegRecPtr->Size); - DumpRecord.TimeOfLastUpdate = RegRecPtr->TimeOfLastUpdate; - DumpRecord.LoadInProgress = RegRecPtr->LoadInProgress; - DumpRecord.ValidationFunc = (RegRecPtr->ValidationFuncPtr != NULL); - DumpRecord.TableLoadedOnce = RegRecPtr->TableLoadedOnce; - DumpRecord.LoadPending = RegRecPtr->LoadPending; - DumpRecord.DumpOnly = RegRecPtr->DumpOnly; - DumpRecord.DoubleBuffered = RegRecPtr->DoubleBuffered; - DumpRecord.FileCreateTimeSecs = RegRecPtr->Buffers[RegRecPtr->ActiveBufferIndex].FileCreateTimeSecs; - DumpRecord.FileCreateTimeSubSecs = RegRecPtr->Buffers[RegRecPtr->ActiveBufferIndex].FileCreateTimeSubSecs; - DumpRecord.Crc = RegRecPtr->Buffers[RegRecPtr->ActiveBufferIndex].Crc; - DumpRecord.CriticalTable = RegRecPtr->CriticalTable; - - /* Convert LoadInProgress flag into more meaningful information */ - /* When a load is in progress, identify which buffer is being used as the inactive buffer */ - if (DumpRecord.LoadInProgress != CFE_TBL_NO_LOAD_IN_PROGRESS) - { - if (DumpRecord.DoubleBuffered) - { - /* For double buffered tables, the value of LoadInProgress, when a load is actually in progress, */ - /* should identify either buffer #0 or buffer #1. Convert these to enumerated value for ground */ - /* display. LoadInProgress = -2 means Buffer #1, LoadInProgress = -3 means Buffer #0. */ - DumpRecord.LoadInProgress = DumpRecord.LoadInProgress - 3; - } - /* For single buffered tables, the value of LoadInProgress, when a load is actually in progress, */ - /* indicates which shared buffer is allocated for the inactive buffer. Since the number of inactive */ - /* buffers is a platform configuration parameter, then 0 on up merely identifies the buffer number. */ - /* No translation is necessary for single buffered tables. */ - } - - /* Zero character arrays to remove garbage text */ - memset(DumpRecord.Name, 0, CFE_TBL_MAX_FULL_NAME_LEN); - memset(DumpRecord.LastFileLoaded, 0, OS_MAX_PATH_LEN); - memset(DumpRecord.OwnerAppName, 0, OS_MAX_API_NAME); - - strncpy(DumpRecord.Name, RegRecPtr->Name, sizeof(DumpRecord.Name)-1); - strncpy(DumpRecord.LastFileLoaded, RegRecPtr->LastFileLoaded, sizeof(DumpRecord.LastFileLoaded)-1); - - /* Walk the access descriptor list to determine the number of users */ - DumpRecord.NumUsers = 0; - HandleIterator = RegRecPtr->HeadOfAccessList; - while (HandleIterator != CFE_TBL_END_OF_LIST) - { - DumpRecord.NumUsers++; - HandleIterator = CFE_TBL_Global.Handles[HandleIterator].NextLink; - } + /* export data to caller */ + *Buffer = &StatePtr->DumpRecord; + *BufSize = sizeof(StatePtr->DumpRecord); + } + else + { + /* No data to write for this record */ + *BufSize = 0; + *Buffer = NULL; + } - /* Determine the name of the owning application */ - if (!CFE_RESOURCEID_TEST_EQUAL(RegRecPtr->OwnerAppId, CFE_TBL_NOT_OWNED)) - { - CFE_ES_GetAppName(DumpRecord.OwnerAppName, RegRecPtr->OwnerAppId, sizeof(DumpRecord.OwnerAppName)); - } - else - { - strncpy(DumpRecord.OwnerAppName, "--UNOWNED--", sizeof(DumpRecord.OwnerAppName)-1); - } + /* Check for EOF (last entry) */ + return (RecordNum >= (CFE_PLATFORM_TBL_MAX_NUM_TABLES-1)); +} - /* Output Registry Dump Record to Registry Dump File */ - Status = OS_write(FileDescriptor, - &DumpRecord, - sizeof(CFE_TBL_RegDumpRec_t)); - - FileSize += Status; - NumEntries++; - } +/******************************************************************* +** +** CFE_TBL_DumpRegistryEventHandler() -- Helper function for dumping table registry +** +********************************************************************/ - /* Look at the next entry in the Registry */ - RegIndex++; - } +void CFE_TBL_DumpRegistryEventHandler(void *Meta, CFE_FS_FileWriteEvent_t Event, int32 Status, uint32 RecordNum, size_t BlockSize, size_t Position) +{ + CFE_TBL_RegDumpStateInfo_t *StatePtr = (CFE_TBL_RegDumpStateInfo_t *)Meta; - if (Status == sizeof(CFE_TBL_RegDumpRec_t)) + /* + * Note that this runs in the context of ES background task (file writer background job) + * It does NOT run in the context of the CFE_TBL app task. + * + * Events should use CFE_EVS_SendEventWithAppID() rather than CFE_EVS_SendEvent() + * to get proper association with TBL task. + */ + switch(Event) + { + case CFE_FS_FileWriteEvent_COMPLETE: + if (StatePtr->FileExisted) { - if (FileExistedPrev) - { - CFE_EVS_SendEvent(CFE_TBL_OVERWRITE_REG_DUMP_INF_EID, - CFE_EVS_EventType_DEBUG, - "Successfully overwrote '%s' with Table Registry:Size=%d,Entries=%d", - DumpFilename, (int)FileSize, (int)NumEntries); - } - else - { - CFE_EVS_SendEvent(CFE_TBL_WRITE_REG_DUMP_INF_EID, - CFE_EVS_EventType_DEBUG, - "Successfully dumped Table Registry to '%s':Size=%d,Entries=%d", - DumpFilename, (int)FileSize, (int)NumEntries); - } - - /* Increment Successful Command Counter */ - ReturnCode = CFE_TBL_INC_CMD_CTR; + CFE_EVS_SendEventWithAppID(CFE_TBL_OVERWRITE_REG_DUMP_INF_EID, + CFE_EVS_EventType_DEBUG, + CFE_TBL_Global.TableTaskAppId, + "Successfully overwrote '%s' with Table Registry:Size=%d,Entries=%d", + StatePtr->FileWrite.FileName, (int)Position, (int)RecordNum); } else { - CFE_EVS_SendEvent(CFE_TBL_WRITE_TBL_REG_ERR_EID, - CFE_EVS_EventType_ERROR, - "Error writing Registry to '%s', Status=0x%08X", - DumpFilename, (unsigned int)Status); + CFE_EVS_SendEventWithAppID(CFE_TBL_WRITE_REG_DUMP_INF_EID, + CFE_EVS_EventType_DEBUG, + CFE_TBL_Global.TableTaskAppId, + "Successfully dumped Table Registry to '%s':Size=%d,Entries=%d", + StatePtr->FileWrite.FileName, (int)Position, (int)RecordNum); } - } - else - { - CFE_EVS_SendEvent(CFE_TBL_WRITE_CFE_HDR_ERR_EID, + break; + + case CFE_FS_FileWriteEvent_RECORD_WRITE_ERROR: + CFE_EVS_SendEventWithAppID(CFE_TBL_WRITE_TBL_REG_ERR_EID, + CFE_EVS_EventType_ERROR, + CFE_TBL_Global.TableTaskAppId, + "Error writing Registry to '%s', Status=0x%08X", + StatePtr->FileWrite.FileName, (unsigned int)Status); + break; + + case CFE_FS_FileWriteEvent_HEADER_WRITE_ERROR: + CFE_EVS_SendEventWithAppID(CFE_TBL_WRITE_CFE_HDR_ERR_EID, CFE_EVS_EventType_ERROR, + CFE_TBL_Global.TableTaskAppId, "Error writing cFE File Header to '%s', Status=0x%08X", - DumpFilename, (unsigned int)Status); - } + StatePtr->FileWrite.FileName, (unsigned int)Status); + break; + + case CFE_FS_FileWriteEvent_CREATE_ERROR: + CFE_EVS_SendEventWithAppID(CFE_TBL_CREATING_DUMP_FILE_ERR_EID, + CFE_EVS_EventType_ERROR, + CFE_TBL_Global.TableTaskAppId, + "Error creating dump file '%s', Status=0x%08X", + StatePtr->FileWrite.FileName, (unsigned int)Status); + break; + + default: + /* unhandled event - ignore */ + break; + } +} - /* We are done outputting data to the dump file. Close it. */ - OS_close(FileDescriptor); - } - else +/******************************************************************* +** +** CFE_TBL_DumpRegistryCmd() -- Process Dump Table Registry to file Command Message +** +** NOTE: For complete prolog information, see 'cfe_tbl_task_cmds.h' +********************************************************************/ + +int32 CFE_TBL_DumpRegistryCmd(const CFE_TBL_DumpRegistryCmd_t *data) +{ + CFE_TBL_CmdProcRet_t ReturnCode = CFE_TBL_INC_ERR_CTR; /* Assume failure */ + int32 Status; + const CFE_TBL_DumpRegistryCmd_Payload_t *CmdPtr = &data->Payload; + os_fstat_t FileStat; + + CFE_TBL_RegDumpStateInfo_t *StatePtr; + + StatePtr = &CFE_TBL_Global.RegDumpState; + + /* If a reg dump was already pending, do not overwrite the current request */ + if (!CFE_FS_BackgroundFileDumpIsPending(&StatePtr->FileWrite)) { - CFE_EVS_SendEvent(CFE_TBL_CREATING_DUMP_FILE_ERR_EID, - CFE_EVS_EventType_ERROR, - "Error creating dump file '%s', Status=0x%08X", - DumpFilename, (unsigned int)Status); + /* Copy the commanded filename into local buffer to ensure size limitation and to allow for modification */ + CFE_SB_MessageStringGet(StatePtr->FileWrite.FileName, CmdPtr->DumpFilename, CFE_PLATFORM_TBL_DEFAULT_REG_DUMP_FILE, + sizeof(StatePtr->FileWrite.FileName), sizeof(CmdPtr->DumpFilename)); + + /* + * Fill out the remainder of meta data. + * This data is currently the same for every request + */ + StatePtr->FileWrite.FileSubType = CFE_FS_SubType_TBL_REG; + snprintf(StatePtr->FileWrite.Description, sizeof(StatePtr->FileWrite.Description), "Table Registry"); + + StatePtr->FileWrite.GetData = CFE_TBL_DumpRegistryGetter; + StatePtr->FileWrite.OnEvent = CFE_TBL_DumpRegistryEventHandler; + + /* + * Before submitting the background request, use OS_stat() to check if the file exists already. + * + * This is because TBL services issued a different event ID in some cases if + * it is overwriting a file vs. creating a new file. + */ + StatePtr->FileExisted = (OS_stat(StatePtr->FileWrite.FileName, &FileStat) == OS_SUCCESS); + + Status = CFE_FS_BackgroundFileDumpRequest(&StatePtr->FileWrite); + + if (Status == CFE_SUCCESS) + { + /* Increment the TBL generic command counter (successfully queued for background job) */ + ReturnCode = CFE_TBL_INC_CMD_CTR; + } } return ReturnCode; diff --git a/fsw/cfe-core/unit-test/es_UT.c b/fsw/cfe-core/unit-test/es_UT.c index 629abd399..91d8000ec 100644 --- a/fsw/cfe-core/unit-test/es_UT.c +++ b/fsw/cfe-core/unit-test/es_UT.c @@ -2306,6 +2306,9 @@ void TestLibs(void) void TestERLog(void) { int Return; + void *LocalBuffer; + size_t LocalBufSize; + CFE_ES_BackgroundLogDumpGlobal_t State; UtPrintf("Begin Test Exception and Reset Log"); @@ -2343,6 +2346,51 @@ void TestERLog(void) CFE_ES_ResetDataPtr->ERLogIndex == 1, "CFE_ES_WriteToERLog", "No log entry rollover; no description; no context"); + + /* Test ER log background write functions */ + memset(&State, 0, sizeof(State)); + LocalBuffer = NULL; + LocalBufSize = 0; + + UT_SetDeferredRetcode(UT_KEY(CFE_PSP_Exception_CopyContext), 1, 128); + UtAssert_True(!CFE_ES_BackgroundERLogFileDataGetter(&State, 0, &LocalBuffer, &LocalBufSize), + "CFE_ES_BackgroundERLogFileDataGetter at start, with context"); + UtAssert_UINT32_EQ(State.EntryBuffer.ContextSize, 128); + UtAssert_NOT_NULL(LocalBuffer); + UtAssert_NONZERO(LocalBufSize); + + memset(&State.EntryBuffer, 0xEE, sizeof(State.EntryBuffer)); + UT_SetDeferredRetcode(UT_KEY(CFE_PSP_Exception_CopyContext), 1, -1); + UtAssert_True(CFE_ES_BackgroundERLogFileDataGetter(&State, CFE_PLATFORM_ES_ER_LOG_ENTRIES-1, &LocalBuffer, &LocalBufSize), + "CFE_ES_BackgroundERLogFileDataGetter at EOF, no context"); + UtAssert_ZERO(State.EntryBuffer.ContextSize); + + UtAssert_True(CFE_ES_BackgroundERLogFileDataGetter(&State, CFE_PLATFORM_ES_ER_LOG_ENTRIES, &LocalBuffer, &LocalBufSize), + "CFE_ES_BackgroundERLogFileDataGetter beyond EOF"); + UtAssert_NULL(LocalBuffer); + UtAssert_ZERO(LocalBufSize); + + + /* Test ER log background write event handling */ + UT_ClearEventHistory(); + CFE_ES_BackgroundERLogFileEventHandler(&State, CFE_FS_FileWriteEvent_COMPLETE, CFE_SUCCESS, 10, 0, 100); + UtAssert_True(UT_EventIsInHistory(CFE_ES_ERLOG2_EID), "COMPLETE: CFE_ES_ERLOG2_EID generated"); + + UT_ClearEventHistory(); + CFE_ES_BackgroundERLogFileEventHandler(&State, CFE_FS_FileWriteEvent_HEADER_WRITE_ERROR, -1, 10, 10, 100); + UtAssert_True(UT_EventIsInHistory(CFE_ES_FILEWRITE_ERR_EID), "HEADER_WRITE_ERROR: CFE_ES_FILEWRITE_ERR_EID generated"); + + UT_ClearEventHistory(); + CFE_ES_BackgroundERLogFileEventHandler(&State, CFE_FS_FileWriteEvent_RECORD_WRITE_ERROR, -1, 10, 10, 100); + UtAssert_True(UT_EventIsInHistory(CFE_ES_FILEWRITE_ERR_EID), "RECORD_WRITE_ERROR: CFE_ES_FILEWRITE_ERR_EID generated"); + + UT_ClearEventHistory(); + CFE_ES_BackgroundERLogFileEventHandler(&State, CFE_FS_FileWriteEvent_CREATE_ERROR, -1, 10, 10, 100); + UtAssert_True(UT_EventIsInHistory(CFE_ES_ERLOG2_ERR_EID), "CREATE_ERROR: CFE_ES_ERLOG2_ERR_EID generated"); + + UT_ClearEventHistory(); + CFE_ES_BackgroundERLogFileEventHandler(&State, CFE_FS_FileWriteEvent_UNDEFINED, CFE_SUCCESS, 10, 0, 100); + UtAssert_True(UT_GetNumEventsSent() == 0, "UNDEFINED: No event generated"); } @@ -2592,7 +2640,6 @@ void TestGenericPool(void) void TestTask(void) { uint32 ResetType; - uint32 UT_ContextData; osal_id_t UT_ContextTask; union { @@ -3430,11 +3477,11 @@ void TestTask(void) strncpy(CmdBuf.WriteERLogCmd.Payload.FileName, "filename", sizeof(CmdBuf.WriteERLogCmd.Payload.FileName) - 1); CmdBuf.WriteERLogCmd.Payload.FileName[sizeof(CmdBuf.WriteERLogCmd.Payload.FileName) - 1] = '\0'; - CFE_ES_TaskData.BackgroundERLogDumpState.IsPending = false; + UT_SetDefaultReturnValue(UT_KEY(CFE_FS_BackgroundFileDumpIsPending), false); UT_CallTaskPipe(CFE_ES_TaskPipe, &CmdBuf.Msg, sizeof(CmdBuf.WriteERLogCmd), UT_TPID_CFE_ES_CMD_WRITE_ER_LOG_CC); UT_Report(__FILE__, __LINE__, - CFE_ES_TaskData.BackgroundERLogDumpState.IsPending, + UT_GetStubCount(UT_KEY(CFE_FS_BackgroundFileDumpRequest)) == 1, "CFE_ES_WriteERLogCmd", "Write E&R log command; pending"); UT_Report(__FILE__, __LINE__, @@ -3442,71 +3489,25 @@ void TestTask(void) "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. */ + /* Failure from CFE_FS_BackgroundFileDumpRequest() should send the pending error event ID */ + UT_ClearEventHistory(); + UT_SetDeferredRetcode(UT_KEY(CFE_FS_BackgroundFileDumpRequest), 1, CFE_STATUS_REQUEST_ALREADY_PENDING); UT_CallTaskPipe(CFE_ES_TaskPipe, &CmdBuf.Msg, sizeof(CmdBuf.WriteERLogCmd), UT_TPID_CFE_ES_CMD_WRITE_ER_LOG_CC); UT_Report(__FILE__, __LINE__, 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_ContextData = 42; - UT_SetDataBuffer(UT_KEY(CFE_PSP_Exception_CopyContext),&UT_ContextData, sizeof(UT_ContextData), 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 command; file written event"); - - /* Test writing the E&R log with an OS create failure */ - ES_ResetUnitTest(); - CFE_ES_TaskData.BackgroundERLogDumpState.IsPending = true; - UT_SetDefaultReturnValue(UT_KEY(OS_OpenCreate), OS_ERROR); - CFE_ES_RunERLogDump(0, &CFE_ES_TaskData.BackgroundERLogDumpState); - UT_Report(__FILE__, __LINE__, - UT_EventIsInHistory(CFE_ES_ERLOG2_ERR_EID), - "CFE_ES_RunERLogDump", - "Write E&R log; OS create"); - - /* Test writing the E&R log with an OS write failure */ - ES_ResetUnitTest(); - CFE_ES_TaskData.BackgroundERLogDumpState.IsPending = true; - UT_SetDefaultReturnValue(UT_KEY(OS_write), OS_ERROR); - CFE_ES_RunERLogDump(0, &CFE_ES_TaskData.BackgroundERLogDumpState); - UT_Report(__FILE__, __LINE__, - UT_EventIsInHistory(CFE_ES_FILEWRITE_ERR_EID), - "CFE_ES_RunERLogDump", - "Write E&R log; OS write"); + "Write E&R log command; already pending event (from FS)"); - /* Test writing the E&R log with a write header failure */ - ES_ResetUnitTest(); - CFE_ES_TaskData.BackgroundERLogDumpState.IsPending = true; - UT_SetDeferredRetcode(UT_KEY(CFE_FS_WriteHeader), 1, OS_ERROR); - CFE_ES_RunERLogDump(0, &CFE_ES_TaskData.BackgroundERLogDumpState); + /* Same event but pending locally */ + UT_ClearEventHistory(); + UT_SetDefaultReturnValue(UT_KEY(CFE_FS_BackgroundFileDumpIsPending), true); + UT_CallTaskPipe(CFE_ES_TaskPipe, &CmdBuf.Msg, sizeof(CmdBuf.WriteERLogCmd), + UT_TPID_CFE_ES_CMD_WRITE_ER_LOG_CC); UT_Report(__FILE__, __LINE__, - UT_EventIsInHistory(CFE_ES_FILEWRITE_ERR_EID), + UT_EventIsInHistory(CFE_ES_ERLOG_PENDING_ERR_EID), "CFE_ES_WriteERLogCmd", - "Write E&R log; write header"); + "Write E&R log command; already pending event (local)"); /* Test scan for exceptions in the PSP, should invoke a Processor Reset */ ES_ResetUnitTest(); diff --git a/fsw/cfe-core/unit-test/fs_UT.c b/fsw/cfe-core/unit-test/fs_UT.c index 4b569cb19..00335e0dd 100644 --- a/fsw/cfe-core/unit-test/fs_UT.c +++ b/fsw/cfe-core/unit-test/fs_UT.c @@ -47,6 +47,24 @@ const char *FS_SYSLOG_MSGS[] = "FS SharedData Mutex Give Err Stat=0x%x,App=%lu,Function=%s\n" }; +/* counts the number of times UT_FS_OnEvent() was invoked (below) */ +uint32 UT_FS_FileWriteEventCount[CFE_FS_FileWriteEvent_MAX]; + + +/* UT helper stub compatible with background file write DataGetter */ +bool UT_FS_DataGetter(void *Meta, uint32 RecordNum, void **Buffer, size_t *BufSize) +{ + UT_GetDataBuffer(UT_KEY(UT_FS_DataGetter), Buffer, BufSize, NULL); + return UT_DEFAULT_IMPL(UT_FS_DataGetter); +} + +/* UT helper stub compatible with background file write OnEvent */ +void UT_FS_OnEvent(void *Meta, CFE_FS_FileWriteEvent_t Event, int32 Status, uint32 RecordNum, size_t BlockSize, size_t Position) +{ + ++UT_FS_FileWriteEventCount[Event]; + UT_DEFAULT_IMPL(UT_FS_OnEvent); +} + /* ** Functions */ @@ -65,6 +83,8 @@ void UtTest_Setup(void) UT_ADD_TEST(Test_CFE_FS_ByteSwapUint32); UT_ADD_TEST(Test_CFE_FS_ExtractFileNameFromPath); UT_ADD_TEST(Test_CFE_FS_Private); + + UT_ADD_TEST(Test_CFE_FS_BackgroundFileDump); } /* @@ -358,3 +378,124 @@ void Test_CFE_FS_Private(void) UtPrintf("End Test Private\n"); } +void Test_CFE_FS_BackgroundFileDump(void) +{ + /* + * Test routine for: + * bool CFE_FS_RunBackgroundFileDump(uint32 ElapsedTime, void *Arg) + */ + CFE_FS_FileWriteMetaData_t State; + uint32 MyBuffer[2]; + int32 Status; + + memset(UT_FS_FileWriteEventCount, 0, sizeof(UT_FS_FileWriteEventCount)); + memset(&State, 0, sizeof(State)); + memset(&CFE_FS_Global.FileDump, 0, sizeof(CFE_FS_Global.FileDump)); + + /* Nominal with nothing pending - should accumulate credit */ + UtAssert_True(!CFE_FS_RunBackgroundFileDump(1, NULL), "CFE_FS_RunBackgroundFileDump() nothing pending, short delay"); + UtAssert_True(CFE_FS_Global.FileDump.Current.Credit > 0, "Credit accumulating (%lu)", (unsigned long)CFE_FS_Global.FileDump.Current.Credit); + UtAssert_True(CFE_FS_Global.FileDump.Current.Credit < CFE_FS_BACKGROUND_MAX_CREDIT, "Credit not max (%lu)", (unsigned long)CFE_FS_Global.FileDump.Current.Credit); + + UtAssert_True(!CFE_FS_RunBackgroundFileDump(100000, NULL), "CFE_FS_RunBackgroundFileDump() nothing pending, long delay"); + UtAssert_True(CFE_FS_Global.FileDump.Current.Credit == CFE_FS_BACKGROUND_MAX_CREDIT, "Credit at max (%lu)", (unsigned long)CFE_FS_Global.FileDump.Current.Credit); + + Status = CFE_FS_BackgroundFileDumpRequest(NULL); + UtAssert_True(Status == CFE_FS_BAD_ARGUMENT, "CFE_FS_BackgroundFileDumpRequest(NULL) (%lu) == CFE_FS_BAD_ARGUMENT", (unsigned long)Status); + Status = CFE_FS_BackgroundFileDumpRequest(&State); + UtAssert_True(Status == CFE_FS_BAD_ARGUMENT, "CFE_FS_BackgroundFileDumpRequest(&State) (%lu) == CFE_FS_BAD_ARGUMENT", (unsigned long)Status); + UtAssert_True(!CFE_FS_BackgroundFileDumpIsPending(&State), "!CFE_FS_BackgroundFileDumpIsPending(&State)"); + UtAssert_STUB_COUNT(CFE_ES_BackgroundWakeup, 0); /* confirm CFE_ES_BackgroundWakeup() was not invoked */ + + /* Set the data except file name and description */ + State.FileSubType = 2; + State.GetData = UT_FS_DataGetter; + State.OnEvent = UT_FS_OnEvent; + Status = CFE_FS_BackgroundFileDumpRequest(&State); + UtAssert_True(Status == CFE_FS_INVALID_PATH, "CFE_FS_BackgroundFileDumpRequest(&State) (%lu) == CFE_FS_INVALID_PATH", (unsigned long)Status); + UtAssert_True(!CFE_FS_BackgroundFileDumpIsPending(&State), "!CFE_FS_BackgroundFileDumpIsPending(&State)"); + UtAssert_STUB_COUNT(CFE_ES_BackgroundWakeup, 0); /* confirm CFE_ES_BackgroundWakeup() was not invoked */ + + /* Set up remainder of fields, so entry is valid */ + strncpy(State.FileName, "/ram/UT.bin", sizeof(State.FileName)); + strncpy(State.Description, "UT", sizeof(State.Description)); + + Status = CFE_FS_BackgroundFileDumpRequest(&State); + UtAssert_True(Status == CFE_SUCCESS, "CFE_FS_BackgroundFileDumpRequest() (%lu) == CFE_SUCCESS", (unsigned long)Status); + UtAssert_True(CFE_FS_BackgroundFileDumpIsPending(&State), "CFE_FS_BackgroundFileDumpIsPending(&State)"); + UtAssert_STUB_COUNT(CFE_ES_BackgroundWakeup, 1); /* confirm CFE_ES_BackgroundWakeup() was invoked */ + + /* + * Set up a fixed data buffer which will be written, + * this will write sizeof(MyBuffer) until credit is gone + */ + MyBuffer[0] = 10; + MyBuffer[1] = 20; + UT_SetDataBuffer(UT_KEY(UT_FS_DataGetter),MyBuffer,sizeof(MyBuffer), false); + UtAssert_True(CFE_FS_RunBackgroundFileDump(1, NULL), "CFE_FS_RunBackgroundFileDump() request pending nominal"); + UtAssert_STUB_COUNT(OS_OpenCreate, 1); /* confirm OS_open() was invoked */ + UtAssert_True(CFE_FS_Global.FileDump.Current.Credit <= 0, "Credit exhausted (%lu)", (unsigned long)CFE_FS_Global.FileDump.Current.Credit); + UtAssert_STUB_COUNT(OS_close, 0); /* confirm OS_close() was not invoked */ + + UT_SetDeferredRetcode(UT_KEY(UT_FS_DataGetter), 2, true); /* return EOF */ + UtAssert_True(!CFE_FS_RunBackgroundFileDump(100, NULL), "CFE_FS_RunBackgroundFileDump() request pending EOF"); + UtAssert_STUB_COUNT(OS_OpenCreate, 1); /* confirm OS_open() was not invoked again */ + UtAssert_STUB_COUNT(OS_close, 1); /* confirm OS_close() was invoked */ + UtAssert_UINT32_EQ(CFE_FS_Global.FileDump.CompleteCount, CFE_FS_Global.FileDump.RequestCount); /* request was completed */ + UtAssert_UINT32_EQ(UT_FS_FileWriteEventCount[CFE_FS_FileWriteEvent_COMPLETE], 1); /* complete event was sent */ + UtAssert_True(!CFE_FS_BackgroundFileDumpIsPending(&State), "!CFE_FS_BackgroundFileDumpIsPending(&State)"); + + UT_ResetState(UT_KEY(UT_FS_DataGetter)); + + + /* Error opening file */ + Status = CFE_FS_BackgroundFileDumpRequest(&State); + UtAssert_True(Status == CFE_SUCCESS, "CFE_FS_BackgroundFileDumpRequest() (%lu) == CFE_SUCCESS", (unsigned long)Status); + UT_SetDeferredRetcode(UT_KEY(OS_OpenCreate), 1, OS_ERROR); + + UtAssert_True(CFE_FS_RunBackgroundFileDump(100, NULL), "CFE_FS_RunBackgroundFileDump() request pending, file open error"); + UtAssert_UINT32_EQ(UT_FS_FileWriteEventCount[CFE_FS_FileWriteEvent_CREATE_ERROR], 1); /* create error event was sent */ + UtAssert_True(!CFE_FS_BackgroundFileDumpIsPending(&State), "!CFE_FS_BackgroundFileDumpIsPending(&State)"); + UtAssert_UINT32_EQ(CFE_FS_Global.FileDump.CompleteCount, CFE_FS_Global.FileDump.RequestCount); /* request was completed */ + + /* Error writing header */ + Status = CFE_FS_BackgroundFileDumpRequest(&State); + UtAssert_True(Status == CFE_SUCCESS, "CFE_FS_BackgroundFileDumpRequest() (%lu) == CFE_SUCCESS", (unsigned long)Status); + UT_SetDeferredRetcode(UT_KEY(OS_write), 1, OS_ERROR); + + UtAssert_True(CFE_FS_RunBackgroundFileDump(100, NULL), "CFE_FS_RunBackgroundFileDump() request pending, file write header error"); + UtAssert_UINT32_EQ(UT_FS_FileWriteEventCount[CFE_FS_FileWriteEvent_HEADER_WRITE_ERROR], 1); /* header error event was sent */ + UtAssert_True(!CFE_FS_BackgroundFileDumpIsPending(&State), "!CFE_FS_BackgroundFileDumpIsPending(&State)"); + UtAssert_UINT32_EQ(CFE_FS_Global.FileDump.CompleteCount, CFE_FS_Global.FileDump.RequestCount); /* request was completed */ + + /* Error writing data */ + Status = CFE_FS_BackgroundFileDumpRequest(&State); + UtAssert_True(Status == CFE_SUCCESS, "CFE_FS_BackgroundFileDumpRequest() (%lu) == CFE_SUCCESS", (unsigned long)Status); + UT_SetDeferredRetcode(UT_KEY(OS_write), 2, OS_ERROR); + UT_SetDataBuffer(UT_KEY(UT_FS_DataGetter),MyBuffer,sizeof(MyBuffer), false); + UtAssert_True(CFE_FS_RunBackgroundFileDump(100, NULL), "CFE_FS_RunBackgroundFileDump() request pending, file write data error"); + UtAssert_UINT32_EQ(UT_FS_FileWriteEventCount[CFE_FS_FileWriteEvent_RECORD_WRITE_ERROR], 1); /* record error event was sent */ + UtAssert_True(!CFE_FS_BackgroundFileDumpIsPending(&State), "!CFE_FS_BackgroundFileDumpIsPending(&State)"); + UtAssert_UINT32_EQ(CFE_FS_Global.FileDump.CompleteCount, CFE_FS_Global.FileDump.RequestCount); /* request was completed */ + + UT_ResetState(UT_KEY(UT_FS_DataGetter)); + + /* Request multiple file dumps, check queing logic */ + Status = CFE_FS_BackgroundFileDumpRequest(&State); + UtAssert_True(Status == CFE_SUCCESS, "CFE_FS_BackgroundFileDumpRequest() (%lu) == CFE_SUCCESS", (unsigned long)Status); + Status = CFE_FS_BackgroundFileDumpRequest(&State); + UtAssert_True(Status == CFE_STATUS_REQUEST_ALREADY_PENDING, "CFE_FS_BackgroundFileDumpRequest() (%lu) == CFE_STATUS_REQUEST_ALREADY_PENDING", (unsigned long)Status); + + do + { + State.IsPending = false; /* UT hack to fill queue - Force not pending. Real code should not do this. */ + Status = CFE_FS_BackgroundFileDumpRequest(&State); + } + while (Status == CFE_SUCCESS); + + UtAssert_True(Status == CFE_STATUS_REQUEST_ALREADY_PENDING, "CFE_FS_BackgroundFileDumpRequest() (%lu) == CFE_STATUS_REQUEST_ALREADY_PENDING", (unsigned long)Status); + UtAssert_UINT32_EQ(CFE_FS_Global.FileDump.RequestCount, (CFE_FS_Global.FileDump.CompleteCount + CFE_FS_MAX_BACKGROUND_FILE_WRITES - 1)); + + /* Confirm null arg handling in CFE_FS_BackgroundFileDumpIsPending() */ + UtAssert_True(!CFE_FS_BackgroundFileDumpIsPending(NULL), "!CFE_FS_BackgroundFileDumpIsPending(NULL)"); +} diff --git a/fsw/cfe-core/unit-test/fs_UT.h b/fsw/cfe-core/unit-test/fs_UT.h index 1d9fdf1c2..47b2573be 100644 --- a/fsw/cfe-core/unit-test/fs_UT.h +++ b/fsw/cfe-core/unit-test/fs_UT.h @@ -270,4 +270,17 @@ void Test_CFE_FS_Decompress(void); ******************************************************************************/ void Test_CFE_FS_GetUncompressedFile(void); +/*****************************************************************************/ +/** +** \brief Tests for FS background file dump +** +** \par Assumptions, External Events, and Notes: +** None +** +** \returns +** This function does not return a value. +** +******************************************************************************/ +void Test_CFE_FS_BackgroundFileDump(void); + #endif /* _es_ut_h_ */ diff --git a/fsw/cfe-core/unit-test/sb_UT.c b/fsw/cfe-core/unit-test/sb_UT.c index 3e041c35d..e6afc7715 100644 --- a/fsw/cfe-core/unit-test/sb_UT.c +++ b/fsw/cfe-core/unit-test/sb_UT.c @@ -383,21 +383,16 @@ void Test_SB_Cmds(void) SB_UT_ADD_SUBTEST(Test_SB_Cmds_Noop); SB_UT_ADD_SUBTEST(Test_SB_Cmds_RstCtrs); SB_UT_ADD_SUBTEST(Test_SB_Cmds_Stats); + SB_UT_ADD_SUBTEST(Test_SB_Cmds_BackgroundFileWriteEvents); SB_UT_ADD_SUBTEST(Test_SB_Cmds_RoutingInfoDef); - SB_UT_ADD_SUBTEST(Test_SB_Cmds_RoutingInfoSpec); - SB_UT_ADD_SUBTEST(Test_SB_Cmds_RoutingInfoCreateFail); - SB_UT_ADD_SUBTEST(Test_SB_Cmds_RoutingInfoHdrFail); - SB_UT_ADD_SUBTEST(Test_SB_Cmds_RoutingInfoWriteFail); + SB_UT_ADD_SUBTEST(Test_SB_Cmds_RoutingInfoAlreadyPending); + SB_UT_ADD_SUBTEST(Test_SB_Cmds_RoutingInfoDataGetter); SB_UT_ADD_SUBTEST(Test_SB_Cmds_PipeInfoDef); - SB_UT_ADD_SUBTEST(Test_SB_Cmds_PipeInfoSpec); - SB_UT_ADD_SUBTEST(Test_SB_Cmds_PipeInfoCreateFail); - SB_UT_ADD_SUBTEST(Test_SB_Cmds_PipeInfoHdrFail); - SB_UT_ADD_SUBTEST(Test_SB_Cmds_PipeInfoWriteFail); + SB_UT_ADD_SUBTEST(Test_SB_Cmds_PipeInfoAlreadyPending); + SB_UT_ADD_SUBTEST(Test_SB_Cmds_PipeInfoDataGetter); SB_UT_ADD_SUBTEST(Test_SB_Cmds_MapInfoDef); - SB_UT_ADD_SUBTEST(Test_SB_Cmds_MapInfoSpec); - SB_UT_ADD_SUBTEST(Test_SB_Cmds_MapInfoCreateFail); - SB_UT_ADD_SUBTEST(Test_SB_Cmds_MapInfoHdrFail); - SB_UT_ADD_SUBTEST(Test_SB_Cmds_MapInfoWriteFail); + SB_UT_ADD_SUBTEST(Test_SB_Cmds_MapInfoAlreadyPending); + SB_UT_ADD_SUBTEST(Test_SB_Cmds_MapInfoDataGetter); SB_UT_ADD_SUBTEST(Test_SB_Cmds_EnRouteValParam); SB_UT_ADD_SUBTEST(Test_SB_Cmds_EnRouteNonExist); SB_UT_ADD_SUBTEST(Test_SB_Cmds_EnRouteInvParam); @@ -528,24 +523,20 @@ void Test_SB_Cmds_RoutingInfoDef(void) CFE_SB_ProcessCmdPipePkt(&WriteRoutingInfo.SBBuf); - EVTCNT(9); + EVTCNT(5); EVTSENT(CFE_SB_INIT_EID); EVTSENT(CFE_SB_SUBSCRIPTION_RCVD_EID); - EVTSENT(CFE_SB_INIT_EID); - - EVTSENT(CFE_SB_SND_RTG_EID); - TEARDOWN(CFE_SB_DeletePipe(CFE_SB_Global.CmdPipe)); } /* end Test_SB_Cmds_RoutingInfoDef */ /* -** Test write routing information command using a specified file name +** Test write routing information command with request already pending */ -void Test_SB_Cmds_RoutingInfoSpec(void) +void Test_SB_Cmds_RoutingInfoAlreadyPending(void) { union { @@ -556,34 +547,7 @@ void Test_SB_Cmds_RoutingInfoSpec(void) CFE_SB_MsgId_t MsgId = CFE_SB_ValueToMsgId(CFE_SB_CMD_MID); CFE_MSG_Size_t Size = sizeof(WriteRoutingInfo.Cmd); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetFcnCode), &FcnCode, sizeof(FcnCode), false); - strncpy(WriteRoutingInfo.Cmd.Payload.Filename, "RoutingTstFile", - sizeof(WriteRoutingInfo.Cmd.Payload.Filename) - 1); - WriteRoutingInfo.Cmd.Payload.Filename[sizeof(WriteRoutingInfo.Cmd.Payload.Filename) - 1] = '\0'; - - CFE_SB_ProcessCmdPipePkt(&WriteRoutingInfo.SBBuf); - - EVTCNT(1); - - EVTSENT(CFE_SB_SND_RTG_EID); - -} /* end Test_SB_Cmds_RoutingInfoSpec */ - -/* -** Test write routing information command with a file creation failure -*/ -void Test_SB_Cmds_RoutingInfoCreateFail(void) -{ - union - { - CFE_SB_Buffer_t SBBuf; - CFE_SB_WriteRoutingInfoCmd_t Cmd; - } WriteRoutingInfo; - CFE_MSG_FcnCode_t FcnCode = CFE_SB_WRITE_ROUTING_INFO_CC; - CFE_SB_MsgId_t MsgId = CFE_SB_ValueToMsgId(CFE_SB_CMD_MID); - CFE_MSG_Size_t Size = sizeof(WriteRoutingInfo.Cmd); + UT_SetDefaultReturnValue(UT_KEY(CFE_FS_BackgroundFileDumpIsPending), true); UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); @@ -592,61 +556,63 @@ void Test_SB_Cmds_RoutingInfoCreateFail(void) sizeof(WriteRoutingInfo.Cmd.Payload.Filename) - 1); WriteRoutingInfo.Cmd.Payload.Filename[sizeof(WriteRoutingInfo.Cmd.Payload.Filename) - 1] = '\0'; - /* Make function CFE_SB_WriteRtgInfo return CFE_SB_FILE_IO_ERR */ - UT_SetDefaultReturnValue(UT_KEY(OS_OpenCreate), OS_ERROR); - CFE_SB_ProcessCmdPipePkt(&WriteRoutingInfo.SBBuf); EVTCNT(1); EVTSENT(CFE_SB_SND_RTG_ERR1_EID); -} /* end Test_SB_Cmds_RoutingInfoCreateFail */ - -/* -** Test write routing information command with a file header write failure -*/ -void Test_SB_Cmds_RoutingInfoHdrFail(void) -{ - UT_SetDeferredRetcode(UT_KEY(CFE_FS_WriteHeader), 1, -1); - - ASSERT_EQ(CFE_SB_WriteRtgInfo("RoutingTstFile"), CFE_SB_FILE_IO_ERR); - - EVTCNT(1); - - EVTSENT(CFE_SB_FILEWRITE_ERR_EID); - -} /* end Test_SB_Cmds_RoutingInfoHdrFail */ +} /* end Test_SB_Cmds_RoutingInfoSpec */ /* -** Test write routing information command with a file write failure on -** the second write +** Test send routing information command data getter */ -void Test_SB_Cmds_RoutingInfoWriteFail(void) +void Test_SB_Cmds_RoutingInfoDataGetter(void) { - /* Make some routing info by calling CFE_SB_AppInit */ - SETUP(CFE_SB_AppInit()); - - UT_SetDeferredRetcode(UT_KEY(OS_write), 2, -1); - - ASSERT_EQ(CFE_SB_WriteRtgInfo("RoutingTstFile"), CFE_SB_FILE_IO_ERR); - - EVTCNT(9); - - EVTSENT(CFE_SB_PIPE_ADDED_EID); + CFE_SB_PipeId_t PipeId1; + CFE_SB_PipeId_t PipeId2; + CFE_SB_PipeId_t PipeId3; + CFE_SB_MsgId_t MsgId0 = SB_UT_TLM_MID1; + CFE_SB_MsgId_t MsgId1 = SB_UT_TLM_MID2; + CFE_SB_MsgId_t MsgId2 = SB_UT_TLM_MID3; + CFE_SB_MsgId_t MsgId3 = SB_UT_TLM_MID4; + CFE_SB_MsgId_t MsgId4 = SB_UT_TLM_MID5; + CFE_SB_MsgId_t MsgId5 = SB_UT_TLM_MID6; + uint16 PipeDepth = 10; + void *LocalBuffer; + size_t LocalBufSize; + CFE_SB_BackgroundFileStateInfo_t State; - EVTSENT(CFE_SB_SUBSCRIPTION_RCVD_EID); + /* Create some map info */ + SETUP(CFE_SB_CreatePipe(&PipeId1, PipeDepth, "TestPipe1")); + SETUP(CFE_SB_CreatePipe(&PipeId2, PipeDepth, "TestPipe2")); + SETUP(CFE_SB_CreatePipe(&PipeId3, PipeDepth, "TestPipe3")); + SETUP(CFE_SB_Subscribe(MsgId0, PipeId1)); + SETUP(CFE_SB_Subscribe(MsgId0, PipeId2)); + SETUP(CFE_SB_Subscribe(MsgId1, PipeId1)); + SETUP(CFE_SB_Subscribe(MsgId2, PipeId3)); + SETUP(CFE_SB_Subscribe(MsgId3, PipeId3)); + SETUP(CFE_SB_Subscribe(MsgId4, PipeId3)); + SETUP(CFE_SB_Subscribe(MsgId5, PipeId2)); - EVTSENT(CFE_SB_INIT_EID); + memset(&State, 0, sizeof(State)); + LocalBuffer = NULL; + LocalBufSize = 0; - EVTSENT(CFE_SB_FILEWRITE_ERR_EID); + ASSERT_TRUE(!CFE_SB_WriteRouteInfoDataGetter(&State, 0, &LocalBuffer, &LocalBufSize)); + UtAssert_NOT_NULL(LocalBuffer); + UtAssert_NONZERO(LocalBufSize); - TEARDOWN(CFE_SB_DeletePipe(CFE_SB_Global.CmdPipe)); + ASSERT_TRUE(CFE_SB_WriteRouteInfoDataGetter(&State, CFE_PLATFORM_SB_MAX_MSG_IDS, &LocalBuffer, &LocalBufSize)); + UtAssert_ZERO(LocalBufSize); -} /* end Test_SB_Cmds_RoutingInfoWriteFail */ + TEARDOWN(CFE_SB_DeletePipe(PipeId1)); + TEARDOWN(CFE_SB_DeletePipe(PipeId2)); + TEARDOWN(CFE_SB_DeletePipe(PipeId3)); +} /* end Test_SB_Cmds_RoutingInfoDataGetter */ /* -** Test write pipe information command using the default file name +** Test send pipe information command default / nominal path */ void Test_SB_Cmds_PipeInfoDef(void) { @@ -675,10 +641,9 @@ void Test_SB_Cmds_PipeInfoDef(void) CFE_SB_ProcessCmdPipePkt(&WritePipeInfo.SBBuf); - EVTCNT(4); + EVTCNT(3); EVTSENT(CFE_SB_PIPE_ADDED_EID); - EVTSENT(CFE_SB_SND_RTG_EID); TEARDOWN(CFE_SB_DeletePipe(PipeId1)); TEARDOWN(CFE_SB_DeletePipe(PipeId2)); @@ -687,9 +652,9 @@ void Test_SB_Cmds_PipeInfoDef(void) } /* end Test_SB_Cmds_PipeInfoDef */ /* -** Test write pipe information command using a specified file name +** Test write pipe information command when already pending */ -void Test_SB_Cmds_PipeInfoSpec(void) +void Test_SB_Cmds_PipeInfoAlreadyPending(void) { union { @@ -700,6 +665,8 @@ void Test_SB_Cmds_PipeInfoSpec(void) CFE_SB_MsgId_t MsgId = CFE_SB_ValueToMsgId(CFE_SB_CMD_MID); CFE_MSG_Size_t Size = sizeof(WritePipeInfo.Cmd); + UT_SetDefaultReturnValue(UT_KEY(CFE_FS_BackgroundFileDumpIsPending), true); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); UT_SetDataBuffer(UT_KEY(CFE_MSG_GetFcnCode), &FcnCode, sizeof(FcnCode), false); @@ -711,70 +678,131 @@ void Test_SB_Cmds_PipeInfoSpec(void) EVTCNT(1); - EVTSENT(CFE_SB_SND_RTG_EID); + EVTSENT(CFE_SB_SND_RTG_ERR1_EID); -} /* end Test_SB_Cmds_PipeInfoSpec */ +} /* end Test_SB_Cmds_PipeInfoAlreadyPending */ /* -** Test write pipe information command with a file creation failure +** Test write pipe information data getter */ -void Test_SB_Cmds_PipeInfoCreateFail(void) +void Test_SB_Cmds_PipeInfoDataGetter(void) { - UT_SetDefaultReturnValue(UT_KEY(OS_OpenCreate), OS_ERROR); - ASSERT_EQ(CFE_SB_WritePipeInfo("PipeTstFile"), CFE_SB_FILE_IO_ERR); + CFE_SB_PipeId_t PipeId1; + CFE_SB_PipeId_t PipeId2; + CFE_SB_PipeId_t PipeId3; + uint16 PipeDepth = 10; + void *LocalBuffer; + size_t LocalBufSize; + CFE_SB_BackgroundFileStateInfo_t State; - EVTCNT(1); + SETUP(CFE_SB_CreatePipe(&PipeId1, PipeDepth, "TestPipe1")); + SETUP(CFE_SB_CreatePipe(&PipeId2, PipeDepth, "TestPipe2")); + SETUP(CFE_SB_CreatePipe(&PipeId3, PipeDepth, "TestPipe3")); - EVTSENT(CFE_SB_SND_RTG_ERR1_EID); + memset(&State, 0, sizeof(State)); + LocalBuffer = NULL; + LocalBufSize = 0; + + /* Note that CFE_SB_CreatePipe() fills entry 1 first, so entry 0 is unused */ + ASSERT_TRUE(!CFE_SB_WritePipeInfoDataGetter(&State, 0, &LocalBuffer, &LocalBufSize)); + UtAssert_ZERO(LocalBufSize); + + ASSERT_TRUE(!CFE_SB_WritePipeInfoDataGetter(&State, 1, &LocalBuffer, &LocalBufSize)); + UtAssert_NOT_NULL(LocalBuffer); + UtAssert_NONZERO(LocalBufSize); -} /* end Test_SB_Cmds_PipeInfoCreateFail */ + ASSERT_TRUE(CFE_SB_WritePipeInfoDataGetter(&State, CFE_PLATFORM_SB_MAX_PIPES-1, &LocalBuffer, &LocalBufSize)); + UtAssert_ZERO(LocalBufSize); + + ASSERT_TRUE(CFE_SB_WritePipeInfoDataGetter(&State, CFE_PLATFORM_SB_MAX_PIPES, &LocalBuffer, &LocalBufSize)); + UtAssert_ZERO(LocalBufSize); + + TEARDOWN(CFE_SB_DeletePipe(PipeId1)); + TEARDOWN(CFE_SB_DeletePipe(PipeId2)); + TEARDOWN(CFE_SB_DeletePipe(PipeId3)); +} /* end Test_SB_Cmds_PipeInfoDataGetter */ /* -** Test write pipe information command with a file header write failure +** Test background file write event generator */ -void Test_SB_Cmds_PipeInfoHdrFail(void) +void Test_SB_Cmds_BackgroundFileWriteEvents(void) { - UT_SetDeferredRetcode(UT_KEY(CFE_FS_WriteHeader), 1, -1); - ASSERT_EQ(CFE_SB_WritePipeInfo("PipeTstFile"), CFE_SB_FILE_IO_ERR); + CFE_SB_BackgroundFileStateInfo_t State; - EVTCNT(1); + memset(&State, 0, sizeof(State)); + UT_ClearEventHistory(); + CFE_SB_BackgroundFileEventHandler(&State, CFE_FS_FileWriteEvent_COMPLETE, CFE_SUCCESS, 10, 0, 1000); + EVTSENT(CFE_SB_SND_RTG_EID); + + UT_ClearEventHistory(); + CFE_SB_BackgroundFileEventHandler(&State, CFE_FS_FileWriteEvent_RECORD_WRITE_ERROR, CFE_SUCCESS, 10, 10, 1000); EVTSENT(CFE_SB_FILEWRITE_ERR_EID); -} /* end Test_SB_Cmds_PipeInfoHdrFail */ + UT_ClearEventHistory(); + CFE_SB_BackgroundFileEventHandler(&State, CFE_FS_FileWriteEvent_HEADER_WRITE_ERROR, CFE_SUCCESS, 10, 10, 1000); + EVTSENT(CFE_SB_FILEWRITE_ERR_EID); + + UT_ClearEventHistory(); + CFE_SB_BackgroundFileEventHandler(&State, CFE_FS_FileWriteEvent_CREATE_ERROR, OS_ERROR, 10, 0, 0); + EVTSENT(CFE_SB_SND_RTG_ERR1_EID); + + UT_ClearEventHistory(); + CFE_SB_BackgroundFileEventHandler(&State, CFE_FS_FileWriteEvent_UNDEFINED, OS_ERROR, 0, 0, 0); + EVTCNT(0); + +} /* -** Test write pipe information command with a file write failure on -** the second write +** Test write pipe information data getter for background file write */ -void Test_SB_Cmds_PipeInfoWriteFail(void) +void Test_SB_Cmds_MapInfoDataGetter(void) { CFE_SB_PipeId_t PipeId1; CFE_SB_PipeId_t PipeId2; CFE_SB_PipeId_t PipeId3; + CFE_SB_MsgId_t MsgId0 = SB_UT_TLM_MID1; + CFE_SB_MsgId_t MsgId1 = SB_UT_TLM_MID2; + CFE_SB_MsgId_t MsgId2 = SB_UT_TLM_MID3; + CFE_SB_MsgId_t MsgId3 = SB_UT_TLM_MID4; + CFE_SB_MsgId_t MsgId4 = SB_UT_TLM_MID5; + CFE_SB_MsgId_t MsgId5 = SB_UT_TLM_MID6; uint16 PipeDepth = 10; + void *LocalBuffer; + size_t LocalBufSize; + CFE_SB_BackgroundFileStateInfo_t State; + /* Create some map info */ SETUP(CFE_SB_CreatePipe(&PipeId1, PipeDepth, "TestPipe1")); SETUP(CFE_SB_CreatePipe(&PipeId2, PipeDepth, "TestPipe2")); SETUP(CFE_SB_CreatePipe(&PipeId3, PipeDepth, "TestPipe3")); - UT_SetDeferredRetcode(UT_KEY(OS_write), 2, -1); - - ASSERT_EQ(CFE_SB_WritePipeInfo("PipeTstFile"), CFE_SB_FILE_IO_ERR); + SETUP(CFE_SB_Subscribe(MsgId0, PipeId1)); + SETUP(CFE_SB_Subscribe(MsgId0, PipeId2)); + SETUP(CFE_SB_Subscribe(MsgId1, PipeId1)); + SETUP(CFE_SB_Subscribe(MsgId2, PipeId3)); + SETUP(CFE_SB_Subscribe(MsgId3, PipeId3)); + SETUP(CFE_SB_Subscribe(MsgId4, PipeId3)); + SETUP(CFE_SB_Subscribe(MsgId5, PipeId2)); - EVTCNT(4); + memset(&State, 0, sizeof(State)); + LocalBuffer = NULL; + LocalBufSize = 0; - EVTSENT(CFE_SB_PIPE_ADDED_EID); + ASSERT_TRUE(!CFE_SB_WriteMsgMapInfoDataGetter(&State, 0, &LocalBuffer, &LocalBufSize)); + UtAssert_NOT_NULL(LocalBuffer); + UtAssert_NONZERO(LocalBufSize); - EVTSENT(CFE_SB_FILEWRITE_ERR_EID); + ASSERT_TRUE(CFE_SB_WriteMsgMapInfoDataGetter(&State, CFE_PLATFORM_SB_MAX_MSG_IDS, &LocalBuffer, &LocalBufSize)); + UtAssert_NULL(LocalBuffer); + UtAssert_ZERO(LocalBufSize); TEARDOWN(CFE_SB_DeletePipe(PipeId1)); TEARDOWN(CFE_SB_DeletePipe(PipeId2)); TEARDOWN(CFE_SB_DeletePipe(PipeId3)); - -} /* end Test_SB_Cmds_PipeInfoWriteFail */ +} /* end Test_SB_MapInfoDataGetter */ /* -** Test write map information command using the default file name +** Test write map information command nominal path */ void Test_SB_Cmds_MapInfoDef(void) { @@ -816,9 +844,7 @@ void Test_SB_Cmds_MapInfoDef(void) CFE_SB_ProcessCmdPipePkt(&WriteMapInfo.SBBuf); - EVTCNT(11); - - EVTSENT(CFE_SB_SND_RTG_EID); + EVTCNT(10); EVTSENT(CFE_SB_PIPE_ADDED_EID); @@ -831,9 +857,9 @@ void Test_SB_Cmds_MapInfoDef(void) } /* end Test_SB_Cmds_MapInfoDef */ /* -** Test write map information command using a specified file name +** Test write map information command when already pending */ -void Test_SB_Cmds_MapInfoSpec(void) +void Test_SB_Cmds_MapInfoAlreadyPending(void) { union { @@ -844,6 +870,8 @@ void Test_SB_Cmds_MapInfoSpec(void) CFE_SB_MsgId_t MsgId = CFE_SB_ValueToMsgId(CFE_SB_CMD_MID); CFE_MSG_Size_t Size = sizeof(WriteMapInfo.Cmd); + UT_SetDefaultReturnValue(UT_KEY(CFE_FS_BackgroundFileDumpIsPending), true); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); UT_SetDataBuffer(UT_KEY(CFE_MSG_GetFcnCode), &FcnCode, sizeof(FcnCode), false); @@ -855,83 +883,9 @@ void Test_SB_Cmds_MapInfoSpec(void) EVTCNT(1); - EVTSENT(CFE_SB_SND_RTG_EID); - -} /* end Test_SB_Cmds_MapInfoSpec */ - -/* -** Test write map information command with a file creation failure -*/ -void Test_SB_Cmds_MapInfoCreateFail(void) -{ - UT_SetDefaultReturnValue(UT_KEY(OS_OpenCreate), OS_ERROR); - ASSERT_EQ(CFE_SB_WriteMapInfo("MapTstFile"), CFE_SB_FILE_IO_ERR); - - EVTCNT(1); - EVTSENT(CFE_SB_SND_RTG_ERR1_EID); -} /* end Test_SB_Cmds_MapInfoCreateFail */ - -/* -** Test write map information command with a file header write failure -*/ -void Test_SB_Cmds_MapInfoHdrFail(void) -{ - UT_SetDeferredRetcode(UT_KEY(CFE_FS_WriteHeader), 1, -1); - ASSERT_EQ(CFE_SB_WriteMapInfo("MapTstFile"), CFE_SB_FILE_IO_ERR); - - EVTCNT(1); - - EVTSENT(CFE_SB_FILEWRITE_ERR_EID); - -} /* end Test_SB_Cmds_MapInfoHdrFail */ - -/* -** Test write map information command with a file write failure on -** the second write -*/ -void Test_SB_Cmds_MapInfoWriteFail(void) -{ - CFE_SB_PipeId_t PipeId1; - CFE_SB_PipeId_t PipeId2; - CFE_SB_PipeId_t PipeId3; - CFE_SB_MsgId_t MsgId0 = SB_UT_TLM_MID1; - CFE_SB_MsgId_t MsgId1 = SB_UT_TLM_MID2; - CFE_SB_MsgId_t MsgId2 = SB_UT_TLM_MID3; - CFE_SB_MsgId_t MsgId3 = SB_UT_TLM_MID4; - CFE_SB_MsgId_t MsgId4 = SB_UT_TLM_MID5; - CFE_SB_MsgId_t MsgId5 = SB_UT_TLM_MID6; - uint16 PipeDepth = 10; - - /* Create some map info */ - SETUP(CFE_SB_CreatePipe(&PipeId1, PipeDepth, "TestPipe1")); - SETUP(CFE_SB_CreatePipe(&PipeId2, PipeDepth, "TestPipe2")); - SETUP(CFE_SB_CreatePipe(&PipeId3, PipeDepth, "TestPipe3")); - SETUP(CFE_SB_Subscribe(MsgId0, PipeId1)); - SETUP(CFE_SB_Subscribe(MsgId0, PipeId2)); - SETUP(CFE_SB_Subscribe(MsgId1, PipeId1)); - SETUP(CFE_SB_Subscribe(MsgId2, PipeId3)); - SETUP(CFE_SB_Subscribe(MsgId3, PipeId3)); - SETUP(CFE_SB_Subscribe(MsgId4, PipeId3)); - SETUP(CFE_SB_Subscribe(MsgId5, PipeId2)); - UT_SetDeferredRetcode(UT_KEY(OS_write), 2, -1); - - ASSERT_EQ(CFE_SB_WriteMapInfo("MapTstFile"), CFE_SB_FILE_IO_ERR); - - EVTCNT(11); - - EVTSENT(CFE_SB_FILEWRITE_ERR_EID); - - EVTSENT(CFE_SB_PIPE_ADDED_EID); - - EVTSENT(CFE_SB_SUBSCRIPTION_RCVD_EID); - - TEARDOWN(CFE_SB_DeletePipe(PipeId1)); - TEARDOWN(CFE_SB_DeletePipe(PipeId2)); - TEARDOWN(CFE_SB_DeletePipe(PipeId3)); - -} /* end Test_SB_Cmds_MapInfoWriteFail */ +} /* end Test_SB_Cmds_MapInfoSpec */ /* ** Test command to enable a specific route using a valid route diff --git a/fsw/cfe-core/unit-test/sb_UT.h b/fsw/cfe-core/unit-test/sb_UT.h index 7ebff942d..2f09ea386 100644 --- a/fsw/cfe-core/unit-test/sb_UT.h +++ b/fsw/cfe-core/unit-test/sb_UT.h @@ -365,7 +365,7 @@ void Test_SB_Cmds_Stats(void); /*****************************************************************************/ /** -** \brief Test send routing information command using the default file name +** \brief Test send routing information command default/nominal path ** ** \par Description ** This function tests the send routing information command using the @@ -381,7 +381,7 @@ void Test_SB_Cmds_RoutingInfoDef(void); /*****************************************************************************/ /** -** \brief Test send routing information command using a specified file name +** \brief Test send routing information command with request already pending ** ** \par Description ** This function tests the send routing information command using a @@ -393,15 +393,11 @@ void Test_SB_Cmds_RoutingInfoDef(void); ** \returns ** This function does not return a value. ******************************************************************************/ -void Test_SB_Cmds_RoutingInfoSpec(void); +void Test_SB_Cmds_RoutingInfoAlreadyPending(void); /*****************************************************************************/ /** -** \brief Test send routing information command with a file creation failure -** -** \par Description -** This function tests the send routing information command with a file -** creation failure. +** \brief Test routing information data getter ** ** \par Assumptions, External Events, and Notes: ** None @@ -409,7 +405,7 @@ void Test_SB_Cmds_RoutingInfoSpec(void); ** \returns ** This function does not return a value. ******************************************************************************/ -void Test_SB_Cmds_RoutingInfoCreateFail(void); +void Test_SB_Cmds_RoutingInfoDataGetter(void); /*****************************************************************************/ /** @@ -650,41 +646,7 @@ void Test_GetPipeIdByName(void); /*****************************************************************************/ /** -** \brief Test send routing information command with a file header -** write failure -** -** \par Description -** This function tests the send routing information command with a file -** header write failure. -** -** \par Assumptions, External Events, and Notes: -** None -** -** \returns -** This function does not return a value. -******************************************************************************/ -void Test_SB_Cmds_RoutingInfoHdrFail(void); - -/*****************************************************************************/ -/** -** \brief Test send routing information command with a file header write -** failure on the second write -** -** \par Description -** This function tests the send routing information command with a file -** header write failure on the second write. -** -** \par Assumptions, External Events, and Notes: -** None -** -** \returns -** This function does not return a value. -******************************************************************************/ -void Test_SB_Cmds_RoutingInfoWriteFail(void); - -/*****************************************************************************/ -/** -** \brief Test send pipe information command using the default file name +** \brief Test send pipe information command default / nominal path ** ** \par Description ** This function tests the send pipe information command using the @@ -700,11 +662,7 @@ void Test_SB_Cmds_PipeInfoDef(void); /*****************************************************************************/ /** -** \brief Test send pipe information command using a specified file name -** -** \par Description -** This function tests the send pipe information command using a -** specified file name. +** \brief Test send pipe information command when already pending ** ** \par Assumptions, External Events, and Notes: ** None @@ -712,15 +670,11 @@ void Test_SB_Cmds_PipeInfoDef(void); ** \returns ** This function does not return a value. ******************************************************************************/ -void Test_SB_Cmds_PipeInfoSpec(void); +void Test_SB_Cmds_PipeInfoAlreadyPending(void); /*****************************************************************************/ /** -** \brief Test send pipe information command with a file creation failure -** -** \par Description -** This function tests the send pipe information command with a file -** creation failure. +** \brief Test pipe information data getter ** ** \par Assumptions, External Events, and Notes: ** None @@ -728,16 +682,11 @@ void Test_SB_Cmds_PipeInfoSpec(void); ** \returns ** This function does not return a value. ******************************************************************************/ -void Test_SB_Cmds_PipeInfoCreateFail(void); +void Test_SB_Cmds_PipeInfoDataGetter(void); /*****************************************************************************/ /** -** \brief Test send pipe information command with a file header -** write failure -** -** \par Description -** This function tests the send pipe information command with a file -** header write failure. +** \brief Test background file writer event handler ** ** \par Assumptions, External Events, and Notes: ** None @@ -745,28 +694,11 @@ void Test_SB_Cmds_PipeInfoCreateFail(void); ** \returns ** This function does not return a value. ******************************************************************************/ -void Test_SB_Cmds_PipeInfoHdrFail(void); +void Test_SB_Cmds_BackgroundFileWriteEvents(void); /*****************************************************************************/ /** -** \brief Test send pipe information command with a file write failure on -** the second write -** -** \par Description -** This function tests the send pipe information command with a file -** write failure on the second write. -** -** \par Assumptions, External Events, and Notes: -** None -** -** \returns -** This function does not return a value. -******************************************************************************/ -void Test_SB_Cmds_PipeInfoWriteFail(void); - -/*****************************************************************************/ -/** -** \brief Test send map information command using the default file name +** \brief Test send map information command using the defaults / nominal path ** ** \par Description ** This function tests the send map information command using the @@ -782,7 +714,7 @@ void Test_SB_Cmds_MapInfoDef(void); /*****************************************************************************/ /** -** \brief Test send map information command using a specified file name +** \brief Test send map information command when already pending ** ** \par Description ** This function tests the send map information command using a @@ -794,48 +726,11 @@ void Test_SB_Cmds_MapInfoDef(void); ** \returns ** This function does not return a value. ******************************************************************************/ -void Test_SB_Cmds_MapInfoSpec(void); +void Test_SB_Cmds_MapInfoAlreadyPending(void); /*****************************************************************************/ /** -** \brief Test send map information command with a file creation failure -** -** \par Description -** This function tests the send map information command with a file -** creation failure. -** -** \par Assumptions, External Events, and Notes: -** None -** -** \returns -** This function does not return a value. -******************************************************************************/ -void Test_SB_Cmds_MapInfoCreateFail(void); - -/*****************************************************************************/ -/** -** \brief Test send map information command with a file header write failure -** -** \par Description -** This function tests the send map information command with a file -** header write failure. -** -** \par Assumptions, External Events, and Notes: -** None -** -** \returns -** This function does not return a value. -******************************************************************************/ -void Test_SB_Cmds_MapInfoHdrFail(void); - -/*****************************************************************************/ -/** -** \brief Test send map information command with a file write failure on -** the second write -** -** \par Description -** This function tests the send map information command with a file -** write failure on the second write. +** \brief Test map information data getter function ** ** \par Assumptions, External Events, and Notes: ** None @@ -843,7 +738,7 @@ void Test_SB_Cmds_MapInfoHdrFail(void); ** \returns ** This function does not return a value. ******************************************************************************/ -void Test_SB_Cmds_MapInfoWriteFail(void); +void Test_SB_Cmds_MapInfoDataGetter(void); /*****************************************************************************/ /** diff --git a/fsw/cfe-core/unit-test/tbl_UT.c b/fsw/cfe-core/unit-test/tbl_UT.c index a26d524c5..156c560a6 100644 --- a/fsw/cfe-core/unit-test/tbl_UT.c +++ b/fsw/cfe-core/unit-test/tbl_UT.c @@ -1145,6 +1145,9 @@ void Test_CFE_TBL_DumpRegCmd(void) int q; CFE_TBL_DumpRegistryCmd_t DumpRegCmd; CFE_ES_AppId_t AppID; + size_t LocalSize; + void *LocalBuf; + bool IsEOF; /* Get the AppID being used for UT */ CFE_ES_GetAppID(&AppID); @@ -1157,77 +1160,122 @@ void Test_CFE_TBL_DumpRegCmd(void) CFE_TBL_Global.Registry[q].HeadOfAccessList = CFE_TBL_END_OF_LIST; } - /* Test with an error creating the dump file */ + /* Test command using the default dump file name (nominal path) */ UT_InitData(); - DumpRegCmd.Payload.DumpFilename[0] = '\0'; - UT_SetDefaultReturnValue(UT_KEY(OS_OpenCreate), OS_ERROR); + UT_SetDefaultReturnValue(UT_KEY(CFE_FS_BackgroundFileDumpIsPending), false); + strncpy(DumpRegCmd.Payload.DumpFilename, "X", sizeof(DumpRegCmd.Payload.DumpFilename) - 1); + DumpRegCmd.Payload.DumpFilename[sizeof(DumpRegCmd.Payload.DumpFilename) - 1] = '\0'; + UT_Report(__FILE__, __LINE__, + CFE_TBL_DumpRegistryCmd(&DumpRegCmd) == + CFE_TBL_INC_CMD_CTR, + "CFE_TBL_DumpRegistryCmd", + "Default dump file name"); + + /* Test command with the dump file already pending (max requests pending) */ + UT_SetDefaultReturnValue(UT_KEY(CFE_FS_BackgroundFileDumpIsPending), true); + UT_SetDefaultReturnValue(UT_KEY(CFE_FS_BackgroundFileDumpRequest), CFE_STATUS_REQUEST_ALREADY_PENDING); UT_Report(__FILE__, __LINE__, CFE_TBL_DumpRegistryCmd(&DumpRegCmd) == CFE_TBL_INC_ERR_CTR, "CFE_TBL_DumpRegistryCmd", - "Error creating dump file"); + "Dump file already pending (FS max requests)"); + UT_ResetState(UT_KEY(CFE_FS_BackgroundFileDumpRequest)); - /* Test with an error writing the cFE File header */ - UT_InitData(); - UT_SetDeferredRetcode(UT_KEY(CFE_FS_WriteHeader), 1, sizeof(CFE_FS_Header_t) - 1); + /* Test command with the dump file already pending (local) */ + UT_SetDefaultReturnValue(UT_KEY(CFE_FS_BackgroundFileDumpIsPending), false); + UT_SetDefaultReturnValue(UT_KEY(CFE_FS_BackgroundFileDumpRequest), CFE_STATUS_REQUEST_ALREADY_PENDING); UT_Report(__FILE__, __LINE__, CFE_TBL_DumpRegistryCmd(&DumpRegCmd) == CFE_TBL_INC_ERR_CTR, "CFE_TBL_DumpRegistryCmd", - "Error writing cFE File header"); + "Dump file already pending (local)"); + + /* Check event generators */ + UT_ClearEventHistory(); + CFE_TBL_Global.RegDumpState.FileExisted = true; + CFE_TBL_DumpRegistryEventHandler(&CFE_TBL_Global.RegDumpState, CFE_FS_FileWriteEvent_COMPLETE, CFE_SUCCESS, 10, 0, 1000); + UT_Report(__FILE__, __LINE__, + UT_EventIsInHistory(CFE_TBL_OVERWRITE_REG_DUMP_INF_EID), + "CFE_TBL_DumpRegistryEventHandler", + "Dump file created event (overwrite)"); + + UT_ClearEventHistory(); + CFE_TBL_Global.RegDumpState.FileExisted = false; + CFE_TBL_DumpRegistryEventHandler(&CFE_TBL_Global.RegDumpState, CFE_FS_FileWriteEvent_COMPLETE, CFE_SUCCESS, 10, 0, 1000); + UT_Report(__FILE__, __LINE__, + UT_EventIsInHistory(CFE_TBL_WRITE_REG_DUMP_INF_EID), + "CFE_TBL_DumpRegistryEventHandler", + "Dump file created event (new)"); + + UT_ClearEventHistory(); + CFE_TBL_DumpRegistryEventHandler(&CFE_TBL_Global.RegDumpState, CFE_FS_FileWriteEvent_RECORD_WRITE_ERROR, CFE_SUCCESS, 10, 10, 1000); + UT_Report(__FILE__, __LINE__, + UT_EventIsInHistory(CFE_TBL_WRITE_TBL_REG_ERR_EID), + "CFE_TBL_DumpRegistryEventHandler", + "Dump file record write error event"); + + UT_ClearEventHistory(); + CFE_TBL_DumpRegistryEventHandler(&CFE_TBL_Global.RegDumpState, CFE_FS_FileWriteEvent_HEADER_WRITE_ERROR, CFE_SUCCESS, 10, 10, 1000); + UT_Report(__FILE__, __LINE__, + UT_EventIsInHistory(CFE_TBL_WRITE_CFE_HDR_ERR_EID), + "CFE_TBL_DumpRegistryEventHandler", + "Dump file header write error event"); + + UT_ClearEventHistory(); + CFE_TBL_DumpRegistryEventHandler(&CFE_TBL_Global.RegDumpState, CFE_FS_FileWriteEvent_CREATE_ERROR, OS_ERROR, 10, 0, 0); + UT_Report(__FILE__, __LINE__, + UT_EventIsInHistory(CFE_TBL_CREATING_DUMP_FILE_ERR_EID), + "CFE_TBL_DumpRegistryEventHandler", + "Dump file created error event"); + + UT_ClearEventHistory(); + CFE_TBL_DumpRegistryEventHandler(&CFE_TBL_Global.RegDumpState, CFE_FS_FileWriteEvent_UNDEFINED, OS_ERROR, 0, 0, 0); + UT_Report(__FILE__, __LINE__, + UT_GetNumEventsSent() == 0, + "CFE_TBL_DumpRegistryEventHandler", + "Undefined event is ignored"); /* Test where the table is owned, the file doesn't already exist, and the * table is successfully dumped */ UT_InitData(); - UT_SetDeferredRetcode(UT_KEY(CFE_FS_WriteHeader), 10, sizeof(CFE_FS_Header_t)); CFE_TBL_Global.Registry[0].OwnerAppId = AppID; CFE_TBL_Global.Registry[0].HeadOfAccessList = CFE_TBL_END_OF_LIST; CFE_TBL_Global.Registry[1].OwnerAppId = CFE_TBL_NOT_OWNED; CFE_TBL_Global.Registry[0].LoadInProgress = CFE_TBL_NO_LOAD_IN_PROGRESS + 1; CFE_TBL_Global.Registry[0].DoubleBuffered = true; - UT_SetDeferredRetcode(UT_KEY(OS_OpenCreate), 1, OS_ERROR); - UT_Report(__FILE__, __LINE__, - CFE_TBL_DumpRegistryCmd(&DumpRegCmd) == - CFE_TBL_INC_CMD_CTR, - "CFE_TBL_DumpRegistryCmd", - "Table is owned, file didn't exist previously: successfully " - "dumped table"); - - /* Test where the file did exist previously and the table is successfully - * overwritten - */ - UT_InitData(); - CFE_TBL_Global.Registry[0].LoadInProgress = CFE_TBL_NO_LOAD_IN_PROGRESS; - UT_Report(__FILE__, __LINE__, - CFE_TBL_DumpRegistryCmd(&DumpRegCmd) == - CFE_TBL_INC_CMD_CTR, - "CFE_TBL_DumpRegistryCmd", - "File did exist previously: successfully overwritten table"); - - /* Test where the table is not owned, the OS write fails, resulting in an - * error writing to the registry - */ - UT_InitData(); - UT_SetDeferredRetcode(UT_KEY(OS_write), 1, sizeof(CFE_TBL_RegDumpRec_t) - 1); - CFE_TBL_Global.Registry[0].OwnerAppId = CFE_TBL_NOT_OWNED; - CFE_TBL_Global.Registry[0].HeadOfAccessList = 2; + LocalBuf = NULL; + LocalSize = 0; + IsEOF = CFE_TBL_DumpRegistryGetter(&CFE_TBL_Global.RegDumpState, 0, &LocalBuf, &LocalSize); + UT_Report(__FILE__, __LINE__, + !IsEOF, + "CFE_TBL_DumpRegistryGetter", + "Nominal, first record, not end of file"); + UtAssert_NOT_NULL(LocalBuf); + UtAssert_NONZERO(LocalSize); + + CFE_TBL_Global.Registry[CFE_PLATFORM_TBL_MAX_NUM_TABLES-1].OwnerAppId = CFE_TBL_NOT_OWNED; + CFE_TBL_Global.Registry[CFE_PLATFORM_TBL_MAX_NUM_TABLES-1].HeadOfAccessList = 2; CFE_TBL_Global.Handles[2].NextLink = CFE_TBL_END_OF_LIST; + LocalBuf = NULL; + LocalSize = 0; + IsEOF = CFE_TBL_DumpRegistryGetter(&CFE_TBL_Global.RegDumpState, CFE_PLATFORM_TBL_MAX_NUM_TABLES-1, &LocalBuf, &LocalSize); UT_Report(__FILE__, __LINE__, - CFE_TBL_DumpRegistryCmd(&DumpRegCmd) == - CFE_TBL_INC_ERR_CTR, - "CFE_TBL_DumpRegistryCmd", - "Table is not owned, OS_write fails: Error writing Registry"); + IsEOF, + "CFE_TBL_DumpRegistryGetter", + "Nominal, last record, multiple accessors, end of file"); + UtAssert_NOT_NULL(LocalBuf); + UtAssert_NONZERO(LocalSize); - /* Test using the default dump file name */ - UT_InitData(); - strncpy(DumpRegCmd.Payload.DumpFilename, "X", sizeof(DumpRegCmd.Payload.DumpFilename) - 1); - DumpRegCmd.Payload.DumpFilename[sizeof(DumpRegCmd.Payload.DumpFilename) - 1] = '\0'; + /* Test with record numb beyond EOF (should be ignored, return null) */ + IsEOF = CFE_TBL_DumpRegistryGetter(&CFE_TBL_Global.RegDumpState, CFE_PLATFORM_TBL_MAX_NUM_TABLES+1, &LocalBuf, &LocalSize); UT_Report(__FILE__, __LINE__, - CFE_TBL_DumpRegistryCmd(&DumpRegCmd) == - CFE_TBL_INC_CMD_CTR, - "CFE_TBL_DumpRegistryCmd", - "Default dump file name"); + IsEOF, + "CFE_TBL_DumpRegistryGetter", + "Past end of file"); + UtAssert_NULL(LocalBuf); + UtAssert_ZERO(LocalSize); + } /* diff --git a/fsw/cfe-core/ut-stubs/ut_es_stubs.c b/fsw/cfe-core/ut-stubs/ut_es_stubs.c index f10629b61..57b1bd105 100644 --- a/fsw/cfe-core/ut-stubs/ut_es_stubs.c +++ b/fsw/cfe-core/ut-stubs/ut_es_stubs.c @@ -1336,3 +1336,8 @@ int32 CFE_ES_TaskID_ToIndex(CFE_ES_TaskId_t TaskID, uint32 *Idx) return return_code; } + +void CFE_ES_BackgroundWakeup(void) +{ + UT_DEFAULT_IMPL(CFE_ES_BackgroundWakeup); +} diff --git a/fsw/cfe-core/ut-stubs/ut_fs_stubs.c b/fsw/cfe-core/ut-stubs/ut_fs_stubs.c index 126fe2d3a..f3bdaf3cd 100644 --- a/fsw/cfe-core/ut-stubs/ut_fs_stubs.c +++ b/fsw/cfe-core/ut-stubs/ut_fs_stubs.c @@ -304,3 +304,40 @@ int32 CFE_FS_ExtractFilenameFromPath(const char *OriginalPath, char *FileNameOnl return status; } + +bool CFE_FS_RunBackgroundFileDump(uint32 ElapsedTime, void *Arg) +{ + UT_Stub_RegisterContextGenericArg(UT_KEY(CFE_FS_RunBackgroundFileDump), ElapsedTime); + UT_Stub_RegisterContextGenericArg(UT_KEY(CFE_FS_RunBackgroundFileDump), Arg); + + int32 status; + + status = UT_DEFAULT_IMPL(CFE_FS_RunBackgroundFileDump); + + return status; +} + +int32 CFE_FS_BackgroundFileDumpRequest(CFE_FS_FileWriteMetaData_t *Meta) +{ + UT_Stub_RegisterContextGenericArg(UT_KEY(CFE_FS_BackgroundFileDumpRequest), Meta); + + int32 status; + + status = UT_DEFAULT_IMPL(CFE_FS_BackgroundFileDumpRequest); + + if (status == CFE_SUCCESS) + { + /* Snapshot the request, in case the UT test case wants to look */ + UT_Stub_CopyFromLocal(UT_KEY(CFE_FS_BackgroundFileDumpRequest), Meta, sizeof(*Meta)); + } + + return status; +} + +bool CFE_FS_BackgroundFileDumpIsPending(const CFE_FS_FileWriteMetaData_t *Meta) +{ + UT_Stub_RegisterContextGenericArg(UT_KEY(CFE_FS_BackgroundFileDumpIsPending), Meta); + + return UT_DEFAULT_IMPL(CFE_FS_BackgroundFileDumpIsPending); + +} From 58abd38d04390cbe123d89b57819af013464d57f Mon Sep 17 00:00:00 2001 From: Joseph Hickey Date: Tue, 2 Feb 2021 22:55:09 -0500 Subject: [PATCH 3/7] Fix #978, store task parameters in task record Implement a "CFE_ES_TaskStartParams_t" to complement the existing "CFE_ES_AppStartParams_t" and store this in the task record. This permits some nice cleanup: - All tasks can now use the same basic start function CFE_ES_StartAppTask() - No special/different logic is needed for main tasks/child tasks - Simplified APIs as parameters can be encapsulated in a single struct. - Fixes a race condition where child tasks may not be fully instantiated at the time the task function is invoked. --- fsw/cfe-core/src/es/cfe_es_api.c | 186 ++++++------- fsw/cfe-core/src/es/cfe_es_apps.c | 379 +++++++++++++------------- fsw/cfe-core/src/es/cfe_es_apps.h | 94 ++++--- fsw/cfe-core/src/es/cfe_es_objtab.c | 10 +- fsw/cfe-core/src/es/cfe_es_resource.h | 4 +- fsw/cfe-core/src/es/cfe_es_start.c | 20 +- fsw/cfe-core/src/es/cfe_es_start.h | 3 +- fsw/cfe-core/src/es/cfe_es_task.c | 39 ++- fsw/cfe-core/src/inc/cfe_es.h | 11 +- fsw/cfe-core/unit-test/es_UT.c | 292 +++++++++++--------- 10 files changed, 528 insertions(+), 510 deletions(-) diff --git a/fsw/cfe-core/src/es/cfe_es_api.c b/fsw/cfe-core/src/es/cfe_es_api.c index 916264a1d..54304aecb 100644 --- a/fsw/cfe-core/src/es/cfe_es_api.c +++ b/fsw/cfe-core/src/es/cfe_es_api.c @@ -1015,15 +1015,15 @@ int32 CFE_ES_GetAppInfo(CFE_ES_AppInfo_t *AppInfo, CFE_ES_AppId_t AppId) AppInfo->ResourceId = CFE_RESOURCEID_UNWRAP(AppId); /* make into a generic resource ID */ AppInfo->Type = AppRecPtr->Type; + strncpy(AppInfo->Name, CFE_ES_AppRecordGetName(AppRecPtr), sizeof(AppInfo->Name)-1); + CFE_ES_CopyModuleBasicInfo(&AppRecPtr->StartParams.BasicInfo, AppInfo); - CFE_ES_CopyModuleStatusInfo(&AppRecPtr->ModuleInfo, AppInfo); + CFE_ES_CopyModuleStatusInfo(&AppRecPtr->LoadStatus, AppInfo); - AppInfo->StackSize = AppRecPtr->StartParams.StackSize; AppInfo->ExceptionAction = AppRecPtr->StartParams.ExceptionAction; - AppInfo->Priority = AppRecPtr->StartParams.Priority; AppInfo->MainTaskId = AppRecPtr->MainTaskId; - ModuleId = AppRecPtr->ModuleInfo.ModuleId; + ModuleId = AppRecPtr->LoadStatus.ModuleId; /* ** Calculate the number of child tasks @@ -1042,6 +1042,10 @@ int32 CFE_ES_GetAppInfo(CFE_ES_AppInfo_t *AppInfo, CFE_ES_AppId_t AppId) strncpy(AppInfo->MainTaskName, TaskRecPtr->TaskName, sizeof(AppInfo->MainTaskName) - 1); AppInfo->MainTaskName[sizeof(AppInfo->MainTaskName) - 1] = '\0'; + + AppInfo->StackSize = TaskRecPtr->StartParams.StackSize; + AppInfo->Priority = TaskRecPtr->StartParams.Priority; + } else { @@ -1105,10 +1109,12 @@ int32 CFE_ES_GetLibInfo(CFE_ES_AppInfo_t *LibInfo, CFE_ES_LibId_t LibId) LibInfo->ResourceId = CFE_RESOURCEID_UNWRAP(LibId); /* make into generic ID */ LibInfo->Type = CFE_ES_AppType_LIBRARY; - CFE_ES_CopyModuleBasicInfo(&LibRecPtr->BasicInfo, LibInfo); - CFE_ES_CopyModuleStatusInfo(&LibRecPtr->ModuleInfo, LibInfo); + strncpy(LibInfo->Name, CFE_ES_LibRecordGetName(LibRecPtr), sizeof(LibInfo->Name)-1); - ModuleId = LibRecPtr->ModuleInfo.ModuleId; + CFE_ES_CopyModuleBasicInfo(&LibRecPtr->LoadParams, LibInfo); + CFE_ES_CopyModuleStatusInfo(&LibRecPtr->LoadStatus, LibInfo); + + ModuleId = LibRecPtr->LoadStatus.ModuleId; Status = CFE_SUCCESS; } @@ -1243,108 +1249,90 @@ int32 CFE_ES_CreateChildTask(CFE_ES_TaskId_t *TaskIdPtr, CFE_ES_TaskPriority_Atom_t Priority, uint32 Flags) { + int32 ReturnCode; + CFE_ES_AppRecord_t * AppRecPtr; + CFE_ES_AppId_t ParentAppId; + CFE_ES_TaskId_t SelfTaskId; + CFE_ES_TaskStartParams_t Params; - int32 Result; - CFE_ES_AppRecord_t *AppRecPtr; - CFE_ES_TaskRecord_t *TaskRecPtr; - int32 ReturnCode; - CFE_ES_TaskId_t SelfTaskId; - CFE_ES_TaskId_t LocalChildTaskId; - osal_id_t OsalId; + ParentAppId = CFE_ES_APPID_UNDEFINED; - /* - ** Validate some of the arguments - */ - if ( TaskIdPtr == NULL ) - { - if (TaskName == NULL) - { - CFE_ES_WriteToSysLog("CFE_ES_CreateChildTask: Task Id and Name Pointer Parameters are NULL.\n"); - ReturnCode = CFE_ES_BAD_ARGUMENT; - } - else - { - CFE_ES_WriteToSysLog("CFE_ES_CreateChildTask: Task Id Pointer Parameter is NULL for Task '%s'.\n",TaskName); - ReturnCode = CFE_ES_BAD_ARGUMENT; - } - } - else if ( TaskName == NULL ) - { - CFE_ES_WriteToSysLog("CFE_ES_CreateChildTask: TaskName Parameter is NULL\n"); - ReturnCode = CFE_ES_BAD_ARGUMENT; - } - else if ( FunctionPtr == NULL ) - { - CFE_ES_WriteToSysLog("CFE_ES_CreateChildTask: Function Pointer Parameter is NULL for Task '%s'\n",TaskName); - ReturnCode = CFE_ES_BAD_ARGUMENT; - } - else - { - - CFE_ES_LockSharedData(__func__,__LINE__); + memset(&Params, 0, sizeof(Params)); + Params.Priority = Priority; + Params.StackSize = StackSize; - /* - ** Get the App Record of the calling Application - */ - AppRecPtr = CFE_ES_GetAppRecordByContext(); - if (AppRecPtr == NULL) - { - CFE_ES_SysLogWrite_Unsync("CFE_ES_CreateChildTask: Invalid calling context when creating Task '%s'\n",TaskName); - ReturnCode = CFE_ES_ERR_RESOURCEID_NOT_VALID; - } - else /* else AppId is valid */ - { - /* - ** First, Make sure the Calling Task is a cFE Main task. - ** TaskID must be the same as the Parent Task ID. - */ - OsalId = OS_TaskGetId(); - SelfTaskId = CFE_ES_TaskId_FromOSAL(OsalId); - if ( CFE_RESOURCEID_TEST_EQUAL(SelfTaskId, AppRecPtr->MainTaskId) ) - { - /* - ** Step 2: Create the new task using the OS API call - */ - Result = OS_TaskCreate(&OsalId, TaskName, FunctionPtr, StackPtr, - StackSize, Priority, OS_FP_ENABLED ); - - /* - ** Step 3: Record the task information in the task table - */ - if ( Result == OS_SUCCESS ) - { - LocalChildTaskId = CFE_ES_TaskId_FromOSAL(OsalId); - TaskRecPtr = CFE_ES_LocateTaskRecordByID(LocalChildTaskId); + /* + ** Validate some of the arguments + */ + if (TaskIdPtr == NULL) + { + if (TaskName == NULL) + { + CFE_ES_WriteToSysLog("CFE_ES_CreateChildTask: Task Id and Name Pointer Parameters are NULL.\n"); + ReturnCode = CFE_ES_BAD_ARGUMENT; + } + else + { + CFE_ES_WriteToSysLog("CFE_ES_CreateChildTask: Task Id Pointer Parameter is NULL for Task '%s'.\n", + TaskName); + ReturnCode = CFE_ES_BAD_ARGUMENT; + } + } + else if (TaskName == NULL) + { + CFE_ES_WriteToSysLog("CFE_ES_CreateChildTask: TaskName Parameter is NULL\n"); + ReturnCode = CFE_ES_BAD_ARGUMENT; + } + else if (FunctionPtr == NULL) + { + CFE_ES_WriteToSysLog("CFE_ES_CreateChildTask: Function Pointer Parameter is NULL for Task '%s'\n", TaskName); + ReturnCode = CFE_ES_BAD_ARGUMENT; + } + else + { + /* + ** First, Make sure the Calling Task is a cFE Main task. + ** TaskID must be the same as the Parent Task ID. + */ + SelfTaskId = CFE_ES_TaskId_FromOSAL(OS_TaskGetId()); - CFE_ES_TaskRecordSetUsed(TaskRecPtr, CFE_RESOURCEID_UNWRAP(LocalChildTaskId)); - TaskRecPtr->AppId = CFE_ES_AppRecordGetID(AppRecPtr); - strncpy(TaskRecPtr->TaskName,TaskName,sizeof(TaskRecPtr->TaskName) - 1); - TaskRecPtr->TaskName[sizeof(TaskRecPtr->TaskName) - 1] = '\0'; - CFE_ES_Global.RegisteredTasks++; + CFE_ES_LockSharedData(__func__, __LINE__); - *TaskIdPtr = CFE_ES_TaskRecordGetID(TaskRecPtr); - ReturnCode = CFE_SUCCESS; - } - else - { - CFE_ES_SysLogWrite_Unsync("CFE_ES_CreateChildTask: Error calling OS_TaskCreate for Task '%s' RC = 0x%08X\n",TaskName,(unsigned int)Result); - ReturnCode = CFE_ES_ERR_CHILD_TASK_CREATE; - } - } - else - { - CFE_ES_SysLogWrite_Unsync("CFE_ES_CreateChildTask: Error: Cannot call from a Child Task (for Task '%s').\n",TaskName); + /* + ** Get the App Record of the calling Application + */ + AppRecPtr = CFE_ES_GetAppRecordByContext(); + if (AppRecPtr == NULL) + { + CFE_ES_SysLogWrite_Unsync("CFE_ES_CreateChildTask: Invalid calling context when creating Task '%s'\n", + TaskName); + ReturnCode = CFE_ES_ERR_RESOURCEID_NOT_VALID; + } + else if (!CFE_RESOURCEID_TEST_EQUAL(SelfTaskId, AppRecPtr->MainTaskId)) + { + CFE_ES_SysLogWrite_Unsync("CFE_ES_CreateChildTask: Error: Cannot call from a Child Task (for Task '%s').\n", + TaskName); ReturnCode = CFE_ES_ERR_CHILD_TASK_CREATE; + } + else + { + ParentAppId = CFE_ES_AppRecordGetID(AppRecPtr); + ReturnCode = CFE_SUCCESS; + } /* end If AppID is valid */ - } /* end if Calling task is a main task */ - - }/* end If AppID is valid */ + CFE_ES_UnlockSharedData(__func__, __LINE__); - CFE_ES_UnlockSharedData(__func__,__LINE__); + } /* end if parameter checking */ - } /* end if parameter checking */ + /* + ** Step 2: Create the new task if the parameter validation succeeded + */ + if (ReturnCode == CFE_SUCCESS) + { + ReturnCode = CFE_ES_StartAppTask(TaskIdPtr, TaskName, FunctionPtr, &Params, ParentAppId); + } - return(ReturnCode); + return (ReturnCode); } /* End of CFE_ES_CreateChildTask() */ diff --git a/fsw/cfe-core/src/es/cfe_es_apps.c b/fsw/cfe-core/src/es/cfe_es_apps.c index 8e825dfb3..fddb1203b 100644 --- a/fsw/cfe-core/src/es/cfe_es_apps.c +++ b/fsw/cfe-core/src/es/cfe_es_apps.c @@ -263,104 +263,98 @@ void CFE_ES_StartApplications(uint32 ResetType, const char *StartFilePath ) */ int32 CFE_ES_ParseFileEntry(const char **TokenList, uint32 NumTokens) { - const char *FileName; - const char *AppName; - const char *EntryPoint; - const char *EntryType; - unsigned long PriorityIn; - unsigned long StackSizeIn; - unsigned long ExceptionActionIn; - union - { + const char * ModuleName; + const char * EntryType; + unsigned long ParsedValue; + union + { CFE_ES_AppId_t AppId; CFE_ES_LibId_t LibId; - } IdBuf; - int32 CreateStatus = CFE_ES_ERR_APP_CREATE; + } IdBuf; + int32 CreateStatus = CFE_ES_ERR_APP_CREATE; + CFE_ES_AppStartParams_t ParamBuf; - /* - ** Check to see if the correct number of items were parsed - */ - if ( NumTokens < 8 ) - { - CFE_ES_WriteToSysLog("ES Startup: Invalid ES Startup file entry: %u\n",(unsigned int)NumTokens); - return (CreateStatus); - } + /* + ** Check to see if the correct number of items were parsed + */ + if (NumTokens < 8) + { + CFE_ES_WriteToSysLog("ES Startup: Invalid ES Startup file entry: %u\n", (unsigned int)NumTokens); + return (CreateStatus); + } - EntryType = TokenList[0]; - FileName = TokenList[1]; - EntryPoint = TokenList[2]; - AppName = TokenList[3]; + /* Get pointers to specific tokens that are simple strings used as-is */ + EntryType = TokenList[0]; + ModuleName = TokenList[3]; - /* - * NOTE: In previous CFE versions the sscanf() function was used to convert - * these string values into integers. This approach of using the pre-tokenized strings - * and strtoul() is safer but the side effect is that it will also be more "permissive" in - * what is accepted vs. rejected by this function. - * - * For instance if the startup script contains "123xyz", this will be converted to the value - * 123 instead of triggering a validation failure as it would have in CFE <= 6.5.0. - * - * This permissive parsing should not be relied upon, as it may become more strict again in - * future CFE revisions. - * - * Also note that this uses "unsigned long" as that is the defined output type of strtoul(). - * It will be converted to the correct type later. - */ - PriorityIn = strtoul(TokenList[4], NULL, 0); - StackSizeIn = strtoul(TokenList[5], NULL, 0); - ExceptionActionIn = strtoul(TokenList[7], NULL, 0); + /* + * Other tokens will need to be scrubbed/converted. + * Both Libraries and Apps use File Name (1) and Symbol Name (2) fields so copy those now + */ + memset(&ParamBuf, 0, sizeof(ParamBuf)); + strncpy(ParamBuf.BasicInfo.FileName, TokenList[1], sizeof(ParamBuf.BasicInfo.FileName) - 1); + strncpy(ParamBuf.BasicInfo.InitSymbolName, TokenList[2], sizeof(ParamBuf.BasicInfo.InitSymbolName) - 1); - if(strcmp(EntryType,"CFE_APP")==0) - { - CFE_ES_WriteToSysLog("ES Startup: Loading file: %s, APP: %s\n", - FileName, AppName); + if (strcmp(EntryType, "CFE_APP") == 0) + { + CFE_ES_WriteToSysLog("ES Startup: Loading file: %s, APP: %s\n", ParamBuf.BasicInfo.FileName, ModuleName); - /* - ** Validate Some parameters - ** Exception action should be 0 ( Restart App ) or - ** 1 ( Processor reset ). If it's non-zero, assume it means - ** reset CPU. - */ - if ( ExceptionActionIn > CFE_ES_ExceptionAction_RESTART_APP ) - { - ExceptionActionIn = CFE_ES_ExceptionAction_PROC_RESTART; - } + /* + * Priority and Exception action have limited ranges, which is checked here + * Task priority cannot be bigger than OS_MAX_TASK_PRIORITY + */ + ParsedValue = strtoul(TokenList[4], NULL, 0); + if (ParsedValue > OS_MAX_TASK_PRIORITY) + { + ParamBuf.MainTaskInfo.Priority = OS_MAX_TASK_PRIORITY; + } + else + { + /* convert parsed value to correct type */ + ParamBuf.MainTaskInfo.Priority = (CFE_ES_TaskPriority_Atom_t)ParsedValue; + } - /* - * Task priority cannot be bigger than OS_MAX_TASK_PRIORITY - */ - if ( PriorityIn > OS_MAX_TASK_PRIORITY ) - { - PriorityIn = OS_MAX_TASK_PRIORITY; - } + /* No specific upper/lower limit for stack size - will pass value through */ + ParamBuf.MainTaskInfo.StackSize = strtoul(TokenList[5], NULL, 0); - /* - ** Now create the application - */ - CreateStatus = CFE_ES_AppCreate(&IdBuf.AppId, FileName, - EntryPoint, AppName, - PriorityIn, - StackSizeIn, - ExceptionActionIn); - } - else if(strcmp(EntryType,"CFE_LIB")==0) - { - CFE_ES_WriteToSysLog("ES Startup: Loading shared library: %s\n",FileName); - /* - ** Now load the library - */ - CreateStatus = CFE_ES_LoadLibrary(&IdBuf.LibId, FileName, - EntryPoint, AppName); + /* + ** Validate Some parameters + ** Exception action should be 0 ( Restart App ) or + ** 1 ( Processor reset ). If it's non-zero, assume it means + ** reset CPU. + */ + ParsedValue = strtoul(TokenList[7], NULL, 0); + if (ParsedValue > CFE_ES_ExceptionAction_RESTART_APP) + { + ParamBuf.ExceptionAction = CFE_ES_ExceptionAction_PROC_RESTART; + } + else + { + /* convert parsed value to correct type */ + ParamBuf.ExceptionAction = (CFE_ES_ExceptionAction_Enum_t)ParsedValue; + } - } - else - { - CFE_ES_WriteToSysLog("ES Startup: Unexpected EntryType %s in startup file.\n",EntryType); - } + /* + ** Now create the application + */ + CreateStatus = CFE_ES_AppCreate(&IdBuf.AppId, ModuleName, &ParamBuf); + } + else if (strcmp(EntryType, "CFE_LIB") == 0) + { + CFE_ES_WriteToSysLog("ES Startup: Loading shared library: %s\n", ParamBuf.BasicInfo.FileName); - return (CreateStatus); + /* + ** Now load the library + */ + CreateStatus = CFE_ES_LoadLibrary(&IdBuf.LibId, ModuleName, &ParamBuf.BasicInfo); + } + else + { + CFE_ES_WriteToSysLog("ES Startup: Unexpected EntryType %s in startup file.\n", EntryType); + } + return (CreateStatus); } /* @@ -373,21 +367,21 @@ int32 CFE_ES_ParseFileEntry(const char **TokenList, uint32 NumTokens) ** **------------------------------------------------------------------------------------- */ -int32 CFE_ES_LoadModule(CFE_ResourceId_t ResourceId, const CFE_ES_ModuleLoadParams_t* LoadParams, CFE_ES_ModuleLoadStatus_t *LoadStatus) +int32 CFE_ES_LoadModule(CFE_ResourceId_t ParentResourceId, const char *ModuleName, const CFE_ES_ModuleLoadParams_t* LoadParams, CFE_ES_ModuleLoadStatus_t *LoadStatus) { osal_id_t ModuleId; - cpuaddr StartAddr; + cpuaddr InitSymbolAddress; int32 ReturnCode; int32 StatusCode; uint32 LoadFlags; LoadFlags = 0; - StartAddr = 0; + InitSymbolAddress = 0; ReturnCode = CFE_SUCCESS; if (LoadParams->FileName[0] != 0) { - switch(CFE_ResourceId_GetBase(ResourceId)) + switch(CFE_ResourceId_GetBase(ParentResourceId)) { case CFE_ES_APPID_BASE: /* @@ -417,7 +411,7 @@ int32 CFE_ES_LoadModule(CFE_ResourceId_t ResourceId, const CFE_ES_ModuleLoadPara * Load the module via OSAL. */ StatusCode = OS_ModuleLoad ( &ModuleId, - LoadParams->Name, + ModuleName, LoadParams->FileName, LoadFlags ); @@ -437,13 +431,13 @@ int32 CFE_ES_LoadModule(CFE_ResourceId_t ResourceId, const CFE_ES_ModuleLoadPara /* * If the Load was OK, then lookup the address of the entry point */ - if (ReturnCode == CFE_SUCCESS && LoadParams->EntryPoint[0] != 0) + if (ReturnCode == CFE_SUCCESS && LoadParams->InitSymbolName[0] != 0) { - StatusCode = OS_ModuleSymbolLookup(ModuleId, &StartAddr, LoadParams->EntryPoint); + StatusCode = OS_ModuleSymbolLookup(ModuleId, &InitSymbolAddress, LoadParams->InitSymbolName); if (StatusCode != OS_SUCCESS) { CFE_ES_WriteToSysLog("ES Startup: Could not find symbol:%s. EC = 0x%08X\n", - LoadParams->EntryPoint, (unsigned int)StatusCode); + LoadParams->InitSymbolName, (unsigned int)StatusCode); ReturnCode = CFE_STATUS_EXTERNAL_RESOURCE_FAIL; } } @@ -452,7 +446,7 @@ int32 CFE_ES_LoadModule(CFE_ResourceId_t ResourceId, const CFE_ES_ModuleLoadPara { /* store the data in the app record after successful load+lookup */ LoadStatus->ModuleId = ModuleId; - LoadStatus->EntryAddress = StartAddr; + LoadStatus->InitSymbolAddress = InitSymbolAddress; } else if (OS_ObjectIdDefined(ModuleId)) { @@ -462,7 +456,7 @@ int32 CFE_ES_LoadModule(CFE_ResourceId_t ResourceId, const CFE_ES_ModuleLoadPara if ( StatusCode != OS_SUCCESS ) /* There's not much we can do except notify */ { CFE_ES_WriteToSysLog("ES Startup: Failed to unload: %s. EC = 0x%08X\n", - LoadParams->Name, (unsigned int)StatusCode); + ModuleName, (unsigned int)StatusCode); } } @@ -471,7 +465,7 @@ int32 CFE_ES_LoadModule(CFE_ResourceId_t ResourceId, const CFE_ES_ModuleLoadPara /* **------------------------------------------------------------------------------------- -** Name: CFE_ES_GetAppEntryPoint +** Name: CFE_ES_GetTaskFunction ** ** Helper function to act as the intermediate entry point of an app ** This is to support starting apps before having a fully completed entry in the @@ -480,9 +474,11 @@ int32 CFE_ES_LoadModule(CFE_ResourceId_t ResourceId, const CFE_ES_ModuleLoadPara ** **------------------------------------------------------------------------------------- */ -int32 CFE_ES_GetAppEntryPoint(osal_task_entry *FuncPtr) +int32 CFE_ES_GetTaskFunction(CFE_ES_TaskEntryFuncPtr_t *FuncPtr) { - CFE_ES_AppRecord_t *AppRecPtr; + CFE_ES_TaskRecord_t *TaskRecPtr; + CFE_ES_AppId_t AppId; + CFE_ES_TaskEntryFuncPtr_t EntryFunc; int32 ReturnCode; int32 Timeout; @@ -491,18 +487,23 @@ int32 CFE_ES_GetAppEntryPoint(osal_task_entry *FuncPtr) */ ReturnCode = CFE_ES_ERR_APP_REGISTER; Timeout = CFE_PLATFORM_ES_STARTUP_SCRIPT_TIMEOUT_MSEC; + AppId = CFE_ES_APPID_UNDEFINED; + EntryFunc = NULL; while(true) { OS_TaskDelay(CFE_PLATFORM_ES_STARTUP_SYNC_POLL_MSEC); CFE_ES_LockSharedData(__func__,__LINE__); - AppRecPtr = CFE_ES_GetAppRecordByContext(); - if (AppRecPtr != NULL) + TaskRecPtr = CFE_ES_GetTaskRecordByContext(); + if (TaskRecPtr != NULL) { - AppRecPtr->AppState = CFE_ES_AppState_EARLY_INIT; - *FuncPtr = (osal_task_entry)AppRecPtr->ModuleInfo.EntryAddress; - ReturnCode = CFE_SUCCESS; + AppId = TaskRecPtr->AppId; + EntryFunc = TaskRecPtr->EntryFunc; + if (CFE_RESOURCEID_TEST_DEFINED(AppId) && EntryFunc != 0) + { + ReturnCode = CFE_SUCCESS; + } } CFE_ES_UnlockSharedData(__func__,__LINE__); @@ -515,12 +516,18 @@ int32 CFE_ES_GetAppEntryPoint(osal_task_entry *FuncPtr) Timeout -= CFE_PLATFORM_ES_STARTUP_SYNC_POLL_MSEC; } + /* output function address to caller */ + if (FuncPtr != NULL) + { + *FuncPtr = EntryFunc; + } + return (ReturnCode); } /* **------------------------------------------------------------------------------------- -** Name: CFE_ES_AppEntryPoint +** Name: CFE_ES_TaskEntryPoint ** ** Helper function to act as the intermediate entry point of an app ** This is to support starting apps before having a fully completed entry in the @@ -529,11 +536,11 @@ int32 CFE_ES_GetAppEntryPoint(osal_task_entry *FuncPtr) ** **------------------------------------------------------------------------------------- */ -void CFE_ES_AppEntryPoint(void) +void CFE_ES_TaskEntryPoint(void) { - osal_task_entry RealEntryFunc; + CFE_ES_TaskEntryFuncPtr_t RealEntryFunc; - if (CFE_ES_GetAppEntryPoint(&RealEntryFunc) == CFE_SUCCESS && + if (CFE_ES_GetTaskFunction(&RealEntryFunc) == CFE_SUCCESS && RealEntryFunc != NULL) { (*RealEntryFunc)(); @@ -556,7 +563,7 @@ void CFE_ES_AppEntryPoint(void) ** **------------------------------------------------------------------------------------- */ -int32 CFE_ES_StartAppTask(const CFE_ES_AppStartParams_t* StartParams, CFE_ES_AppId_t RefAppId, CFE_ES_TaskId_t *TaskIdPtr) +int32 CFE_ES_StartAppTask(CFE_ES_TaskId_t *TaskIdPtr, const char *TaskName, CFE_ES_TaskEntryFuncPtr_t EntryFunc, const CFE_ES_TaskStartParams_t* Params, CFE_ES_AppId_t ParentAppId) { CFE_ES_TaskRecord_t *TaskRecPtr; osal_id_t OsalTaskId; @@ -565,15 +572,15 @@ int32 CFE_ES_StartAppTask(const CFE_ES_AppStartParams_t* StartParams, CFE_ES_App int32 ReturnCode; /* - ** Create the primary task for the newly loaded task + * Create the primary task for the newly loaded task */ - StatusCode = OS_TaskCreate(&OsalTaskId, /* task id */ - StartParams->BasicInfo.Name, /* task name */ - CFE_ES_AppEntryPoint, /* task function pointer */ - OSAL_TASK_STACK_ALLOCATE, /* stack pointer (allocate) */ - StartParams->StackSize, /* stack size */ - StartParams->Priority, /* task priority */ - OS_FP_ENABLED); /* task options */ + StatusCode = OS_TaskCreate(&OsalTaskId, /* task id */ + TaskName, /* task name matches app name for main task */ + CFE_ES_TaskEntryPoint, /* task function pointer */ + OSAL_TASK_STACK_ALLOCATE, /* stack pointer (allocate) */ + Params->StackSize, /* stack size */ + Params->Priority, /* task priority */ + OS_FP_ENABLED); /* task options */ CFE_ES_LockSharedData(__func__,__LINE__); @@ -598,13 +605,17 @@ int32 CFE_ES_StartAppTask(const CFE_ES_AppStartParams_t* StartParams, CFE_ES_App */ memset(TaskRecPtr, 0, sizeof(*TaskRecPtr)); - TaskRecPtr->AppId = RefAppId; - strncpy(TaskRecPtr->TaskName, StartParams->BasicInfo.Name, sizeof(TaskRecPtr->TaskName)-1); + TaskRecPtr->AppId = ParentAppId; + TaskRecPtr->EntryFunc = EntryFunc; + TaskRecPtr->StartParams = *Params; + + strncpy(TaskRecPtr->TaskName, TaskName, sizeof(TaskRecPtr->TaskName)-1); TaskRecPtr->TaskName[sizeof(TaskRecPtr->TaskName)-1] = 0; + CFE_ES_TaskRecordSetUsed(TaskRecPtr, CFE_RESOURCEID_UNWRAP(LocalTaskId)); /* - ** Increment the registered Task count. + * Increment the registered Task count. */ CFE_ES_Global.RegisteredTasks++; ReturnCode = CFE_SUCCESS; @@ -613,7 +624,7 @@ int32 CFE_ES_StartAppTask(const CFE_ES_AppStartParams_t* StartParams, CFE_ES_App else { CFE_ES_SysLogWrite_Unsync("ES Startup: AppCreate Error: TaskCreate %s Failed. EC = 0x%08X!\n", - StartParams->BasicInfo.Name,(unsigned int)StatusCode); + TaskName,(unsigned int)StatusCode); ReturnCode = CFE_STATUS_EXTERNAL_RESOURCE_FAIL; *TaskIdPtr = CFE_ES_TASKID_UNDEFINED; } @@ -634,28 +645,22 @@ int32 CFE_ES_StartAppTask(const CFE_ES_AppStartParams_t* StartParams, CFE_ES_App ** **--------------------------------------------------------------------------------------- */ -int32 CFE_ES_AppCreate(CFE_ES_AppId_t *ApplicationIdPtr, - const char *FileName, - const char *EntryPointName, - const char *AppName, - CFE_ES_TaskPriority_Atom_t Priority, - size_t StackSize, - CFE_ES_ExceptionAction_Enum_t ExceptionAction) +int32 CFE_ES_AppCreate(CFE_ES_AppId_t *ApplicationIdPtr, const char *AppName, const CFE_ES_AppStartParams_t *Params) { CFE_Status_t Status; - CFE_ES_TaskId_t MainTaskId; CFE_ES_AppRecord_t *AppRecPtr; CFE_ResourceId_t PendingResourceId; /* - * The FileName must not be NULL + * The AppName must not be NULL */ - if (FileName == NULL || AppName == NULL) + if (AppName == NULL || Params == NULL) { return CFE_ES_BAD_ARGUMENT; } - if (strlen(AppName) >= OS_MAX_API_NAME) + /* Confirm name will fit inside the record */ + if (memchr(AppName,0,sizeof(AppRecPtr->AppName)) == NULL) { return CFE_ES_BAD_ARGUMENT; } @@ -705,27 +710,19 @@ int32 CFE_ES_AppCreate(CFE_ES_AppId_t *ApplicationIdPtr, /* Fully clear the entry, just in case of stale data */ memset(AppRecPtr, 0, sizeof(*AppRecPtr)); + /* Store the app name from passed-in value */ + strncpy(AppRecPtr->AppName, AppName, sizeof(AppRecPtr->AppName)-1); + + AppRecPtr->Type = CFE_ES_AppType_EXTERNAL; + /* * Fill out the parameters in the StartParams sub-structure + * + * This contains all relevant info, including file name, entry point, + * main task info, etc. which is required to start the app now + * or in a future restart/reload request. */ - AppRecPtr->Type = CFE_ES_AppType_EXTERNAL; - strncpy(AppRecPtr->StartParams.BasicInfo.Name, AppName, - sizeof(AppRecPtr->StartParams.BasicInfo.Name)-1); - AppRecPtr->StartParams.BasicInfo.Name[sizeof(AppRecPtr->StartParams.BasicInfo.Name)-1] = '\0'; - strncpy(AppRecPtr->StartParams.BasicInfo.FileName, FileName, - sizeof(AppRecPtr->StartParams.BasicInfo.FileName)-1); - AppRecPtr->StartParams.BasicInfo.FileName[sizeof(AppRecPtr->StartParams.BasicInfo.FileName)-1] = '\0'; - if (EntryPointName != NULL && strcmp(EntryPointName, "NULL") != 0) - { - strncpy(AppRecPtr->StartParams.BasicInfo.EntryPoint, EntryPointName, - sizeof(AppRecPtr->StartParams.BasicInfo.EntryPoint)-1); - AppRecPtr->StartParams.BasicInfo.EntryPoint[ - sizeof(AppRecPtr->StartParams.BasicInfo.EntryPoint)-1] = '\0'; - } - - AppRecPtr->StartParams.StackSize = StackSize; - AppRecPtr->StartParams.ExceptionAction = ExceptionAction; - AppRecPtr->StartParams.Priority = Priority; + AppRecPtr->StartParams = *Params; /* * Fill out the Task State info @@ -753,18 +750,19 @@ int32 CFE_ES_AppCreate(CFE_ES_AppId_t *ApplicationIdPtr, /* * Load the module based on StartParams configured above. */ - Status = CFE_ES_LoadModule(PendingResourceId, &AppRecPtr->StartParams.BasicInfo, &AppRecPtr->ModuleInfo); + Status = CFE_ES_LoadModule(PendingResourceId, AppName, &AppRecPtr->StartParams.BasicInfo, &AppRecPtr->LoadStatus); /* * If the Load was OK, then complete the initialization */ if (Status == CFE_SUCCESS) { - Status = CFE_ES_StartAppTask(&AppRecPtr->StartParams, CFE_ES_APPID_C(PendingResourceId), &MainTaskId); - } - else - { - MainTaskId = CFE_ES_TASKID_UNDEFINED; + Status = CFE_ES_StartAppTask(&AppRecPtr->MainTaskId, /* Task ID (output) stored in App Record as main task */ + AppName, /* Main Task name matches app name */ + (CFE_ES_TaskEntryFuncPtr_t)AppRecPtr->LoadStatus + .InitSymbolAddress, /* Init Symbol is main task entry point */ + &AppRecPtr->StartParams.MainTaskInfo, /* Main task parameters */ + CFE_ES_APPID_C(PendingResourceId)); /* Parent App ID */ } /* @@ -779,7 +777,6 @@ int32 CFE_ES_AppCreate(CFE_ES_AppId_t *ApplicationIdPtr, * important - set the ID to its proper value * which turns this into a real/valid table entry */ - AppRecPtr->MainTaskId = MainTaskId; CFE_ES_AppRecordSetUsed(AppRecPtr, PendingResourceId); /* @@ -812,10 +809,7 @@ int32 CFE_ES_AppCreate(CFE_ES_AppId_t *ApplicationIdPtr, ** **--------------------------------------------------------------------------------------- */ -int32 CFE_ES_LoadLibrary(CFE_ES_LibId_t *LibraryIdPtr, - const char *FileName, - const char *EntryPointName, - const char *LibName) +int32 CFE_ES_LoadLibrary(CFE_ES_LibId_t *LibraryIdPtr, const char *LibName, const CFE_ES_ModuleLoadParams_t *Params) { CFE_ES_LibraryEntryFuncPtr_t FunctionPointer; CFE_ES_LibRecord_t * LibSlotPtr; @@ -823,14 +817,15 @@ int32 CFE_ES_LoadLibrary(CFE_ES_LibId_t *LibraryIdPtr, CFE_ResourceId_t PendingResourceId; /* - * The FileName must not be NULL + * The LibName must not be NULL */ - if (FileName == NULL || LibName == NULL) + if (LibName == NULL || Params == NULL) { return CFE_ES_BAD_ARGUMENT; } - if (strlen(LibName) >= OS_MAX_API_NAME) + /* Confirm name will fit inside the record */ + if (memchr(LibName,0,sizeof(LibSlotPtr->LibName)) == NULL) { return CFE_ES_BAD_ARGUMENT; } @@ -889,18 +884,10 @@ int32 CFE_ES_LoadLibrary(CFE_ES_LibId_t *LibraryIdPtr, /* * Fill out the parameters in the AppStartParams sub-structure */ - strncpy(LibSlotPtr->BasicInfo.Name, LibName, - sizeof(LibSlotPtr->BasicInfo.Name)-1); - LibSlotPtr->BasicInfo.Name[sizeof(LibSlotPtr->BasicInfo.Name)-1] = '\0'; - strncpy(LibSlotPtr->BasicInfo.FileName, FileName, - sizeof(LibSlotPtr->BasicInfo.FileName)-1); - LibSlotPtr->BasicInfo.FileName[sizeof(LibSlotPtr->BasicInfo.FileName)-1] = '\0'; - if (EntryPointName != NULL && strcmp(EntryPointName, "NULL") != 0) - { - strncpy(LibSlotPtr->BasicInfo.EntryPoint, EntryPointName, - sizeof(LibSlotPtr->BasicInfo.EntryPoint)-1); - LibSlotPtr->BasicInfo.EntryPoint[sizeof(LibSlotPtr->BasicInfo.EntryPoint)-1] = '\0'; - } + strncpy(LibSlotPtr->LibName, LibName, + sizeof(LibSlotPtr->LibName)-1); + LibSlotPtr->LibName[sizeof(LibSlotPtr->LibName)-1] = '\0'; + LibSlotPtr->LoadParams = *Params; CFE_ES_LibRecordSetUsed(LibSlotPtr, CFE_RESOURCEID_RESERVED); CFE_ES_Global.LastLibId = PendingResourceId; @@ -923,10 +910,10 @@ int32 CFE_ES_LoadLibrary(CFE_ES_LibId_t *LibraryIdPtr, /* * Load the module based on StartParams configured above. */ - Status = CFE_ES_LoadModule(PendingResourceId, &LibSlotPtr->BasicInfo, &LibSlotPtr->ModuleInfo); + Status = CFE_ES_LoadModule(PendingResourceId, LibName, &LibSlotPtr->LoadParams, &LibSlotPtr->LoadStatus); if (Status == CFE_SUCCESS) { - FunctionPointer = (CFE_ES_LibraryEntryFuncPtr_t)LibSlotPtr->ModuleInfo.EntryAddress; + FunctionPointer = (CFE_ES_LibraryEntryFuncPtr_t)LibSlotPtr->LoadStatus.InitSymbolAddress; if (FunctionPointer != NULL) { Status = (*FunctionPointer)(CFE_ES_LIBID_C(PendingResourceId)); @@ -1112,7 +1099,8 @@ void CFE_ES_ProcessControlRequest(CFE_ES_AppId_t AppId) { CFE_ES_AppRecord_t *AppRecPtr; uint32 PendingControlReq; - CFE_ES_AppStartParams_t OrigStartParams; + CFE_ES_AppStartParams_t RestartParams; + char OrigAppName[OS_MAX_API_NAME]; CFE_Status_t CleanupStatus; CFE_Status_t StartupStatus; CFE_ES_AppId_t NewAppId; @@ -1129,8 +1117,11 @@ void CFE_ES_ProcessControlRequest(CFE_ES_AppId_t AppId) StartupStatus = CFE_SUCCESS; PendingControlReq = 0; NewAppId = CFE_ES_APPID_UNDEFINED; + OrigAppName[0] = 0; + memset(&RestartParams, 0, sizeof(RestartParams)); + AppRecPtr = CFE_ES_LocateAppRecordByID(AppId); - memset(&OrigStartParams, 0, sizeof(OrigStartParams)); + /* @@ -1144,7 +1135,15 @@ void CFE_ES_ProcessControlRequest(CFE_ES_AppId_t AppId) if (CFE_ES_AppRecordIsMatch(AppRecPtr, AppId)) { PendingControlReq = AppRecPtr->ControlReq.AppControlRequest; - OrigStartParams = AppRecPtr->StartParams; + strncpy(OrigAppName, AppRecPtr->AppName, sizeof(OrigAppName)-1); + OrigAppName[sizeof(OrigAppName)-1] = 0; + + /* If a restart was requested, copy the parameters to re-use in new app */ + if ( PendingControlReq == CFE_ES_RunStatus_SYS_RESTART || + PendingControlReq == CFE_ES_RunStatus_SYS_RELOAD ) + { + RestartParams = AppRecPtr->StartParams; + } } CFE_ES_UnlockSharedData(__func__,__LINE__); @@ -1174,13 +1173,7 @@ void CFE_ES_ProcessControlRequest(CFE_ES_AppId_t AppId) if ( PendingControlReq == CFE_ES_RunStatus_SYS_RESTART || PendingControlReq == CFE_ES_RunStatus_SYS_RELOAD ) { - StartupStatus = CFE_ES_AppCreate(&NewAppId, - OrigStartParams.BasicInfo.FileName, - OrigStartParams.BasicInfo.EntryPoint, - OrigStartParams.BasicInfo.Name, - OrigStartParams.Priority, - OrigStartParams.StackSize, - OrigStartParams.ExceptionAction); + StartupStatus = CFE_ES_AppCreate(&NewAppId, OrigAppName, &RestartParams); } /* @@ -1328,7 +1321,7 @@ void CFE_ES_ProcessControlRequest(CFE_ES_AppId_t AppId) } CFE_EVS_SendEvent(EventID, EventType, "%s Application %s %s", - ReqName, OrigStartParams.BasicInfo.Name, MessageDetail); + ReqName, OrigAppName, MessageDetail); } } /* End Function */ @@ -1379,7 +1372,7 @@ int32 CFE_ES_CleanUpApp(CFE_ES_AppId_t AppId) * * (this will be OS_OBJECT_ID_UNDEFINED if it was not loaded dynamically) */ - ModuleId = AppRecPtr->ModuleInfo.ModuleId; + ModuleId = AppRecPtr->LoadStatus.ModuleId; } /* @@ -1765,11 +1758,7 @@ int32 CFE_ES_CleanupTaskResources(CFE_ES_TaskId_t TaskId) */ void CFE_ES_CopyModuleBasicInfo(const CFE_ES_ModuleLoadParams_t *ParamsPtr, CFE_ES_AppInfo_t *AppInfoPtr) { - strncpy(AppInfoPtr->Name, ParamsPtr->Name, - sizeof(AppInfoPtr->Name)-1); - AppInfoPtr->Name[sizeof(AppInfoPtr->Name)-1] = '\0'; - - strncpy(AppInfoPtr->EntryPoint, ParamsPtr->EntryPoint, + strncpy(AppInfoPtr->EntryPoint, ParamsPtr->InitSymbolName, sizeof(AppInfoPtr->EntryPoint) - 1); AppInfoPtr->EntryPoint[sizeof(AppInfoPtr->EntryPoint) - 1] = '\0'; @@ -1790,7 +1779,7 @@ void CFE_ES_CopyModuleBasicInfo(const CFE_ES_ModuleLoadParams_t *ParamsPtr, CFE_ */ void CFE_ES_CopyModuleStatusInfo(const CFE_ES_ModuleLoadStatus_t *StatusPtr, CFE_ES_AppInfo_t *AppInfoPtr) { - AppInfoPtr->StartAddress = CFE_ES_MEMADDRESS_C(StatusPtr->EntryAddress); + AppInfoPtr->StartAddress = CFE_ES_MEMADDRESS_C(StatusPtr->InitSymbolAddress); } /* diff --git a/fsw/cfe-core/src/es/cfe_es_apps.h b/fsw/cfe-core/src/es/cfe_es_apps.h index abe038378..208a3b3d1 100644 --- a/fsw/cfe-core/src/es/cfe_es_apps.h +++ b/fsw/cfe-core/src/es/cfe_es_apps.h @@ -77,8 +77,7 @@ typedef struct */ typedef struct { - char Name[OS_MAX_API_NAME]; - char EntryPoint[OS_MAX_API_NAME]; + char InitSymbolName[OS_MAX_API_NAME]; char FileName[OS_MAX_PATH_LEN]; } CFE_ES_ModuleLoadParams_t; @@ -92,19 +91,31 @@ typedef struct */ typedef struct { - cpuaddr EntryAddress; osal_id_t ModuleId; + cpuaddr InitSymbolAddress; } CFE_ES_ModuleLoadStatus_t; +/* +** CFE_ES_TaskStartParams_t contains basic details about a CFE task +** +** This information needs to be specified when starting a task and is +** stored as part of the task record for future reference. +*/ +typedef struct +{ + size_t StackSize; + CFE_ES_TaskPriority_Atom_t Priority; + +} CFE_ES_TaskStartParams_t; + /* -** CFE_ES_AppStartParams_t is a structure of information used when an application is -** created in the system. +** CFE_ES_AppStartParams_t contains basic details about a CFE app. ** ** This is an extension of the CFE_ES_ModuleLoadParams_t which adds information -** about the task stack size and priority. It is only used for apps, as libraries +** about the main task and exception action. It is only used for apps, as libraries ** do not have a task associated. */ typedef struct @@ -112,30 +123,28 @@ typedef struct /* * Basic (static) information about the module */ - CFE_ES_ModuleLoadParams_t BasicInfo; + CFE_ES_ModuleLoadParams_t BasicInfo; - /* - * Extra information the pertains to applications only, not libraries. - */ - size_t StackSize; - CFE_ES_TaskPriority_Atom_t Priority; - CFE_ES_ExceptionAction_Enum_t ExceptionAction; + CFE_ES_TaskStartParams_t MainTaskInfo; + CFE_ES_ExceptionAction_Enum_t ExceptionAction; } CFE_ES_AppStartParams_t; + /* ** CFE_ES_AppRecord_t is an internal structure used to keep track of ** CFE Applications that are active in the system. */ typedef struct { - CFE_ES_AppId_t AppId; /* The actual AppID of this entry, or undefined */ - CFE_ES_AppState_Enum_t AppState; /* Is the app running, or stopped, or waiting? */ - CFE_ES_AppType_Enum_t Type; /* The type of App: CORE or EXTERNAL */ - CFE_ES_AppStartParams_t StartParams; /* The start parameters for an App */ - CFE_ES_ModuleLoadStatus_t ModuleInfo; /* Runtime module information */ - CFE_ES_ControlReq_t ControlReq; /* The Control Request Record for External cFE Apps */ - CFE_ES_TaskId_t MainTaskId; /* The Application's Main Task ID */ + CFE_ES_AppId_t AppId; /* The actual AppID of this entry, or undefined */ + char AppName[OS_MAX_API_NAME]; /* The name of the app */ + CFE_ES_AppState_Enum_t AppState; /* Is the app running, or stopped, or waiting? */ + CFE_ES_AppType_Enum_t Type; /* The type of App: CORE or EXTERNAL */ + CFE_ES_AppStartParams_t StartParams; /* The start parameters for an App */ + CFE_ES_ModuleLoadStatus_t LoadStatus; /* Runtime module information */ + CFE_ES_ControlReq_t ControlReq; /* The Control Request Record for External cFE Apps */ + CFE_ES_TaskId_t MainTaskId; /* The Application's Main Task ID */ } CFE_ES_AppRecord_t; @@ -146,11 +155,12 @@ typedef struct */ typedef struct { - CFE_ES_TaskId_t TaskId; /* The actual TaskID of this entry, or undefined */ - CFE_ES_AppId_t AppId; /* The parent Application's App ID */ - uint32 ExecutionCounter; /* The execution counter for the Child task */ - char TaskName[OS_MAX_API_NAME]; /* Task Name */ - + CFE_ES_TaskId_t TaskId; /* The actual TaskID of this entry, or undefined */ + char TaskName[OS_MAX_API_NAME]; /* Task Name */ + CFE_ES_AppId_t AppId; /* The parent Application's App ID */ + CFE_ES_TaskStartParams_t StartParams; /* The start parameters for the task */ + CFE_ES_TaskEntryFuncPtr_t EntryFunc; /* Task entry function */ + uint32 ExecutionCounter; /* The execution counter for the task */ } CFE_ES_TaskRecord_t; @@ -160,9 +170,11 @@ typedef struct */ typedef struct { - CFE_ES_LibId_t LibId; /* The actual LibID of this entry, or undefined */ - CFE_ES_ModuleLoadParams_t BasicInfo; /* Basic (static) information about the module */ - CFE_ES_ModuleLoadStatus_t ModuleInfo; /* Runtime information about the module */ + CFE_ES_LibId_t LibId; /* The actual LibID of this entry, or undefined */ + char LibName[OS_MAX_API_NAME]; /* Library Name */ + CFE_ES_ModuleLoadParams_t LoadParams; /* Basic (static) information about the module */ + CFE_ES_ModuleLoadStatus_t LoadStatus; /* Runtime information about the module */ + } CFE_ES_LibRecord_t; /* @@ -198,7 +210,7 @@ int32 CFE_ES_ParseFileEntry(const char **TokenList, uint32 NumTokens); ** This only loads the code and looks up relevent runtime information. ** It does not start any tasks. */ -int32 CFE_ES_LoadModule(CFE_ResourceId_t ResourceId, const CFE_ES_ModuleLoadParams_t* LoadParams, CFE_ES_ModuleLoadStatus_t *LoadStatus); +int32 CFE_ES_LoadModule(CFE_ResourceId_t ParentResourceId, const char *ModuleName, const CFE_ES_ModuleLoadParams_t* LoadParams, CFE_ES_ModuleLoadStatus_t *LoadStatus); /* ** Internal function to determine the entry point of an app. @@ -206,37 +218,29 @@ int32 CFE_ES_LoadModule(CFE_ResourceId_t ResourceId, const CFE_ES_ModuleLoadPara ** then this delays until the app is completely configured and the entry point is ** confirmed to be valid. */ -int32 CFE_ES_GetAppEntryPoint(osal_task_entry *FuncPtr); +int32 CFE_ES_GetTaskFunction(CFE_ES_TaskEntryFuncPtr_t *FuncPtr); /* -** Intermediate entry point of an app. Determines the actual +** Intermediate entry point of all tasks. Determines the actual ** entry point from the global data structures. */ -void CFE_ES_AppEntryPoint(void); +void CFE_ES_TaskEntryPoint(void); /* -** Internal function to start the main task of an app. +** Internal function to start a task associated with an app. */ -int32 CFE_ES_StartAppTask(const CFE_ES_AppStartParams_t* StartParams, CFE_ES_AppId_t RefAppId, CFE_ES_TaskId_t *TaskIdPtr); +int32 CFE_ES_StartAppTask(CFE_ES_TaskId_t *TaskIdPtr, const char *TaskName, CFE_ES_TaskEntryFuncPtr_t EntryFunc, const CFE_ES_TaskStartParams_t* Params, CFE_ES_AppId_t ParentAppId); /* ** Internal function to create/start a new cFE app ** based on the parameters passed in */ -int32 CFE_ES_AppCreate(CFE_ES_AppId_t *ApplicationIdPtr, - const char *FileName, - const char *EntryPointName, - const char *AppName, - CFE_ES_TaskPriority_Atom_t Priority, - size_t StackSize, - CFE_ES_ExceptionAction_Enum_t ExceptionAction); +int32 CFE_ES_AppCreate(CFE_ES_AppId_t *ApplicationIdPtr, const char *AppName, const CFE_ES_AppStartParams_t *Params); + /* ** Internal function to load a a new cFE shared Library */ -int32 CFE_ES_LoadLibrary(CFE_ES_LibId_t *LibraryIdPtr, - const char *FileName, - const char *EntryPointName, - const char *LibName); +int32 CFE_ES_LoadLibrary(CFE_ES_LibId_t *LibraryIdPtr, const char *LibName, const CFE_ES_ModuleLoadParams_t *Params); /* ** Scan the Application Table for actions to take diff --git a/fsw/cfe-core/src/es/cfe_es_objtab.c b/fsw/cfe-core/src/es/cfe_es_objtab.c index 88bca7540..18c4c3287 100644 --- a/fsw/cfe-core/src/es/cfe_es_objtab.c +++ b/fsw/cfe-core/src/es/cfe_es_objtab.c @@ -129,7 +129,7 @@ CFE_ES_ObjectTable_t CFE_ES_ObjectTable[CFE_PLATFORM_ES_OBJECT_TABLE_SIZE] = { .ObjectType = CFE_ES_CORE_TASK, .ObjectName = "CFE_EVS", - .FuncPtrUnion.MainAppPtr = CFE_EVS_TaskMain, + .FuncPtrUnion.MainTaskPtr = CFE_EVS_TaskMain, .ObjectPriority = CFE_PLATFORM_EVS_START_TASK_PRIORITY, .ObjectSize = CFE_PLATFORM_EVS_START_TASK_STACK_SIZE }, @@ -139,7 +139,7 @@ CFE_ES_ObjectTable_t CFE_ES_ObjectTable[CFE_PLATFORM_ES_OBJECT_TABLE_SIZE] = { .ObjectType = CFE_ES_CORE_TASK, .ObjectName = "CFE_SB", - .FuncPtrUnion.MainAppPtr = CFE_SB_TaskMain, + .FuncPtrUnion.MainTaskPtr = CFE_SB_TaskMain, .ObjectPriority = CFE_PLATFORM_SB_START_TASK_PRIORITY, .ObjectSize = CFE_PLATFORM_SB_START_TASK_STACK_SIZE }, @@ -149,7 +149,7 @@ CFE_ES_ObjectTable_t CFE_ES_ObjectTable[CFE_PLATFORM_ES_OBJECT_TABLE_SIZE] = { .ObjectType = CFE_ES_CORE_TASK, .ObjectName = "CFE_ES", - .FuncPtrUnion.MainAppPtr = CFE_ES_TaskMain, + .FuncPtrUnion.MainTaskPtr = CFE_ES_TaskMain, .ObjectPriority = CFE_PLATFORM_ES_START_TASK_PRIORITY, .ObjectSize = CFE_PLATFORM_ES_START_TASK_STACK_SIZE }, @@ -159,7 +159,7 @@ CFE_ES_ObjectTable_t CFE_ES_ObjectTable[CFE_PLATFORM_ES_OBJECT_TABLE_SIZE] = { .ObjectType = CFE_ES_CORE_TASK, .ObjectName = "CFE_TIME", - .FuncPtrUnion.MainAppPtr = CFE_TIME_TaskMain, + .FuncPtrUnion.MainTaskPtr = CFE_TIME_TaskMain, .ObjectPriority = CFE_PLATFORM_TIME_START_TASK_PRIORITY, .ObjectSize = CFE_PLATFORM_TIME_START_TASK_STACK_SIZE }, @@ -169,7 +169,7 @@ CFE_ES_ObjectTable_t CFE_ES_ObjectTable[CFE_PLATFORM_ES_OBJECT_TABLE_SIZE] = { .ObjectType = CFE_ES_CORE_TASK, .ObjectName = "CFE_TBL", - .FuncPtrUnion.MainAppPtr = CFE_TBL_TaskMain, + .FuncPtrUnion.MainTaskPtr = CFE_TBL_TaskMain, .ObjectPriority = CFE_PLATFORM_TBL_START_TASK_PRIORITY, .ObjectSize = CFE_PLATFORM_TBL_START_TASK_STACK_SIZE }, diff --git a/fsw/cfe-core/src/es/cfe_es_resource.h b/fsw/cfe-core/src/es/cfe_es_resource.h index 9cbaa840d..efdb8280a 100644 --- a/fsw/cfe-core/src/es/cfe_es_resource.h +++ b/fsw/cfe-core/src/es/cfe_es_resource.h @@ -173,7 +173,7 @@ static inline bool CFE_ES_AppRecordIsMatch(const CFE_ES_AppRecord_t *AppRecPtr, */ static inline const char* CFE_ES_AppRecordGetName(const CFE_ES_AppRecord_t *AppRecPtr) { - return AppRecPtr->StartParams.BasicInfo.Name; + return AppRecPtr->AppName; } @@ -266,7 +266,7 @@ static inline bool CFE_ES_LibRecordIsMatch(const CFE_ES_LibRecord_t *LibRecPtr, */ static inline const char* CFE_ES_LibRecordGetName(const CFE_ES_LibRecord_t *LibRecPtr) { - return LibRecPtr->BasicInfo.Name; + return LibRecPtr->LibName; } diff --git a/fsw/cfe-core/src/es/cfe_es_start.c b/fsw/cfe-core/src/es/cfe_es_start.c index 5fcf246e7..da0538c4c 100644 --- a/fsw/cfe-core/src/es/cfe_es_start.c +++ b/fsw/cfe-core/src/es/cfe_es_start.c @@ -743,7 +743,6 @@ void CFE_ES_CreateObjects(void) uint16 i; CFE_ES_AppRecord_t *AppRecPtr; CFE_ResourceId_t PendingAppId; - CFE_ES_TaskId_t PendingTaskId; CFE_ES_WriteToSysLog("ES Startup: Starting Object Creation calls.\n"); @@ -767,15 +766,15 @@ void CFE_ES_CreateObjects(void) ** Fill out the parameters in the AppStartParams sub-structure */ AppRecPtr->Type = CFE_ES_AppType_CORE; - strncpy(AppRecPtr->StartParams.BasicInfo.Name, CFE_ES_ObjectTable[i].ObjectName, - sizeof(AppRecPtr->StartParams.BasicInfo.Name)-1); - AppRecPtr->StartParams.BasicInfo.Name[sizeof(AppRecPtr->StartParams.BasicInfo.Name)-1] = '\0'; + + strncpy(AppRecPtr->AppName, CFE_ES_ObjectTable[i].ObjectName, + sizeof(AppRecPtr->AppName)-1); + AppRecPtr->AppName[sizeof(AppRecPtr->AppName)-1] = '\0'; /* FileName and EntryPoint is not valid for core apps */ - AppRecPtr->StartParams.StackSize = CFE_ES_ObjectTable[i].ObjectSize; + AppRecPtr->StartParams.MainTaskInfo.StackSize = CFE_ES_ObjectTable[i].ObjectSize; + AppRecPtr->StartParams.MainTaskInfo.Priority = CFE_ES_ObjectTable[i].ObjectPriority; AppRecPtr->StartParams.ExceptionAction = CFE_ES_ExceptionAction_PROC_RESTART; - AppRecPtr->StartParams.Priority = CFE_ES_ObjectTable[i].ObjectPriority; - AppRecPtr->ModuleInfo.EntryAddress = (cpuaddr)CFE_ES_ObjectTable[i].FuncPtrUnion.VoidPtr; /* ** Fill out the Task State info @@ -798,7 +797,11 @@ void CFE_ES_CreateObjects(void) ** Start the core app main task ** (core apps are already in memory - no loading needed) */ - ReturnCode = CFE_ES_StartAppTask(&AppRecPtr->StartParams, CFE_ES_APPID_C(PendingAppId), &PendingTaskId); + ReturnCode = CFE_ES_StartAppTask(&AppRecPtr->MainTaskId, + AppRecPtr->AppName, + CFE_ES_ObjectTable[i].FuncPtrUnion.MainTaskPtr, + &AppRecPtr->StartParams.MainTaskInfo, + CFE_ES_APPID_C(PendingAppId)); /* * Finalize data in the app table entry, which must be done under lock. @@ -809,7 +812,6 @@ void CFE_ES_CreateObjects(void) if ( ReturnCode == OS_SUCCESS ) { - AppRecPtr->MainTaskId = PendingTaskId; CFE_ES_AppRecordSetUsed(AppRecPtr, PendingAppId); /* diff --git a/fsw/cfe-core/src/es/cfe_es_start.h b/fsw/cfe-core/src/es/cfe_es_start.h index e98990cc8..119df0a5a 100644 --- a/fsw/cfe-core/src/es/cfe_es_start.h +++ b/fsw/cfe-core/src/es/cfe_es_start.h @@ -62,12 +62,11 @@ */ typedef int32 (*CFE_ES_EarlyInitFuncPtr_t)(void); /**< \brief Req'd prototype of Early Init Functions */ -typedef void (*CFE_ES_MainAppFuncPtr_t)(void); /**< \brief Req'd prototype of Application Main Functions */ typedef union { CFE_ES_EarlyInitFuncPtr_t FunctionPtr; - CFE_ES_MainAppFuncPtr_t MainAppPtr; + CFE_ES_TaskEntryFuncPtr_t MainTaskPtr; void *VoidPtr; } CFE_ES_FuncPtrUnion_t; diff --git a/fsw/cfe-core/src/es/cfe_es_task.c b/fsw/cfe-core/src/es/cfe_es_task.c index 3f7696876..54de717ab 100644 --- a/fsw/cfe-core/src/es/cfe_es_task.c +++ b/fsw/cfe-core/src/es/cfe_es_task.c @@ -849,19 +849,18 @@ int32 CFE_ES_StartAppCmd(const CFE_ES_StartAppCmd_t *data) int32 FilenameLen; int32 AppEntryLen; int32 AppNameLen; - size_t AppStackSize; - char LocalFile[OS_MAX_PATH_LEN]; - char LocalEntryPt[OS_MAX_API_NAME]; char LocalAppName[OS_MAX_API_NAME]; + CFE_ES_AppStartParams_t StartParams; + /* Create local copies of all input strings and ensure null termination */ - FilenameLen = CFE_SB_MessageStringGet(LocalFile, (char *)cmd->AppFileName, NULL, - sizeof(LocalFile), sizeof(cmd->AppFileName)); + FilenameLen = CFE_SB_MessageStringGet(StartParams.BasicInfo.FileName, cmd->AppFileName, NULL, + sizeof(StartParams.BasicInfo.FileName), sizeof(cmd->AppFileName)); - AppEntryLen = CFE_SB_MessageStringGet(LocalEntryPt, (char *)cmd->AppEntryPoint, NULL, - sizeof(LocalEntryPt), sizeof(cmd->AppEntryPoint)); + AppEntryLen = CFE_SB_MessageStringGet(StartParams.BasicInfo.InitSymbolName, cmd->AppEntryPoint, NULL, + sizeof(StartParams.BasicInfo.InitSymbolName), sizeof(cmd->AppEntryPoint)); - AppNameLen = CFE_SB_MessageStringGet(LocalAppName, (char *)cmd->Application, NULL, + AppNameLen = CFE_SB_MessageStringGet(LocalAppName, cmd->Application, NULL, sizeof(LocalAppName), sizeof(cmd->Application)); /* @@ -872,19 +871,19 @@ int32 CFE_ES_StartAppCmd(const CFE_ES_StartAppCmd_t *data) CFE_ES_TaskData.CommandErrorCounter++; CFE_EVS_SendEvent(CFE_ES_START_INVALID_FILENAME_ERR_EID, CFE_EVS_EventType_ERROR, "CFE_ES_StartAppCmd: invalid filename: %s", - LocalFile); + StartParams.BasicInfo.FileName); } else if (AppEntryLen <= 0) { CFE_ES_TaskData.CommandErrorCounter++; CFE_EVS_SendEvent(CFE_ES_START_INVALID_ENTRY_POINT_ERR_EID, CFE_EVS_EventType_ERROR, - "CFE_ES_StartAppCmd: App Entry Point is NULL."); + "CFE_ES_StartAppCmd: App Entry Point is empty."); } else if (AppNameLen <= 0) { CFE_ES_TaskData.CommandErrorCounter++; CFE_EVS_SendEvent(CFE_ES_START_NULL_APP_NAME_ERR_EID, CFE_EVS_EventType_ERROR, - "CFE_ES_StartAppCmd: App Name is NULL."); + "CFE_ES_StartAppCmd: App Name is empty."); } else if (cmd->Priority > OS_MAX_PRIORITY) { @@ -906,22 +905,20 @@ int32 CFE_ES_StartAppCmd(const CFE_ES_StartAppCmd_t *data) /* If stack size was provided, use it, otherwise use default. */ if (cmd->StackSize == 0) { - AppStackSize = CFE_PLATFORM_ES_DEFAULT_STACK_SIZE; + StartParams.MainTaskInfo.StackSize = CFE_PLATFORM_ES_DEFAULT_STACK_SIZE; } else { - AppStackSize = cmd->StackSize; + StartParams.MainTaskInfo.StackSize = cmd->StackSize; } + StartParams.MainTaskInfo.Priority = cmd->Priority; + StartParams.ExceptionAction = cmd->ExceptionAction; + /* ** Invoke application loader/startup function. */ - Result = CFE_ES_AppCreate(&AppID, LocalFile, - LocalEntryPt, - LocalAppName, - cmd->Priority, - AppStackSize, - cmd->ExceptionAction); + Result = CFE_ES_AppCreate(&AppID, LocalAppName, &StartParams); /* ** Send appropriate event message @@ -931,14 +928,14 @@ int32 CFE_ES_StartAppCmd(const CFE_ES_StartAppCmd_t *data) CFE_ES_TaskData.CommandCounter++; CFE_EVS_SendEvent(CFE_ES_START_INF_EID, CFE_EVS_EventType_INFORMATION, "Started %s from %s, AppID = %lu", - LocalAppName, LocalFile, CFE_RESOURCEID_TO_ULONG(AppID)); + LocalAppName, StartParams.BasicInfo.FileName, CFE_RESOURCEID_TO_ULONG(AppID)); } else { CFE_ES_TaskData.CommandErrorCounter++; CFE_EVS_SendEvent(CFE_ES_START_ERR_EID, CFE_EVS_EventType_ERROR, "Failed to start %s from %s, RC = 0x%08X", - LocalAppName, LocalFile, (unsigned int)Result); + LocalAppName, StartParams.BasicInfo.FileName, (unsigned int)Result); } } /* End if -- command parameter validation */ diff --git a/fsw/cfe-core/src/inc/cfe_es.h b/fsw/cfe-core/src/inc/cfe_es.h index 499fe397f..23eaa9649 100644 --- a/fsw/cfe-core/src/inc/cfe_es.h +++ b/fsw/cfe-core/src/inc/cfe_es.h @@ -140,11 +140,18 @@ */ /* -** Child Task Main Function Prototype +** Entry Function Prototypes */ -typedef void (*CFE_ES_ChildTaskMainFuncPtr_t)(void); /**< \brief Required Prototype of Child Task Main Functions */ +typedef void (*CFE_ES_TaskEntryFuncPtr_t)(void); /**< \brief Required Prototype of Task Main Functions */ typedef int32 (*CFE_ES_LibraryEntryFuncPtr_t)(CFE_ES_LibId_t LibId); /**< \brief Required Prototype of Library Initialization Functions */ +/** + * \brief Compatible typedef for ES child task entry point. + * + * All ES task functions (main + child) use the same entry point type. + */ +typedef CFE_ES_TaskEntryFuncPtr_t CFE_ES_ChildTaskMainFuncPtr_t; + /** * @brief Type for the stack pointer of tasks. * diff --git a/fsw/cfe-core/unit-test/es_UT.c b/fsw/cfe-core/unit-test/es_UT.c index 629abd399..800429ec8 100644 --- a/fsw/cfe-core/unit-test/es_UT.c +++ b/fsw/cfe-core/unit-test/es_UT.c @@ -275,6 +275,51 @@ CFE_ResourceId_t ES_UT_MakeCDSIdForIndex(uint32 ArrayIdx) return CFE_ResourceId_FromInteger(ArrayIdx + CFE_ES_CDSBLOCKID_BASE); } +/* + * A local stub that can serve as the user function for testing ES tasks + */ +void ES_UT_TaskFunction(void) +{ + UT_DEFAULT_IMPL(ES_UT_TaskFunction); +} + +/* + * Helper function to assemble basic bits of info into the "CFE_ES_ModuleLoadParams_t" struct + */ +void ES_UT_SetupModuleLoadParams(CFE_ES_ModuleLoadParams_t *Params, const char *FileName, const char *EntryName) +{ + char Empty = 0; + + if (FileName == NULL) + { + FileName = &Empty; + } + + if (EntryName == NULL) + { + EntryName = &Empty; + } + + strncpy(Params->FileName, FileName, sizeof(Params->FileName)); + strncpy(Params->InitSymbolName, EntryName, sizeof(Params->InitSymbolName)); +} + +/* + * Helper function to assemble basic bits of info into the "CFE_ES_AppStartParams_t" struct + */ +void ES_UT_SetupAppStartParams(CFE_ES_AppStartParams_t *Params, const char *FileName, const char *EntryName, + size_t StackSize, CFE_ES_TaskPriority_Atom_t Priority, + CFE_ES_ExceptionAction_Enum_t ExceptionAction) +{ + ES_UT_SetupModuleLoadParams(&Params->BasicInfo, FileName, EntryName); + Params->MainTaskInfo.StackSize = StackSize; + Params->MainTaskInfo.Priority = Priority; + Params->ExceptionAction = ExceptionAction; +} + + + + /* * Helper function to setup a single app ID in the given state, along with * a main task ID. A pointer to the App and Task record is output so the @@ -306,11 +351,9 @@ void ES_UT_SetupSingleAppId(CFE_ES_AppType_Enum_t AppType, CFE_ES_AppState_Enum_ if (AppName) { - strncpy(LocalAppPtr->StartParams.BasicInfo.Name, AppName, - sizeof(LocalAppPtr->StartParams.BasicInfo.Name)-1); - LocalAppPtr->StartParams.BasicInfo.Name[sizeof(LocalAppPtr->StartParams.BasicInfo.Name)-1] = 0; - strncpy(LocalTaskPtr->TaskName, AppName, - sizeof(LocalTaskPtr->TaskName)-1); + strncpy(LocalAppPtr->AppName, AppName, sizeof(LocalAppPtr->AppName)-1); + LocalAppPtr->AppName[sizeof(LocalAppPtr->AppName)-1] = 0; + strncpy(LocalTaskPtr->TaskName, AppName, sizeof(LocalTaskPtr->TaskName)-1); LocalTaskPtr->TaskName[sizeof(LocalTaskPtr->TaskName)-1] = 0; } @@ -332,7 +375,7 @@ void ES_UT_SetupSingleAppId(CFE_ES_AppType_Enum_t AppType, CFE_ES_AppState_Enum_ ++CFE_ES_Global.RegisteredExternalApps; OS_ModuleLoad(&UtOsalId, NULL, NULL, 0); - LocalAppPtr->ModuleInfo.ModuleId = UtOsalId; + LocalAppPtr->LoadStatus.ModuleId = UtOsalId; } ++CFE_ES_Global.RegisteredTasks; } @@ -391,9 +434,9 @@ void ES_UT_SetupSingleLibId(const char *LibName, CFE_ES_LibRecord_t **OutLibRec) if (LibName) { - strncpy(LocalLibPtr->BasicInfo.Name, LibName, - sizeof(LocalLibPtr->BasicInfo.Name)-1); - LocalLibPtr->BasicInfo.Name[sizeof(LocalLibPtr->BasicInfo.Name)-1] = 0; + strncpy(LocalLibPtr->LibName, LibName, + sizeof(LocalLibPtr->LibName)-1); + LocalLibPtr->LibName[sizeof(LocalLibPtr->LibName)-1] = 0; } if (OutLibRec) @@ -1168,6 +1211,7 @@ void TestApps(void) CFE_ES_AppRecord_t *UtAppRecPtr; CFE_ES_MemPoolRecord_t *UtPoolRecPtr; char NameBuffer[OS_MAX_API_NAME+5]; + CFE_ES_AppStartParams_t StartParams; UtPrintf("Begin Test Apps"); @@ -1271,25 +1315,23 @@ void TestApps(void) /* Test application loading and creation with a task creation failure */ ES_ResetUnitTest(); UT_SetDefaultReturnValue(UT_KEY(OS_TaskCreate), OS_ERROR); - Return = CFE_ES_AppCreate(&AppId, + ES_UT_SetupAppStartParams(&StartParams, "ut/filename", "EntryPoint", - "AppName", 170, 4096, 1); + Return = CFE_ES_AppCreate(&AppId, + "AppName", + &StartParams); UtAssert_INT32_EQ(Return, CFE_STATUS_EXTERNAL_RESOURCE_FAIL); UtAssert_NONZERO(UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_APP_CREATE])); - /* Test application creation with NULL file name */ + /* Test application creation with NULL parameters */ ES_ResetUnitTest(); Return = CFE_ES_AppCreate(&AppId, - NULL, - "EntryPoint", "AppName", - 170, - 4096, - 1); + NULL); UT_Report(__FILE__, __LINE__, Return == CFE_ES_BAD_ARGUMENT, "CFE_ES_AppCreate", @@ -1298,13 +1340,15 @@ void TestApps(void) /* Test application creation with name too long */ memset(NameBuffer, 'x', sizeof(NameBuffer)-1); NameBuffer[sizeof(NameBuffer)-1] = 0; - Return = CFE_ES_AppCreate(&AppId, + ES_UT_SetupAppStartParams(&StartParams, "ut/filename.x", "EntryPoint", - NameBuffer, 170, 4096, 1); + Return = CFE_ES_AppCreate(&AppId, + NameBuffer, + &StartParams); UT_Report(__FILE__, __LINE__, Return == CFE_ES_BAD_ARGUMENT, "CFE_ES_AppCreate", @@ -1313,26 +1357,30 @@ void TestApps(void) /* Test successful application loading and creation */ ES_ResetUnitTest(); - Return = CFE_ES_AppCreate(&AppId, + ES_UT_SetupAppStartParams(&StartParams, "ut/filename.x", "EntryPoint", - "AppName", 170, 8192, 1); + Return = CFE_ES_AppCreate(&AppId, + "AppName", + &StartParams); UT_Report(__FILE__, __LINE__, Return == CFE_SUCCESS, "CFE_ES_AppCreate", "Application load/create; successful"); /* Test application loading of the same name again */ - Return = CFE_ES_AppCreate(&AppId, + ES_UT_SetupAppStartParams(&StartParams, "ut/filename.x", "EntryPoint", - "AppName", 170, 8192, 1); + Return = CFE_ES_AppCreate(&AppId, + "AppName", + &StartParams); UT_Report(__FILE__, __LINE__, Return == CFE_ES_ERR_DUPLICATE_NAME, "CFE_ES_AppCreate", @@ -1341,26 +1389,30 @@ void TestApps(void) /* Test application loading and creation where the file cannot be loaded */ UT_InitData(); UT_SetDeferredRetcode(UT_KEY(OS_ModuleLoad), 1, -1); - Return = CFE_ES_AppCreate(&AppId, + ES_UT_SetupAppStartParams(&StartParams, "ut/filename.x", "EntryPoint", - "AppName2", 170, 8192, 1); + Return = CFE_ES_AppCreate(&AppId, + "AppName2", + &StartParams); UtAssert_INT32_EQ(Return, CFE_STATUS_EXTERNAL_RESOURCE_FAIL); UtAssert_NONZERO(UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_EXTRACT_FILENAME_UT55])); /* Test application loading and creation where all app slots are taken */ ES_ResetUnitTest(); UT_SetDefaultReturnValue(UT_KEY(CFE_ResourceId_FindNext), OS_ERROR); - Return = CFE_ES_AppCreate(&AppId, + ES_UT_SetupAppStartParams(&StartParams, "ut/filename.x", "EntryPoint", - "AppName", 170, 8192, 1); + Return = CFE_ES_AppCreate(&AppId, + "AppName", + &StartParams); UT_Report(__FILE__, __LINE__, Return == CFE_ES_NO_RESOURCE_IDS_AVAILABLE && UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_NO_FREE_APP_SLOTS]), @@ -1378,13 +1430,15 @@ void TestApps(void) */ ES_ResetUnitTest(); UT_SetDeferredRetcode(UT_KEY(OS_ModuleSymbolLookup), 1, -1); - Return = CFE_ES_AppCreate(&AppId, + ES_UT_SetupAppStartParams(&StartParams, "ut/filename.x", "EntryPoint", - "AppName", 170, 8192, 1); + Return = CFE_ES_AppCreate(&AppId, + "AppName", + &StartParams); UtAssert_INT32_EQ(Return, CFE_STATUS_EXTERNAL_RESOURCE_FAIL); UtAssert_NONZERO(UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_CANNOT_FIND_SYMBOL])); @@ -1395,13 +1449,15 @@ void TestApps(void) ES_ResetUnitTest(); UT_SetDeferredRetcode(UT_KEY(OS_ModuleSymbolLookup), 1, -1); UT_SetDeferredRetcode(UT_KEY(OS_ModuleUnload), 1, -1); - Return = CFE_ES_AppCreate(&AppId, + ES_UT_SetupAppStartParams(&StartParams, "ut/filename.x", "EntryPoint", - "AppName", 170, 8192, 1); + Return = CFE_ES_AppCreate(&AppId, + "AppName", + &StartParams); UtAssert_INT32_EQ(Return, CFE_STATUS_EXTERNAL_RESOURCE_FAIL); UtAssert_NONZERO(UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_CANNOT_FIND_SYMBOL])); UtAssert_NONZERO(UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_MODULE_UNLOAD_FAILED])); @@ -1487,15 +1543,12 @@ void TestApps(void) /* Test a successful control action request to exit an application */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); - strncpy(UtAppRecPtr->StartParams.BasicInfo.FileName, - "/ram/Filename", sizeof(UtAppRecPtr->StartParams.BasicInfo.FileName) - 1); - UtAppRecPtr->StartParams.BasicInfo.FileName[sizeof(UtAppRecPtr->StartParams.BasicInfo.FileName) - 1] = '\0'; - strncpy(UtAppRecPtr->StartParams.BasicInfo.EntryPoint, - "NotNULL", sizeof(UtAppRecPtr->StartParams.BasicInfo.EntryPoint) - 1); - UtAppRecPtr->StartParams.BasicInfo.EntryPoint[sizeof(UtAppRecPtr->StartParams.BasicInfo.EntryPoint) - 1] = '\0'; - UtAppRecPtr->StartParams.Priority = 255; - UtAppRecPtr->StartParams.StackSize = 8192; - UtAppRecPtr->StartParams.ExceptionAction = 0; + ES_UT_SetupAppStartParams(&UtAppRecPtr->StartParams, + "/ram/Filename", + "NotNULL", + 8192, + 255, + 0); UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_EXIT; AppId = CFE_ES_AppRecordGetID(UtAppRecPtr); @@ -1556,7 +1609,7 @@ void TestApps(void) ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_RESTART; - OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL, 0); + OS_ModuleLoad(&UtAppRecPtr->LoadStatus.ModuleId, NULL, NULL, 0); UT_SetDefaultReturnValue(UT_KEY(OS_TaskCreate), OS_ERROR); AppId = CFE_ES_AppRecordGetID(UtAppRecPtr); CFE_ES_ProcessControlRequest(AppId); @@ -1587,7 +1640,7 @@ void TestApps(void) ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_RELOAD; - OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL, 0); + OS_ModuleLoad(&UtAppRecPtr->LoadStatus.ModuleId, NULL, NULL, 0); UT_SetDefaultReturnValue(UT_KEY(OS_TaskCreate), OS_ERROR); AppId = CFE_ES_AppRecordGetID(UtAppRecPtr); CFE_ES_ProcessControlRequest(AppId); @@ -1601,15 +1654,13 @@ void TestApps(void) */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); - strncpy(UtAppRecPtr->StartParams.BasicInfo.FileName, - "/ram/FileName", sizeof(UtAppRecPtr->StartParams.BasicInfo.FileName) - 1); - UtAppRecPtr->StartParams.BasicInfo.FileName[sizeof(UtAppRecPtr->StartParams.BasicInfo.FileName) - 1] = '\0'; - strncpy(UtAppRecPtr->StartParams.BasicInfo.EntryPoint, "NULL", - sizeof(UtAppRecPtr->StartParams.BasicInfo.EntryPoint) - 1); - UtAppRecPtr->StartParams.BasicInfo.EntryPoint[sizeof(UtAppRecPtr->StartParams.BasicInfo.EntryPoint) - 1] = '\0'; - UtAppRecPtr->StartParams.Priority = 255; - UtAppRecPtr->StartParams.StackSize = 8192; - UtAppRecPtr->StartParams.ExceptionAction = 0; + ES_UT_SetupAppStartParams(&UtAppRecPtr->StartParams, + "/ram/FileName", + "NULL", + 8192, + 255, + 0); + UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_ERROR; AppId = CFE_ES_AppRecordGetID(UtAppRecPtr); @@ -1637,15 +1688,12 @@ void TestApps(void) /* Test a successful control action request to stop an application */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); - strncpy(UtAppRecPtr->StartParams.BasicInfo.FileName, - "/ram/FileName", sizeof(UtAppRecPtr->StartParams.BasicInfo.FileName) - 1); - UtAppRecPtr->StartParams.BasicInfo.FileName[sizeof(UtAppRecPtr->StartParams.BasicInfo.FileName) - 1] = '\0'; - strncpy(UtAppRecPtr->StartParams.BasicInfo.EntryPoint, "NULL", - sizeof(UtAppRecPtr->StartParams.BasicInfo.EntryPoint) - 1); - UtAppRecPtr->StartParams.BasicInfo.EntryPoint[sizeof(UtAppRecPtr->StartParams.BasicInfo.EntryPoint) - 1] = '\0'; - UtAppRecPtr->StartParams.Priority = 255; - UtAppRecPtr->StartParams.StackSize = 8192; - UtAppRecPtr->StartParams.ExceptionAction = 0; + ES_UT_SetupAppStartParams(&UtAppRecPtr->StartParams, + "/ram/FileName", + "NULL", + 8192, + 255, + 0); UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_DELETE; AppId = CFE_ES_AppRecordGetID(UtAppRecPtr); @@ -1658,15 +1706,12 @@ void TestApps(void) /* Test a successful control action request to restart an application */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); - strncpy(UtAppRecPtr->StartParams.BasicInfo.FileName, - "/ram/FileName", sizeof(UtAppRecPtr->StartParams.BasicInfo.FileName) - 1); - UtAppRecPtr->StartParams.BasicInfo.FileName[sizeof(UtAppRecPtr->StartParams.BasicInfo.FileName) - 1] = '\0'; - strncpy(UtAppRecPtr->StartParams.BasicInfo.EntryPoint, "NULL", - sizeof(UtAppRecPtr->StartParams.BasicInfo.EntryPoint) - 1); - UtAppRecPtr->StartParams.BasicInfo.EntryPoint[sizeof(UtAppRecPtr->StartParams.BasicInfo.EntryPoint) - 1] = '\0'; - UtAppRecPtr->StartParams.Priority = 255; - UtAppRecPtr->StartParams.StackSize = 8192; - UtAppRecPtr->StartParams.ExceptionAction = 0; + ES_UT_SetupAppStartParams(&UtAppRecPtr->StartParams, + "/ram/FileName", + "NULL", + 8192, + 255, + 0); UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_RESTART; AppId = CFE_ES_AppRecordGetID(UtAppRecPtr); @@ -1679,15 +1724,12 @@ void TestApps(void) /* Test a successful control action request to reload an application */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); - strncpy(UtAppRecPtr->StartParams.BasicInfo.FileName, - "/ram/FileName", sizeof(UtAppRecPtr->StartParams.BasicInfo.FileName) -1); - UtAppRecPtr->StartParams.BasicInfo.FileName[sizeof(UtAppRecPtr->StartParams.BasicInfo.FileName) -1] = '\0'; - strncpy(UtAppRecPtr->StartParams.BasicInfo.EntryPoint, "NULL", - sizeof(UtAppRecPtr->StartParams.BasicInfo.EntryPoint) - 1); - UtAppRecPtr->StartParams.BasicInfo.EntryPoint[sizeof(UtAppRecPtr->StartParams.BasicInfo.EntryPoint) - 1] = '\0'; - UtAppRecPtr->StartParams.Priority = 255; - UtAppRecPtr->StartParams.StackSize = 8192; - UtAppRecPtr->StartParams.ExceptionAction = 0; + ES_UT_SetupAppStartParams(&UtAppRecPtr->StartParams, + "/ram/FileName", + "NULL", + 8192, + 255, + 0); UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_RELOAD; AppId = CFE_ES_AppRecordGetID(UtAppRecPtr); @@ -1702,15 +1744,12 @@ void TestApps(void) */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); - strncpy(UtAppRecPtr->StartParams.BasicInfo.FileName, - "/ram/FileName", sizeof(UtAppRecPtr->StartParams.BasicInfo.FileName) - 1); - UtAppRecPtr->StartParams.BasicInfo.FileName[sizeof(UtAppRecPtr->StartParams.BasicInfo.FileName) - 1] = '\0'; - strncpy(UtAppRecPtr->StartParams.BasicInfo.EntryPoint, "NULL", - sizeof(UtAppRecPtr->StartParams.BasicInfo.EntryPoint) - 1); - UtAppRecPtr->StartParams.BasicInfo.EntryPoint[sizeof(UtAppRecPtr->StartParams.BasicInfo.EntryPoint) - 1] = '\0'; - UtAppRecPtr->StartParams.Priority = 255; - UtAppRecPtr->StartParams.StackSize = 8192; - UtAppRecPtr->StartParams.ExceptionAction = 0; + ES_UT_SetupAppStartParams(&UtAppRecPtr->StartParams, + "/ram/FileName", + "NULL", + 8192, + 255, + 0); UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_EXCEPTION; AppId = CFE_ES_AppRecordGetID(UtAppRecPtr); @@ -1781,7 +1820,7 @@ void TestApps(void) ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); ES_UT_SetupForOSCleanup(); - OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL, 0); + OS_ModuleLoad(&UtAppRecPtr->LoadStatus.ModuleId, NULL, NULL, 0); UT_SetDefaultReturnValue(UT_KEY(OS_TaskDelete), OS_ERROR); UT_SetDefaultReturnValue(UT_KEY(OS_close), OS_ERROR); AppId = CFE_ES_AppRecordGetID(UtAppRecPtr); @@ -2156,36 +2195,29 @@ void TestResourceID(void) void TestLibs(void) { CFE_ES_LibRecord_t *UtLibRecPtr; - char LongLibraryName[sizeof(UtLibRecPtr->BasicInfo.Name)+1]; + char LongLibraryName[sizeof(UtLibRecPtr->LibName)+1]; CFE_ES_LibId_t Id; int32 Return; + CFE_ES_ModuleLoadParams_t LoadParams; /* Test shared library loading and initialization where the initialization * routine returns an error */ ES_ResetUnitTest(); UT_SetDummyFuncRtn(-444); - Return = CFE_ES_LoadLibrary(&Id, - "filename", - "EntryPoint", - "LibName"); + ES_UT_SetupModuleLoadParams(&LoadParams, "filename", "entrypt"); + Return = CFE_ES_LoadLibrary(&Id, "LibName", &LoadParams); UtAssert_INT32_EQ(Return, -444); UtAssert_NONZERO(UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_SHARED_LIBRARY_INIT])); /* Test Load library returning an error on a null pointer argument */ - Return = CFE_ES_LoadLibrary(&Id, - NULL, - "EntryPoint", - "LibName"); + Return = CFE_ES_LoadLibrary(&Id, "LibName", NULL); UT_Report(__FILE__, __LINE__, Return == CFE_ES_BAD_ARGUMENT, "CFE_ES_LoadLibrary", "Load shared library bad argument (NULL filename)"); - Return = CFE_ES_LoadLibrary(&Id, - "filename", - "EntryPoint", - NULL); + Return = CFE_ES_LoadLibrary(&Id, NULL, &LoadParams); UT_Report(__FILE__, __LINE__, Return == CFE_ES_BAD_ARGUMENT, "CFE_ES_LoadLibrary", @@ -2194,10 +2226,7 @@ void TestLibs(void) /* Test Load library returning an error on a too long library name */ memset(LongLibraryName, 'a', sizeof(LongLibraryName)-1); LongLibraryName[sizeof(LongLibraryName)-1] = '\0'; - Return = CFE_ES_LoadLibrary(&Id, - "filename", - "EntryPoint", - &LongLibraryName[0]); + Return = CFE_ES_LoadLibrary(&Id, LongLibraryName, &LoadParams); UT_Report(__FILE__, __LINE__, Return == CFE_ES_BAD_ARGUMENT, "CFE_ES_LoadLibrary", @@ -2206,10 +2235,7 @@ void TestLibs(void) /* Test successful shared library loading and initialization */ UT_InitData(); UT_SetDummyFuncRtn(OS_SUCCESS); - Return = CFE_ES_LoadLibrary(&Id, - "/cf/apps/tst_lib.bundle", - "TST_LIB_Init", - "TST_LIB"); + Return = CFE_ES_LoadLibrary(&Id, "TST_LIB", &LoadParams); UT_Report(__FILE__, __LINE__, Return == CFE_SUCCESS, "CFE_ES_LoadLibrary", @@ -2220,10 +2246,7 @@ void TestLibs(void) UtAssert_True(CFE_ES_LibRecordIsUsed(UtLibRecPtr), "CFE_ES_LoadLibrary() record used"); /* Try loading same library again, should return the DUPLICATE code */ - Return = CFE_ES_LoadLibrary(&Id, - "/cf/apps/tst_lib.bundle", - "TST_LIB_Init", - "TST_LIB"); + Return = CFE_ES_LoadLibrary(&Id, "TST_LIB", &LoadParams); UT_Report(__FILE__, __LINE__, Return == CFE_ES_ERR_DUPLICATE_NAME, "CFE_ES_LoadLibrary", @@ -2236,10 +2259,7 @@ void TestLibs(void) */ ES_ResetUnitTest(); UT_SetDeferredRetcode(UT_KEY(OS_ModuleLoad), 1, -1); - Return = CFE_ES_LoadLibrary(&Id, - "/cf/apps/tst_lib.bundle", - "TST_LIB_Init", - "TST_LIB"); + Return = CFE_ES_LoadLibrary(&Id, "TST_LIB", &LoadParams); UtAssert_INT32_EQ(Return, CFE_STATUS_EXTERNAL_RESOURCE_FAIL); /* Test shared library loading and initialization where the library @@ -2247,10 +2267,7 @@ void TestLibs(void) */ ES_ResetUnitTest(); UT_SetDeferredRetcode(UT_KEY(OS_ModuleSymbolLookup), 1, -1); - Return = CFE_ES_LoadLibrary(&Id, - "/cf/apps/tst_lib.bundle", - "TST_LIB_Init", - "TST_LIB"); + Return = CFE_ES_LoadLibrary(&Id, "TST_LIB", &LoadParams); UtAssert_INT32_EQ(Return, CFE_STATUS_EXTERNAL_RESOURCE_FAIL); /* Test shared library loading and initialization where the library @@ -2259,10 +2276,8 @@ void TestLibs(void) ES_ResetUnitTest(); UT_SetDefaultReturnValue(UT_KEY(OS_remove), OS_ERROR); /* for coverage of error path */ UT_SetDefaultReturnValue(UT_KEY(dummy_function), -555); - Return = CFE_ES_LoadLibrary(&Id, - "/cf/apps/tst_lib.bundle", - "dummy_function", - "TST_LIB"); + ES_UT_SetupModuleLoadParams(&LoadParams, "filename", "dummy_function"); + Return = CFE_ES_LoadLibrary(&Id, "TST_LIB", &LoadParams); UT_Report(__FILE__, __LINE__, Return == -555, "CFE_ES_LoadLibrary", @@ -2273,10 +2288,7 @@ void TestLibs(void) */ ES_ResetUnitTest(); UT_SetDefaultReturnValue(UT_KEY(CFE_ResourceId_FindNext), OS_ERROR); - Return = CFE_ES_LoadLibrary(&Id, - "filename", - "EntryPoint", - "LibName"); + Return = CFE_ES_LoadLibrary(&Id, "LibName", &LoadParams); UT_Report(__FILE__, __LINE__, Return == CFE_ES_NO_RESOURCE_IDS_AVAILABLE && UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_LIBRARY_SLOTS]), @@ -4870,7 +4882,7 @@ void TestAPI(void) 400, 0); UT_Report(__FILE__, __LINE__, - Return == CFE_ES_ERR_CHILD_TASK_CREATE, + Return == CFE_STATUS_EXTERNAL_RESOURCE_FAIL, "CFE_ES_ChildTaskCreate", "OS task create failed"); @@ -4962,6 +4974,26 @@ void TestAPI(void) Return == CFE_SUCCESS, "CFE_ES_CreateChildTask", "Create child task successful"); + /* Test common entry point */ + ES_ResetUnitTest(); + + /* + * Without no app/task set up the entry point will not be found. + * There is no return value to check here, it just will not do anything. + */ + CFE_ES_TaskEntryPoint(); + + /* Now set up an app+task */ + ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, &UtTaskRecPtr); + + /* Test with app/task set up but no entry point defined */ + CFE_ES_TaskEntryPoint(); + + /* Finally set entry point, nominal mode */ + UtTaskRecPtr->EntryFunc = ES_UT_TaskFunction; + CFE_ES_TaskEntryPoint(); + UtAssert_STUB_COUNT(ES_UT_TaskFunction, 1); + /* Test deleting a child task using a main task's ID */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, "UT", NULL, &UtTaskRecPtr); From 81e907f210041c792ded8e91bf14236decd5d2f4 Mon Sep 17 00:00:00 2001 From: Alex Campbell Date: Wed, 17 Feb 2021 12:03:53 -0500 Subject: [PATCH 4/7] Fix #735, comment if null terminated or not. --- cmake/sample_defs/sample_mission_cfg.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/cmake/sample_defs/sample_mission_cfg.h b/cmake/sample_defs/sample_mission_cfg.h index 09a12ea17..c6a241853 100644 --- a/cmake/sample_defs/sample_mission_cfg.h +++ b/cmake/sample_defs/sample_mission_cfg.h @@ -47,7 +47,6 @@ ** messages sent. If the pkt length field indicates the message is larger ** than this define, SB sends an event and rejects the send. ** -** ** \par Limits ** This parameter has a lower limit of 6 (CCSDS primary header size). There ** are no restrictions on the upper limit however, the maximum message size is @@ -247,6 +246,7 @@ ** portion of a Full CDS Name of the following form: ** "ApplicationName.CDSName" ** +** This length does not need to include an extra character for NULL termination. ** ** \par Limits ** This value should be kept as a multiple of 4, to maintain alignment of @@ -264,6 +264,8 @@ ** Indicates the maximum length (in characters) of the formatted text ** string portion of an event message ** +** This length does not need to include an extra character for NULL termination. +** ** \par Limits ** Not Applicable */ @@ -299,6 +301,8 @@ ** ('TblName') portion of a Full Table Name of the following ** form: "ApplicationName.TblName" ** +** This length does not need to include an extra character for NULL termination. +** ** \par Limits ** This value should be kept as a multiple of 4, to maintain alignment of ** any possible neighboring fields without implicit padding. @@ -531,6 +535,8 @@ ** ** This affects only the layout of command/telemetry messages and table definitions; ** internal allocation may use the platform-specific OS_MAX_PATH_LEN value. +** +** This length must include an extra character for NULL termination. ** ** \par Limits ** All CPUs within the same SB domain (mission) and ground tools must share the @@ -557,6 +563,8 @@ ** This affects only the layout of command/telemetry messages and table definitions; ** internal allocation may use the platform-specific OS_MAX_FILE_LEN value. ** +** This length must include an extra character for NULL termination. +** ** \par Limits ** All CPUs within the same SB domain (mission) and ground tools must share the ** same definition. @@ -582,6 +590,8 @@ ** This affects only the layout of command/telemetry messages and table definitions; ** internal allocation may use the platform-specific OS_MAX_API_LEN value. ** +** This length must include an extra character for NULL termination. +** ** \par Limits ** All CPUs within the same SB domain (mission) must share the same definition ** Note this affects the size of messages, so it must not cause any message From ba562e39cee70244317bfe9730c4d9b8a7c998ec Mon Sep 17 00:00:00 2001 From: Jacob Hageman Date: Wed, 17 Feb 2021 15:12:41 -0500 Subject: [PATCH 5/7] Fix #1172, Update to use Ut_Stub_CheckDefaultReturnValue API --- fsw/cfe-core/ut-stubs/ut_tbl_stubs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fsw/cfe-core/ut-stubs/ut_tbl_stubs.c b/fsw/cfe-core/ut-stubs/ut_tbl_stubs.c index f9df4806a..f75ae4a35 100644 --- a/fsw/cfe-core/ut-stubs/ut_tbl_stubs.c +++ b/fsw/cfe-core/ut-stubs/ut_tbl_stubs.c @@ -132,7 +132,7 @@ int32 CFE_TBL_GetAddress (void **TblPtr, CFE_TBL_Handle_t TblHandle) int32 ForceValue; status = UT_DEFAULT_IMPL(CFE_TBL_GetAddress); - if (status >= 0 && !UT_Stub_CheckForceFail(UT_KEY(CFE_TBL_GetAddress), &ForceValue)) + if (status >= 0 && !UT_Stub_CheckDefaultReturnValue(UT_KEY(CFE_TBL_GetAddress), &ForceValue)) { UT_Stub_CopyToLocal(UT_KEY(CFE_TBL_GetAddress), (uint8 *)TblPtr, sizeof(void*)); } From 4ab182b789390f3a62afa19be309f1548302e1e7 Mon Sep 17 00:00:00 2001 From: Jacob Hageman Date: Thu, 18 Feb 2021 09:10:06 -0500 Subject: [PATCH 6/7] Fix #1160, Shorten task info default filename --- cmake/sample_defs/cpu1_platform_cfg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/sample_defs/cpu1_platform_cfg.h b/cmake/sample_defs/cpu1_platform_cfg.h index e45d64055..431c9960f 100644 --- a/cmake/sample_defs/cpu1_platform_cfg.h +++ b/cmake/sample_defs/cpu1_platform_cfg.h @@ -901,7 +901,7 @@ ** The length of each string, including the NULL terminator cannot exceed the ** #OS_MAX_PATH_LEN value. */ -#define CFE_PLATFORM_ES_DEFAULT_TASK_LOG_FILE "/ram/cfe_es_task_info.log" +#define CFE_PLATFORM_ES_DEFAULT_TASK_LOG_FILE "/ram/cfe_es_taskinfo.log" /** ** \cfeescfg Default System Log Filename From f282c361ce2b04906ff489a7f015acb30658e1bc Mon Sep 17 00:00:00 2001 From: "Gerardo E. Cruz-Ortiz" <59618057+astrogeco@users.noreply.github.com> Date: Fri, 26 Feb 2021 12:19:55 -0500 Subject: [PATCH 7/7] Bump to v6.8.0-rc1+dev365 --- README.md | 19 +++++++++++++++++++ fsw/cfe-core/src/inc/cfe_version.h | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f7e5fb10c..0b985bd14 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,25 @@ The detailed cFE user's guide can be viewed at + ### Development Build: 6.8.0-rc1+dev348 - Corrects reference to PSP header file location. Build now succesfully completes the build succeeds again when using `add_psp_module()` in custom CMakeLists file. diff --git a/fsw/cfe-core/src/inc/cfe_version.h b/fsw/cfe-core/src/inc/cfe_version.h index f7bd98e01..94cb45b7c 100644 --- a/fsw/cfe-core/src/inc/cfe_version.h +++ b/fsw/cfe-core/src/inc/cfe_version.h @@ -35,7 +35,7 @@ /* Development Build Macro Definitions */ -#define CFE_BUILD_NUMBER 348 /*!< Development Build: Number of commits since baseline */ +#define CFE_BUILD_NUMBER 365 /*!< Development Build: Number of commits since baseline */ #define CFE_BUILD_BASELINE "v6.8.0-rc1" /*!< Development Build: git tag that is the base for the current development */ /* Version Macro Definitions */