diff --git a/modules/tbl/fsw/src/cfe_tbl_api.c b/modules/tbl/fsw/src/cfe_tbl_api.c index 92dc8933c..06da7856b 100644 --- a/modules/tbl/fsw/src/cfe_tbl_api.c +++ b/modules/tbl/fsw/src/cfe_tbl_api.c @@ -49,7 +49,7 @@ CFE_Status_t CFE_TBL_Register(CFE_TBL_Handle_t *TblHandlePtr, const char *Name, { CFE_TBL_TxnState_t Txn; CFE_TBL_RegistryRec_t *RegRecPtr = NULL; - CFE_TBL_CritRegRec_t * CritRegRecPtr = NULL; + CFE_TBL_CritRegRec_t *CritRegRecPtr = NULL; CFE_Status_t Status; CFE_ES_AppId_t ThisAppId; char AppName[OS_MAX_API_NAME] = {"UNKNOWN"}; @@ -214,7 +214,7 @@ CFE_Status_t CFE_TBL_Share(CFE_TBL_Handle_t *TblHandlePtr, const char *TblName) int32 Status; CFE_ES_AppId_t ThisAppId; CFE_TBL_AccessDescriptor_t *AccessDescPtr = NULL; - CFE_TBL_RegistryRec_t * RegRecPtr = NULL; + CFE_TBL_RegistryRec_t *RegRecPtr = NULL; char AppName[OS_MAX_API_NAME] = {"UNKNOWN"}; if (TblHandlePtr == NULL || TblName == NULL) @@ -356,13 +356,14 @@ CFE_Status_t CFE_TBL_Unregister(CFE_TBL_Handle_t TblHandle) CFE_Status_t CFE_TBL_Load(CFE_TBL_Handle_t TblHandle, CFE_TBL_SrcEnum_t SrcType, const void *SrcDataPtr) { CFE_TBL_TxnState_t Txn; - int32 Status; + CFE_Status_t Status; CFE_ES_AppId_t ThisAppId; - CFE_TBL_LoadBuff_t * WorkingBufferPtr; + CFE_TBL_LoadBuff_t *WorkingBufferPtr = NULL; CFE_TBL_AccessDescriptor_t *AccessDescPtr; - CFE_TBL_RegistryRec_t * RegRecPtr; + CFE_TBL_RegistryRec_t *RegRecPtr; char AppName[OS_MAX_API_NAME] = {"UNKNOWN"}; - bool FirstTime = false; + bool IsFirstTime; + bool StillProcessing = true; if (SrcDataPtr == NULL) { @@ -377,7 +378,6 @@ CFE_Status_t CFE_TBL_Load(CFE_TBL_Handle_t TblHandle, CFE_TBL_SrcEnum_t SrcType, CFE_EVS_SendEventWithAppID(CFE_TBL_HANDLE_ACCESS_ERR_EID, CFE_EVS_EventType_ERROR, CFE_TBL_Global.TableTaskAppId, "%s: No access to Tbl Handle=%d", AppName, (int)TblHandle); - return Status; } @@ -385,204 +385,95 @@ CFE_Status_t CFE_TBL_Load(CFE_TBL_Handle_t TblHandle, CFE_TBL_SrcEnum_t SrcType, RegRecPtr = CFE_TBL_TxnRegRec(&Txn); ThisAppId = CFE_TBL_TxnAppId(&Txn); - /* - * This is not the end of the transaction - this is just put here for now - * until the many inline "return" statements in this function can be cleaned up. - * - * This means nearly everything is subject to race conditions, but it is no worse - * than it had been before. - */ - CFE_TBL_TxnFinish(&Txn); - /* Translate AppID of caller into App Name */ CFE_ES_GetAppName(AppName, ThisAppId, sizeof(AppName)); - /* Initialize return pointer to NULL */ - WorkingBufferPtr = NULL; - /* Check to see if this is a dump only table */ if (RegRecPtr->DumpOnly) { - if ((!RegRecPtr->UserDefAddr) || (RegRecPtr->TableLoadedOnce)) - { - CFE_EVS_SendEventWithAppID(CFE_TBL_LOADING_A_DUMP_ONLY_ERR_EID, CFE_EVS_EventType_ERROR, - CFE_TBL_Global.TableTaskAppId, "%s: Attempted to load Dump Only Tbl '%s'", - AppName, RegRecPtr->Name); - - return CFE_TBL_ERR_DUMP_ONLY; - } + Status = CFE_TBL_LoadDumpOnlyTable(RegRecPtr, AppName, SrcDataPtr); - /* The Application is allowed to call Load once when the address */ - /* of the dump only table is being defined by the application. */ - RegRecPtr->Buffers[0].BufferPtr = (void *)SrcDataPtr; - RegRecPtr->TableLoadedOnce = true; - - snprintf(RegRecPtr->Buffers[0].DataSource, sizeof(RegRecPtr->Buffers[0].DataSource), "Addr 0x%08lX", - (unsigned long)SrcDataPtr); - - RegRecPtr->Buffers[0].FileTime = CFE_TIME_ZERO_VALUE; - - CFE_EVS_SendEventWithAppID(CFE_TBL_LOAD_SUCCESS_INF_EID, CFE_EVS_EventType_DEBUG, CFE_TBL_Global.TableTaskAppId, - "Successfully loaded '%s' from '%s'", RegRecPtr->Name, - RegRecPtr->Buffers[0].DataSource); - - return CFE_SUCCESS; + StillProcessing = false; } /* Loads by an Application are not allowed if a table load is already in progress */ - if (RegRecPtr->LoadInProgress != CFE_TBL_NO_LOAD_IN_PROGRESS) + if (StillProcessing && RegRecPtr->LoadInProgress != CFE_TBL_NO_LOAD_IN_PROGRESS) { CFE_EVS_SendEventWithAppID(CFE_TBL_LOAD_IN_PROGRESS_ERR_EID, CFE_EVS_EventType_ERROR, CFE_TBL_Global.TableTaskAppId, "%s: Load already in progress for '%s'", AppName, RegRecPtr->Name); - return CFE_TBL_ERR_LOAD_IN_PROGRESS; - } - - /* Obtain a working buffer (either the table's dedicated buffer or one of the shared buffers) */ - Status = CFE_TBL_GetWorkingBuffer(&WorkingBufferPtr, RegRecPtr, true); - - if (Status != CFE_SUCCESS) - { - CFE_EVS_SendEventWithAppID(CFE_TBL_NO_WORK_BUFFERS_ERR_EID, CFE_EVS_EventType_ERROR, - CFE_TBL_Global.TableTaskAppId, "%s: Failed to get Working Buffer (Stat=%u)", AppName, - (unsigned int)Status); + Status = CFE_TBL_ERR_LOAD_IN_PROGRESS; - return Status; + StillProcessing = false; } - /* Perform appropriate update to working buffer */ - /* Determine whether the load is to occur from a file or from a block of memory */ - switch (SrcType) + if (StillProcessing) { - case CFE_TBL_SRC_FILE: - /* Load the data from the file into the specified buffer */ - Status = CFE_TBL_LoadFromFile(AppName, WorkingBufferPtr, RegRecPtr, (const char *)SrcDataPtr); - - if ((Status == CFE_TBL_WARN_PARTIAL_LOAD) && (!RegRecPtr->TableLoadedOnce)) - { - /* Uninitialized tables cannot be loaded with partial table loads */ - /* Partial loads can only occur on previously loaded tables. */ - CFE_EVS_SendEventWithAppID(CFE_TBL_PARTIAL_LOAD_ERR_EID, CFE_EVS_EventType_ERROR, - CFE_TBL_Global.TableTaskAppId, - "%s: Attempted to load from partial Tbl '%s' from '%s' (Stat=%u)", AppName, - RegRecPtr->Name, (const char *)SrcDataPtr, (unsigned int)Status); - - Status = CFE_TBL_ERR_PARTIAL_LOAD; - } - - break; - case CFE_TBL_SRC_ADDRESS: - /* When the source is a block of memory, it is assumed to be a complete load */ - memcpy(WorkingBufferPtr->BufferPtr, (uint8 *)SrcDataPtr, RegRecPtr->Size); - - snprintf(WorkingBufferPtr->DataSource, sizeof(WorkingBufferPtr->DataSource), "Addr 0x%08lX", - (unsigned long)SrcDataPtr); - - WorkingBufferPtr->FileTime = CFE_TIME_ZERO_VALUE; - - /* Compute the CRC on the specified table buffer */ - WorkingBufferPtr->Crc = - CFE_ES_CalculateCRC(WorkingBufferPtr->BufferPtr, RegRecPtr->Size, 0, CFE_MISSION_ES_DEFAULT_CRC); + /* Obtain a working buffer (either the table's dedicated buffer or one of the shared buffers) */ + Status = CFE_TBL_GetWorkingBuffer(&WorkingBufferPtr, RegRecPtr, true); - break; - default: - CFE_EVS_SendEventWithAppID(CFE_TBL_LOAD_TYPE_ERR_EID, CFE_EVS_EventType_ERROR, - CFE_TBL_Global.TableTaskAppId, - "%s: Attempted to load from illegal source type=%d", AppName, (int)SrcType); + if (Status != CFE_SUCCESS) + { + CFE_EVS_SendEventWithAppID(CFE_TBL_NO_WORK_BUFFERS_ERR_EID, CFE_EVS_EventType_ERROR, + CFE_TBL_Global.TableTaskAppId, "%s: Failed to get Working Buffer (Stat=%u)", + AppName, (unsigned int)Status); - Status = CFE_TBL_ERR_ILLEGAL_SRC_TYPE; + StillProcessing = false; + } } - /* If the data was successfully loaded, then validate its contents */ - if ((Status >= CFE_SUCCESS) && (RegRecPtr->ValidationFuncPtr != NULL)) + if (StillProcessing) { - Status = (RegRecPtr->ValidationFuncPtr)(WorkingBufferPtr->BufferPtr); + /* Perform appropriate update to working buffer */ + /* Determine whether the load is to occur from a file or from a block of memory */ + Status = CFE_TBL_LoadWorkingBuffer(SrcType, AppName, WorkingBufferPtr, RegRecPtr, SrcDataPtr); - if (Status > CFE_SUCCESS) + /* If the data was successfully loaded, then validate its contents */ + if ((Status >= CFE_SUCCESS) && (RegRecPtr->ValidationFuncPtr != NULL)) { - CFE_EVS_SendEventWithAppID(CFE_TBL_LOAD_VAL_ERR_EID, CFE_EVS_EventType_ERROR, CFE_TBL_Global.TableTaskAppId, - "%s: Validation func return code invalid (Stat=%u) for '%s'", AppName, - (unsigned int)Status, RegRecPtr->Name); - - Status = -1; + Status = CFE_TBL_ValidateWorkingBufferContents(RegRecPtr, WorkingBufferPtr, AppName); } - if (Status < 0) + // Free the working buffer if there was an error up to this point + if (Status < CFE_SUCCESS) { - CFE_EVS_SendEventWithAppID(CFE_TBL_VALIDATION_ERR_EID, CFE_EVS_EventType_ERROR, - CFE_TBL_Global.TableTaskAppId, - "%s: Validation func reports table invalid (Stat=%u) for '%s'", AppName, - (unsigned int)Status, RegRecPtr->Name); + /* The load has had a problem, free the working buffer for another attempt */ + if ((!RegRecPtr->DoubleBuffered) && (RegRecPtr->TableLoadedOnce == true)) + { + /* For single-buffered tables, freeing entails resetting flag */ + CFE_TBL_Global.LoadBuffs[RegRecPtr->LoadInProgress].Taken = false; + } - /* Zero out the buffer to remove any bad data */ - memset(WorkingBufferPtr->BufferPtr, 0, RegRecPtr->Size); - } - } + /* For double-buffered tables, freeing buffer is simple */ + RegRecPtr->LoadInProgress = CFE_TBL_NO_LOAD_IN_PROGRESS; - /* Perform the table update to complete the load */ - if (Status < CFE_SUCCESS) - { - /* The load has had a problem, free the working buffer for another attempt */ - if ((!RegRecPtr->DoubleBuffered) && (RegRecPtr->TableLoadedOnce == true)) - { - /* For single-buffered tables, freeing entails resetting flag */ - CFE_TBL_Global.LoadBuffs[RegRecPtr->LoadInProgress].Taken = false; + StillProcessing = false; } - - /* For double-buffered tables, freeing buffer is simple */ - RegRecPtr->LoadInProgress = CFE_TBL_NO_LOAD_IN_PROGRESS; - - return Status; } - FirstTime = !RegRecPtr->TableLoadedOnce; - - /* If this is not the first load, then the data must be moved from the inactive buffer */ - /* to the active buffer to complete the load. First loads are done directly to the active. */ - if (!FirstTime) + if (StillProcessing) { - /* Force the table update */ - RegRecPtr->LoadPending = true; + IsFirstTime = !RegRecPtr->TableLoadedOnce; - Status = CFE_TBL_UpdateInternal(TblHandle, RegRecPtr, AccessDescPtr); + /* Perform the table update to complete the load */ + Status = CFE_TBL_PerformUpdate(RegRecPtr, TblHandle, AccessDescPtr, AppName, WorkingBufferPtr, IsFirstTime); - if (Status != CFE_SUCCESS) + if (Status == CFE_SUCCESS) { - CFE_EVS_SendEventWithAppID(CFE_TBL_UPDATE_ERR_EID, CFE_EVS_EventType_ERROR, CFE_TBL_Global.TableTaskAppId, - "%s: Failed to update '%s' (Stat=%u)", AppName, RegRecPtr->Name, - (unsigned int)Status); - } - } - else - { - /* On initial loads, make sure registry is given file/address of data source */ - strncpy(RegRecPtr->LastFileLoaded, WorkingBufferPtr->DataSource, sizeof(RegRecPtr->LastFileLoaded) - 1); - RegRecPtr->LastFileLoaded[sizeof(RegRecPtr->LastFileLoaded) - 1] = '\0'; - - CFE_TBL_NotifyTblUsersOfUpdate(RegRecPtr); + /* The first time a table is loaded, the event message is DEBUG */ + /* to help eliminate a flood of events during a startup */ + CFE_EVS_SendEventWithAppID(CFE_TBL_LOAD_SUCCESS_INF_EID, + IsFirstTime ? CFE_EVS_EventType_DEBUG : CFE_EVS_EventType_INFORMATION, + CFE_TBL_Global.TableTaskAppId, "Successfully loaded '%s' from '%s'", + RegRecPtr->Name, RegRecPtr->LastFileLoaded); - /* If the table is a critical table, update the appropriate CDS with the new data */ - if (RegRecPtr->CriticalTable == true) - { - CFE_TBL_UpdateCriticalTblCDS(RegRecPtr); + /* Save the index of the table for housekeeping telemetry */ + CFE_TBL_Global.LastTblUpdated = AccessDescPtr->RegIndex; } - - Status = CFE_SUCCESS; } - if (Status == CFE_SUCCESS) - { - /* The first time a table is loaded, the event message is DEBUG */ - /* to help eliminate a flood of events during a startup */ - CFE_EVS_SendEventWithAppID(CFE_TBL_LOAD_SUCCESS_INF_EID, - FirstTime ? CFE_EVS_EventType_DEBUG : CFE_EVS_EventType_INFORMATION, - CFE_TBL_Global.TableTaskAppId, "Successfully loaded '%s' from '%s'", RegRecPtr->Name, - RegRecPtr->LastFileLoaded); - - /* Save the index of the table for housekeeping telemetry */ - CFE_TBL_Global.LastTblUpdated = AccessDescPtr->RegIndex; - } + CFE_TBL_TxnFinish(&Txn); return Status; } @@ -598,7 +489,7 @@ CFE_Status_t CFE_TBL_Update(CFE_TBL_Handle_t TblHandle) CFE_TBL_TxnState_t Txn; int32 Status; CFE_ES_AppId_t ThisAppId; - CFE_TBL_RegistryRec_t * RegRecPtr = NULL; + CFE_TBL_RegistryRec_t *RegRecPtr = NULL; CFE_TBL_AccessDescriptor_t *AccessDescPtr = NULL; char AppName[OS_MAX_API_NAME] = {"UNKNOWN"}; @@ -841,11 +732,11 @@ CFE_Status_t CFE_TBL_Validate(CFE_TBL_Handle_t TblHandle) { CFE_TBL_TxnState_t Txn; int32 Status; - CFE_TBL_RegistryRec_t * RegRecPtr; + CFE_TBL_RegistryRec_t *RegRecPtr; char AppName[OS_MAX_API_NAME] = {"UNKNOWN"}; - CFE_TBL_LoadBuff_t * BuffPtr; + CFE_TBL_LoadBuff_t *BuffPtr; CFE_TBL_ValidationResult_t *ResultPtr; - const char * LogTagStr; + const char *LogTagStr; ResultPtr = NULL; BuffPtr = NULL; @@ -1096,7 +987,7 @@ CFE_Status_t CFE_TBL_DumpToBuffer(CFE_TBL_Handle_t TblHandle) int32 Status; CFE_TBL_RegistryRec_t *RegRecPtr = NULL; CFE_TBL_DumpControl_t *DumpCtrlPtr = NULL; - CFE_TBL_LoadBuff_t * ActiveBufPtr; + CFE_TBL_LoadBuff_t *ActiveBufPtr; Status = CFE_TBL_TxnStartFromHandle(&Txn, TblHandle, CFE_TBL_TxnContext_ACCESSOR_APP); diff --git a/modules/tbl/fsw/src/cfe_tbl_internal.c b/modules/tbl/fsw/src/cfe_tbl_internal.c index 3a407ee45..7ed8a1666 100644 --- a/modules/tbl/fsw/src/cfe_tbl_internal.c +++ b/modules/tbl/fsw/src/cfe_tbl_internal.c @@ -398,7 +398,7 @@ CFE_TBL_LoadBuff_t *CFE_TBL_GetInactiveBuffer(CFE_TBL_RegistryRec_t *RegRecPtr) * See description in header file for argument/return detail * *-----------------------------------------------------------------*/ -CFE_TBL_LoadBuff_t *CFE_TBL_GetSelectedBuffer(CFE_TBL_RegistryRec_t * RegRecPtr, +CFE_TBL_LoadBuff_t *CFE_TBL_GetSelectedBuffer(CFE_TBL_RegistryRec_t *RegRecPtr, CFE_TBL_BufferSelect_Enum_t BufferSelect) { CFE_TBL_LoadBuff_t *Result; @@ -1660,7 +1660,7 @@ void CFE_TBL_CountAccessDescHelper(CFE_TBL_AccessDescriptor_t *AccDescPtr, void *-----------------------------------------------------------------*/ CFE_TBL_ValidationResult_t *CFE_TBL_CheckValidationRequest(CFE_TBL_ValidationResultId_t *ValIdPtr) { - CFE_TBL_ValidationResult_t * ResultPtr; + CFE_TBL_ValidationResult_t *ResultPtr; CFE_TBL_ValidationResultId_t ValId; ValId = *ValIdPtr; @@ -1690,3 +1690,181 @@ CFE_TBL_ValidationResult_t *CFE_TBL_CheckValidationRequest(CFE_TBL_ValidationRes return ResultPtr; } + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +CFE_Status_t CFE_TBL_LoadDumpOnlyTable(CFE_TBL_RegistryRec_t *RegRecPtr, const char *AppName, const void *SrcDataPtr) +{ + CFE_Status_t Status = CFE_SUCCESS; + + if ((!RegRecPtr->UserDefAddr) || (RegRecPtr->TableLoadedOnce)) + { + CFE_EVS_SendEventWithAppID(CFE_TBL_LOADING_A_DUMP_ONLY_ERR_EID, CFE_EVS_EventType_ERROR, + CFE_TBL_Global.TableTaskAppId, "%s: Attempted to load Dump Only Tbl '%s'", AppName, + RegRecPtr->Name); + + Status = CFE_TBL_ERR_DUMP_ONLY; + } + else + { + /* The Application is allowed to call Load once when the address */ + /* of the dump only table is being defined by the application. */ + RegRecPtr->Buffers[0].BufferPtr = (void *)SrcDataPtr; + RegRecPtr->TableLoadedOnce = true; + + snprintf(RegRecPtr->Buffers[0].DataSource, sizeof(RegRecPtr->Buffers[0].DataSource), "Addr 0x%08lX", + (unsigned long)SrcDataPtr); + + RegRecPtr->Buffers[0].FileTime = CFE_TIME_ZERO_VALUE; + + CFE_EVS_SendEventWithAppID(CFE_TBL_LOAD_SUCCESS_INF_EID, CFE_EVS_EventType_DEBUG, CFE_TBL_Global.TableTaskAppId, + "Successfully loaded '%s' from '%s'", RegRecPtr->Name, + RegRecPtr->Buffers[0].DataSource); + } + + return Status; +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +CFE_Status_t CFE_TBL_LoadWorkingBuffer(const CFE_TBL_SrcEnum_t SrcType, const char *AppName, + CFE_TBL_LoadBuff_t *WorkingBufferPtr, CFE_TBL_RegistryRec_t *RegRecPtr, + const void *SrcDataPtr) +{ + CFE_Status_t Status = CFE_SUCCESS; + + switch (SrcType) + { + case CFE_TBL_SRC_FILE: + /* Load the data from the file into the specified buffer */ + Status = CFE_TBL_LoadFromFile(AppName, WorkingBufferPtr, RegRecPtr, (const char *)SrcDataPtr); + + if ((Status == CFE_TBL_WARN_PARTIAL_LOAD) && (!RegRecPtr->TableLoadedOnce)) + { + /* Uninitialized tables cannot be loaded with partial table loads */ + /* Partial loads can only occur on previously loaded tables. */ + CFE_EVS_SendEventWithAppID(CFE_TBL_PARTIAL_LOAD_ERR_EID, CFE_EVS_EventType_ERROR, + CFE_TBL_Global.TableTaskAppId, + "%s: Attempted to load from partial Tbl '%s' from '%s' (Stat=%u)", AppName, + RegRecPtr->Name, (const char *)SrcDataPtr, (unsigned int)Status); + + Status = CFE_TBL_ERR_PARTIAL_LOAD; + } + + break; + + case CFE_TBL_SRC_ADDRESS: + /* When the source is a block of memory, it is assumed to be a complete load */ + memcpy(WorkingBufferPtr->BufferPtr, (uint8 *)SrcDataPtr, RegRecPtr->Size); + + snprintf(WorkingBufferPtr->DataSource, sizeof(WorkingBufferPtr->DataSource), "Addr 0x%08lX", + (unsigned long)SrcDataPtr); + + WorkingBufferPtr->FileTime = CFE_TIME_ZERO_VALUE; + + /* Compute the CRC on the specified table buffer */ + WorkingBufferPtr->Crc = + CFE_ES_CalculateCRC(WorkingBufferPtr->BufferPtr, RegRecPtr->Size, 0, CFE_MISSION_ES_DEFAULT_CRC); + + break; + + default: + CFE_EVS_SendEventWithAppID(CFE_TBL_LOAD_TYPE_ERR_EID, CFE_EVS_EventType_ERROR, + CFE_TBL_Global.TableTaskAppId, + "%s: Attempted to load from illegal source type=%d", AppName, (int)SrcType); + + Status = CFE_TBL_ERR_ILLEGAL_SRC_TYPE; + + break; + } + + return Status; +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ + +CFE_Status_t CFE_TBL_ValidateWorkingBufferContents(CFE_TBL_RegistryRec_t *RegRecPtr, + CFE_TBL_LoadBuff_t *WorkingBufferPtr, const char *AppName) +{ + CFE_Status_t Status = (RegRecPtr->ValidationFuncPtr)(WorkingBufferPtr->BufferPtr); + + if (Status > CFE_SUCCESS) + { + CFE_EVS_SendEventWithAppID(CFE_TBL_LOAD_VAL_ERR_EID, CFE_EVS_EventType_ERROR, CFE_TBL_Global.TableTaskAppId, + "%s: Validation func return code invalid (Stat=%u) for '%s'", AppName, + (unsigned int)Status, RegRecPtr->Name); + + Status = CFE_STATUS_VALIDATION_FAILURE; + } + + if (Status < CFE_SUCCESS) + { + CFE_EVS_SendEventWithAppID(CFE_TBL_VALIDATION_ERR_EID, CFE_EVS_EventType_ERROR, CFE_TBL_Global.TableTaskAppId, + "%s: Validation func reports table invalid (Stat=%u) for '%s'", AppName, + (unsigned int)Status, RegRecPtr->Name); + + /* Zero out the buffer to remove any bad data */ + memset(WorkingBufferPtr->BufferPtr, 0, RegRecPtr->Size); + } + + return Status; +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +CFE_Status_t CFE_TBL_PerformUpdate(CFE_TBL_RegistryRec_t *RegRecPtr, const CFE_TBL_Handle_t TblHandle, + CFE_TBL_AccessDescriptor_t *AccessDescPtr, const char *AppName, + const CFE_TBL_LoadBuff_t *WorkingBufferPtr, const bool IsFirstTime) +{ + CFE_Status_t Status = CFE_SUCCESS; + + /* If this is not the first load, then the data must be moved from the inactive buffer */ + /* to the active buffer to complete the load. First loads are done directly to the active. */ + if (!IsFirstTime) + { + /* Force the table update */ + RegRecPtr->LoadPending = true; + + Status = CFE_TBL_UpdateInternal(TblHandle, RegRecPtr, AccessDescPtr); + + if (Status != CFE_SUCCESS) + { + CFE_EVS_SendEventWithAppID(CFE_TBL_UPDATE_ERR_EID, CFE_EVS_EventType_ERROR, CFE_TBL_Global.TableTaskAppId, + "%s: Failed to update '%s' (Stat=%u)", AppName, RegRecPtr->Name, + (unsigned int)Status); + } + } + else + { + /* On initial loads, make sure registry is given file/address of data source */ + strncpy(RegRecPtr->LastFileLoaded, WorkingBufferPtr->DataSource, sizeof(RegRecPtr->LastFileLoaded) - 1); + RegRecPtr->LastFileLoaded[sizeof(RegRecPtr->LastFileLoaded) - 1] = '\0'; + + CFE_TBL_NotifyTblUsersOfUpdate(RegRecPtr); + + /* If the table is a critical table, update the appropriate CDS with the new data */ + if (RegRecPtr->CriticalTable) + { + CFE_TBL_UpdateCriticalTblCDS(RegRecPtr); + } + } + + return Status; +} diff --git a/modules/tbl/fsw/src/cfe_tbl_internal.h b/modules/tbl/fsw/src/cfe_tbl_internal.h index 23c7654c0..1f7106972 100644 --- a/modules/tbl/fsw/src/cfe_tbl_internal.h +++ b/modules/tbl/fsw/src/cfe_tbl_internal.h @@ -717,7 +717,7 @@ CFE_TBL_LoadBuff_t *CFE_TBL_GetInactiveBuffer(CFE_TBL_RegistryRec_t *RegRecPtr); ** \param BufferSelect The buffer to obtain (active or inactive) ** \returns Pointer to the selected table buffer */ -CFE_TBL_LoadBuff_t *CFE_TBL_GetSelectedBuffer(CFE_TBL_RegistryRec_t * RegRecPtr, +CFE_TBL_LoadBuff_t *CFE_TBL_GetSelectedBuffer(CFE_TBL_RegistryRec_t *RegRecPtr, CFE_TBL_BufferSelect_Enum_t BufferSelect); /*---------------------------------------------------------------------------------------*/ @@ -745,6 +745,90 @@ CFE_TBL_LoadBuff_t *CFE_TBL_GetSelectedBuffer(CFE_TBL_RegistryRec_t * RegRec */ CFE_TBL_ValidationResult_t *CFE_TBL_CheckValidationRequest(CFE_TBL_ValidationResultId_t *ValIdPtr); +/*---------------------------------------------------------------------------------------*/ +/** +** \brief Load data into a Dump-Only Table +** +** \par Description +** This function loads data into a Dump-Only Table. It ensures that the table is only loaded once +** and that the address is defined by the application. If the table has already been loaded or +** the address is not user-defined, an error event is sent. +** +** \param RegRecPtr Pointer to Table Registry Record for table to be loaded. +** \param AppName The name of the application attempting to load the table. +** \param SrcDataPtr Pointer to the source data to be loaded into the table. +** +** \return Execution status, see \ref CFEReturnCodes +** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS +** \retval #CFE_TBL_ERR_DUMP_ONLY \copybrief CFE_TBL_ERR_DUMP_ONLY +*/ +CFE_Status_t CFE_TBL_LoadDumpOnlyTable(CFE_TBL_RegistryRec_t *RegRecPtr, const char *AppName, const void *SrcDataPtr); + +/** +** \brief Load data into a working buffer for a table +** +** \par Description +** This function loads data into a working buffer from a specified source type (file or memory address). +** The function also handles partial loads and computes the CRC for the loaded data. +** +** \param SrcType The type of source (file or memory address). +** \param AppName The name of the application attempting to load the buffer. +** \param WorkingBufferPtr Pointer to the working buffer where data will be loaded. +** \param RegRecPtr Pointer to the table registry record. +** \param SrcDataPtr Pointer to the source data (file name or memory address). +** +** \return Execution status, see \ref CFEReturnCodes +** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS +** \retval #CFE_TBL_WARN_PARTIAL_LOAD \copybrief CFE_TBL_WARN_PARTIAL_LOAD +** \retval #CFE_TBL_ERR_PARTIAL_LOAD \copybrief CFE_TBL_ERR_PARTIAL_LOAD +** \retval #CFE_TBL_ERR_ILLEGAL_SRC_TYPE \copybrief CFE_TBL_ERR_ILLEGAL_SRC_TYPE +*/ +CFE_Status_t CFE_TBL_LoadWorkingBuffer(const CFE_TBL_SrcEnum_t SrcType, const char *AppName, + CFE_TBL_LoadBuff_t *WorkingBufferPtr, CFE_TBL_RegistryRec_t *RegRecPtr, + const void *SrcDataPtr); + +/** +** \brief Validate the contents of a working buffer for a table +** +** \par Description +** This function validates the contents of a working buffer using the validation function +** specified in the table registry record. +** +** \param RegRecPtr Pointer to the Table Registry record. +** \param WorkingBufferPtr Pointer to the working buffer to be validated. +** \param AppName The name of the application attempting to validate the buffer. +** +** \return Execution status, see \ref CFEReturnCodes +** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS +** \retval #CFE_STATUS_VALIDATION_FAILURE \copybrief CFE_STATUS_VALIDATION_FAILURE +*/ +CFE_Status_t CFE_TBL_ValidateWorkingBufferContents(CFE_TBL_RegistryRec_t *RegRecPtr, + CFE_TBL_LoadBuff_t *WorkingBufferPtr, const char *AppName); + +/** +** \brief Perform the update of a table's working buffer +** +** \par Description +** This function performs the update of a table's working buffer. If this is the first load, the +** data is directly loaded into the active buffer. If not the first load, the data is moved from +** the inactive buffer to the active buffer. +** For first-time loads, the function also updates the table registry with the data source information +** and notifies table users of the update. If the table is a critical table, the CDS is also updated. +** +** \param RegRecPtr Pointer to the Table Registry record. +** \param TblHandle Handle of the table to be updated. +** \param AccessDescPtr Pointer to the access descriptor for the table. +** \param AppName The name of the application performing the update. +** \param WorkingBufferPtr Pointer to the working buffer containing the data to be loaded. +** \param IsFirstTime Boolean indicating if this is the first load of the table. +** +** \return Execution status, see \ref CFEReturnCodes +** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS +** \retval #CFE_TBL_UPDATE_ERR_EID \copybrief CFE_TBL_UPDATE_ERR_EID +*/ +CFE_Status_t CFE_TBL_PerformUpdate(CFE_TBL_RegistryRec_t *RegRecPtr, const CFE_TBL_Handle_t TblHandle, + CFE_TBL_AccessDescriptor_t *AccessDescPtr, const char *AppName, + const CFE_TBL_LoadBuff_t *WorkingBufferPtr, const bool IsFirstTime); /* ** Globals specific to the TBL module */ diff --git a/modules/tbl/ut-coverage/tbl_UT.c b/modules/tbl/ut-coverage/tbl_UT.c index 64c08e044..ff5e83f12 100644 --- a/modules/tbl/ut-coverage/tbl_UT.c +++ b/modules/tbl/ut-coverage/tbl_UT.c @@ -2273,7 +2273,7 @@ void Test_CFE_TBL_Load(void) */ UT_InitData(); UT_SetDeferredRetcode(UT_KEY(Test_CFE_TBL_ValidationFunc), 1, 1); - UtAssert_INT32_EQ(CFE_TBL_Load(App1TblHandle1, CFE_TBL_SRC_ADDRESS, &TestTable1), -1); + UtAssert_INT32_EQ(CFE_TBL_Load(App1TblHandle1, CFE_TBL_SRC_ADDRESS, &TestTable1), CFE_STATUS_VALIDATION_FAILURE); CFE_UtAssert_EVENTSENT(CFE_TBL_LOAD_VAL_ERR_EID); CFE_UtAssert_EVENTCOUNT(2);