From 4dc37e2e616829c0d64fc9d46f60a3370735a650 Mon Sep 17 00:00:00 2001 From: Joseph Hickey Date: Thu, 18 Apr 2024 10:44:09 -0400 Subject: [PATCH] Fix #2550, Use resource ID for validation index Use a resourceID value for access into the validation result structure array. This allows for consistent lookup, matching, and free/in-use determination, as well as improved resilience to race conditions and stale data. --- .../fsw/inc/cfe_core_resourceid_basevalues.h | 8 + modules/tbl/fsw/src/cfe_tbl_api.c | 138 +++--- modules/tbl/fsw/src/cfe_tbl_internal.c | 168 +++++++- modules/tbl/fsw/src/cfe_tbl_internal.h | 10 +- modules/tbl/fsw/src/cfe_tbl_resource.c | 67 +++ modules/tbl/fsw/src/cfe_tbl_resource.h | 268 ++++++++++++ modules/tbl/fsw/src/cfe_tbl_task.h | 49 ++- modules/tbl/fsw/src/cfe_tbl_task_cmds.c | 106 ++--- modules/tbl/fsw/src/cfe_tbl_transaction.c | 4 +- modules/tbl/fsw/src/cfe_tbl_transaction.h | 17 +- modules/tbl/ut-coverage/tbl_UT.c | 400 +++++++++++------- modules/tbl/ut-coverage/tbl_UT.h | 5 + 12 files changed, 910 insertions(+), 330 deletions(-) diff --git a/modules/resourceid/fsw/inc/cfe_core_resourceid_basevalues.h b/modules/resourceid/fsw/inc/cfe_core_resourceid_basevalues.h index 3c851430b..443136be6 100644 --- a/modules/resourceid/fsw/inc/cfe_core_resourceid_basevalues.h +++ b/modules/resourceid/fsw/inc/cfe_core_resourceid_basevalues.h @@ -70,6 +70,10 @@ enum /* configuration registry */ CFE_RESOURCEID_CONFIGID_BASE_OFFSET = OS_OBJECT_TYPE_USER + 7, + + /* TBL managed resources */ + CFE_RESOURCEID_TBL_VALRESULTID_BASE_OFFSET = OS_OBJECT_TYPE_USER + 8, + }; /* @@ -92,6 +96,10 @@ enum /* configuration registry */ CFE_CONFIGID_BASE = CFE_RESOURCEID_MAKE_BASE(CFE_RESOURCEID_CONFIGID_BASE_OFFSET), + + /* TBL managed resources */ + CFE_TBL_VALRESULTID_BASE = CFE_RESOURCEID_MAKE_BASE(CFE_RESOURCEID_TBL_VALRESULTID_BASE_OFFSET), + }; /** @} */ diff --git a/modules/tbl/fsw/src/cfe_tbl_api.c b/modules/tbl/fsw/src/cfe_tbl_api.c index 36e08f068..e63252ef8 100644 --- a/modules/tbl/fsw/src/cfe_tbl_api.c +++ b/modules/tbl/fsw/src/cfe_tbl_api.c @@ -839,128 +839,90 @@ CFE_Status_t CFE_TBL_ReleaseAddresses(uint16 NumTables, const CFE_TBL_Handle_t T *-----------------------------------------------------------------*/ CFE_Status_t CFE_TBL_Validate(CFE_TBL_Handle_t TblHandle) { - CFE_TBL_TxnState_t Txn; - int32 Status; - CFE_ES_AppId_t ThisAppId; - CFE_TBL_RegistryRec_t *RegRecPtr; - char AppName[OS_MAX_API_NAME] = {"UNKNOWN"}; + CFE_TBL_TxnState_t Txn; + int32 Status; + CFE_TBL_RegistryRec_t * RegRecPtr; + char AppName[OS_MAX_API_NAME] = {"UNKNOWN"}; + CFE_TBL_LoadBuff_t * BuffPtr; + CFE_TBL_ValidationResult_t *ResultPtr; + const char * LogTagStr; + + ResultPtr = NULL; + BuffPtr = NULL; + LogTagStr = "(none)"; /* Verify that this application has the right to perform operation */ Status = CFE_TBL_TxnStartFromHandle(&Txn, TblHandle, CFE_TBL_TxnContext_OWNER_APP); - - ThisAppId = CFE_TBL_TxnAppId(&Txn); - if (Status == CFE_SUCCESS) { /* Get pointers to pertinent records in registry and handles */ RegRecPtr = CFE_TBL_TxnRegRec(&Txn); - CFE_TBL_TxnFinish(&Txn); - - CFE_ES_GetAppName(AppName, ThisAppId, sizeof(AppName)); - /* Identify the image to be validated, starting with the Inactive Buffer */ - if (RegRecPtr->ValidateInactiveIndex != CFE_TBL_NO_VALIDATION_PENDING) + ResultPtr = CFE_TBL_CheckValidationRequest(&RegRecPtr->ValidateInactiveId); + if (ResultPtr != NULL) + { + LogTagStr = "inactive"; + BuffPtr = CFE_TBL_GetInactiveBuffer(RegRecPtr); + } + else { - /* Identify whether the Inactive Buffer is a shared buffer or a dedicated one */ - if (RegRecPtr->DoubleBuffered) + ResultPtr = CFE_TBL_CheckValidationRequest(&RegRecPtr->ValidateActiveId); + if (ResultPtr != NULL) { - /* Call the Application's Validation function for the Inactive Buffer */ - Status = - (RegRecPtr->ValidationFuncPtr)(RegRecPtr->Buffers[(1U - RegRecPtr->ActiveBufferIndex)].BufferPtr); - - /* Allow buffer to be activated after passing validation */ - if (Status == CFE_SUCCESS) - { - RegRecPtr->Buffers[(1U - RegRecPtr->ActiveBufferIndex)].Validated = true; - } + LogTagStr = "active"; + BuffPtr = CFE_TBL_GetActiveBuffer(RegRecPtr); } - else - { - /* Call the Application's Validation function for the appropriate shared buffer */ - Status = (RegRecPtr->ValidationFuncPtr)(CFE_TBL_Global.LoadBuffs[RegRecPtr->LoadInProgress].BufferPtr); + } - /* Allow buffer to be activated after passing validation */ - if (Status == CFE_SUCCESS) - { - CFE_TBL_Global.LoadBuffs[RegRecPtr->LoadInProgress].Validated = true; - } - } + CFE_TBL_TxnFinish(&Txn); - if (Status == CFE_SUCCESS) - { - CFE_EVS_SendEventWithAppID(CFE_TBL_VALIDATION_INF_EID, CFE_EVS_EventType_INFORMATION, - CFE_TBL_Global.TableTaskAppId, "%s validation successful for Inactive '%s'", - AppName, RegRecPtr->Name); - } - else + if (ResultPtr != NULL) + { + if (BuffPtr == NULL) { - CFE_EVS_SendEventWithAppID(CFE_TBL_VALIDATION_ERR_EID, CFE_EVS_EventType_ERROR, - CFE_TBL_Global.TableTaskAppId, - "%s validation failed for Inactive '%s', Status=0x%08X", AppName, - RegRecPtr->Name, (unsigned int)Status); - - if (Status > CFE_SUCCESS) - { - CFE_ES_WriteToSysLog("%s: App(%lu) Validation func return code invalid (Stat=0x%08X) for '%s'\n", - __func__, CFE_RESOURCEID_TO_ULONG(CFE_TBL_Global.TableTaskAppId), - (unsigned int)Status, RegRecPtr->Name); - } + /* No buffer, it cannot be valid */ + ResultPtr->Result = -1; } - - /* Save the result of the Validation function for the Table Services Task */ - CFE_TBL_Global.ValidationResults[RegRecPtr->ValidateInactiveIndex].Result = Status; - - /* Once validation is complete, set flags to indicate response is ready */ - CFE_TBL_Global.ValidationResults[RegRecPtr->ValidateInactiveIndex].State = CFE_TBL_VALIDATION_PERFORMED; - RegRecPtr->ValidateInactiveIndex = CFE_TBL_NO_VALIDATION_PENDING; - - /* Since the validation was successfully performed (although maybe not a successful result) */ - /* return a success status */ - Status = CFE_SUCCESS; - } - else if (RegRecPtr->ValidateActiveIndex != CFE_TBL_NO_VALIDATION_PENDING) - { - /* Perform validation on the currently active table buffer */ - /* Identify whether the Active Buffer is a shared buffer or a dedicated one */ - if (RegRecPtr->DoubleBuffered) + else if (RegRecPtr->ValidationFuncPtr == NULL) { - /* Call the Application's Validation function for the Dedicated Active Buffer */ - Status = (RegRecPtr->ValidationFuncPtr)(RegRecPtr->Buffers[RegRecPtr->ActiveBufferIndex].BufferPtr); + /* no validation function, assume its OK */ + ResultPtr->Result = 0; } else { - /* Call the Application's Validation function for the static buffer */ - Status = (RegRecPtr->ValidationFuncPtr)(RegRecPtr->Buffers[0].BufferPtr); + /* Save the result of the Validation function for the Table Services Task */ + ResultPtr->Result = (RegRecPtr->ValidationFuncPtr)(BuffPtr->BufferPtr); } - if (Status == CFE_SUCCESS) + /* Get the app name for logging */ + CFE_ES_GetAppName(AppName, CFE_TBL_TxnAppId(&Txn), sizeof(AppName)); + + /* Allow buffer to be activated after passing validation */ + if (ResultPtr->Result == 0) { + BuffPtr->Validated = true; CFE_EVS_SendEventWithAppID(CFE_TBL_VALIDATION_INF_EID, CFE_EVS_EventType_INFORMATION, - CFE_TBL_Global.TableTaskAppId, "%s validation successful for Active '%s'", - AppName, RegRecPtr->Name); + CFE_TBL_Global.TableTaskAppId, "%s validation successful for %s '%s'", + AppName, LogTagStr, RegRecPtr->Name); } else { CFE_EVS_SendEventWithAppID(CFE_TBL_VALIDATION_ERR_EID, CFE_EVS_EventType_ERROR, CFE_TBL_Global.TableTaskAppId, - "%s validation failed for Active '%s', Status=0x%08X", AppName, - RegRecPtr->Name, (unsigned int)Status); + "%s validation failed for %s '%s', Status=0x%08X", AppName, RegRecPtr->Name, + LogTagStr, (unsigned int)Status); - if (Status > CFE_SUCCESS) + if (ResultPtr->Result > 0) { CFE_ES_WriteToSysLog("%s: App(%lu) Validation func return code invalid (Stat=0x%08X) for '%s'\n", __func__, CFE_RESOURCEID_TO_ULONG(CFE_TBL_Global.TableTaskAppId), - (unsigned int)Status, RegRecPtr->Name); + (unsigned int)ResultPtr->Result, RegRecPtr->Name); } } - /* Save the result of the Validation function for the Table Services Task */ - CFE_TBL_Global.ValidationResults[RegRecPtr->ValidateActiveIndex].Result = Status; - - /* Once validation is complete, reset the flags */ - CFE_TBL_Global.ValidationResults[RegRecPtr->ValidateActiveIndex].State = CFE_TBL_VALIDATION_PERFORMED; - RegRecPtr->ValidateActiveIndex = CFE_TBL_NO_VALIDATION_PENDING; + /* Once validation is complete, set flags to indicate response is ready */ + ResultPtr->State = CFE_TBL_VALIDATION_PERFORMED; /* Since the validation was successfully performed (although maybe not a successful result) */ /* return a success status */ @@ -973,8 +935,8 @@ CFE_Status_t CFE_TBL_Validate(CFE_TBL_Handle_t TblHandle) } else { - CFE_ES_WriteToSysLog("%s: App(%lu) does not have access to Tbl Handle=%d\n", __func__, - CFE_RESOURCEID_TO_ULONG(ThisAppId), (int)TblHandle); + CFE_ES_WriteToSysLog("%s: App(%lu) does not have access to Tbl Handle=%lu\n", __func__, + CFE_TBL_TxnAppIdAsULong(&Txn), CFE_TBL_TxnHandleAsULong(&Txn)); } return Status; diff --git a/modules/tbl/fsw/src/cfe_tbl_internal.c b/modules/tbl/fsw/src/cfe_tbl_internal.c index 4ab8ef482..76053e463 100644 --- a/modules/tbl/fsw/src/cfe_tbl_internal.c +++ b/modules/tbl/fsw/src/cfe_tbl_internal.c @@ -89,12 +89,6 @@ int32 CFE_TBL_EarlyInit(void) CFE_TBL_HandleLinkInit(&CFE_TBL_Global.Handles[i].Link); } - /* Initialize the Table Validation Results Records nonzero values */ - for (i = 0; i < CFE_PLATFORM_TBL_MAX_NUM_VALIDATIONS; i++) - { - CFE_TBL_Global.ValidationResults[i].State = CFE_TBL_VALIDATION_FREE; - } - /* Initialize the Dump-Only Table Dump Control Blocks nonzero values */ for (i = 0; i < CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS; i++) { @@ -223,13 +217,13 @@ void CFE_TBL_InitRegistryRecord(CFE_TBL_RegistryRec_t *RegRecPtr) { memset(RegRecPtr, 0, sizeof(*RegRecPtr)); - RegRecPtr->OwnerAppId = CFE_TBL_NOT_OWNED; - RegRecPtr->NotificationMsgId = CFE_SB_INVALID_MSG_ID; - RegRecPtr->LoadInProgress = CFE_TBL_NO_LOAD_IN_PROGRESS; - RegRecPtr->ValidateActiveIndex = CFE_TBL_NO_VALIDATION_PENDING; - RegRecPtr->ValidateInactiveIndex = CFE_TBL_NO_VALIDATION_PENDING; - RegRecPtr->CDSHandle = CFE_ES_CDS_BAD_HANDLE; - RegRecPtr->DumpControlIndex = CFE_TBL_NO_DUMP_PENDING; + RegRecPtr->OwnerAppId = CFE_TBL_NOT_OWNED; + RegRecPtr->NotificationMsgId = CFE_SB_INVALID_MSG_ID; + RegRecPtr->LoadInProgress = CFE_TBL_NO_LOAD_IN_PROGRESS; + RegRecPtr->ValidateActiveId = CFE_TBL_NO_VALIDATION_PENDING; + RegRecPtr->ValidateInactiveId = CFE_TBL_NO_VALIDATION_PENDING; + RegRecPtr->CDSHandle = CFE_ES_CDS_BAD_HANDLE; + RegRecPtr->DumpControlIndex = CFE_TBL_NO_DUMP_PENDING; CFE_TBL_HandleLinkInit(&RegRecPtr->AccessList); } @@ -322,6 +316,115 @@ int32 CFE_TBL_UnlockRegistry(void) return Status; } +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +CFE_TBL_LoadBuff_t *CFE_TBL_GetActiveBuffer(CFE_TBL_RegistryRec_t *RegRecPtr) +{ + int32 BufferIndex; + + /* + * This should be simpler because ActiveBufferIndex always refers to + * the active buffer, and applies to both single and double buffered + * (That is, it is always 0 on a single-buffered table). + * + * However, legacy code always checked the double buffer flag before + * using ActiveBufferIndex so this will to (at least for now) + */ + if (RegRecPtr->DoubleBuffered) + { + BufferIndex = RegRecPtr->ActiveBufferIndex; + } + else + { + BufferIndex = 0; + } + + return &RegRecPtr->Buffers[BufferIndex]; +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +int32 CFE_TBL_GetNextLocalBufferId(CFE_TBL_RegistryRec_t *RegRecPtr) +{ + /* This implements a flip-flop buffer: if active is 1, return 0 and vice versa */ + return (1 - (RegRecPtr->ActiveBufferIndex & 1)); +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +CFE_TBL_LoadBuff_t *CFE_TBL_GetInactiveBuffer(CFE_TBL_RegistryRec_t *RegRecPtr) +{ + int32 BufferIndex; + CFE_TBL_LoadBuff_t *Result; + + if (RegRecPtr->DoubleBuffered) + { + /* Determine the index of the Inactive Buffer Pointer */ + BufferIndex = CFE_TBL_GetNextLocalBufferId(RegRecPtr); + + /* then return the pointer to it */ + Result = &RegRecPtr->Buffers[BufferIndex]; + } + else if (!RegRecPtr->UserDefAddr && RegRecPtr->LoadInProgress != CFE_TBL_NO_LOAD_IN_PROGRESS) + { + /* + * The only time a single buffered table has an inactive buffer is when its loading, and + * this always refers to a shared load buffer + */ + Result = &CFE_TBL_Global.LoadBuffs[RegRecPtr->LoadInProgress]; + } + else + { + /* Tables with a user-defined address never have an inactive buffer */ + Result = NULL; + } + + return Result; +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +CFE_TBL_LoadBuff_t *CFE_TBL_GetSelectedBuffer(CFE_TBL_RegistryRec_t * RegRecPtr, + CFE_TBL_BufferSelect_Enum_t BufferSelect) +{ + CFE_TBL_LoadBuff_t *Result; + + switch (BufferSelect) + { + case CFE_TBL_BufferSelect_INACTIVE: + Result = CFE_TBL_GetInactiveBuffer(RegRecPtr); + break; + case CFE_TBL_BufferSelect_ACTIVE: + Result = CFE_TBL_GetActiveBuffer(RegRecPtr); + break; + default: + CFE_EVS_SendEvent(CFE_TBL_ILLEGAL_BUFF_PARAM_ERR_EID, CFE_EVS_EventType_ERROR, + "Cmd for Table '%s' had illegal buffer parameter (0x%08X)", RegRecPtr->Name, + (unsigned int)BufferSelect); + + Result = NULL; + break; + } + + return Result; +} + /*---------------------------------------------------------------- * * Application-scope internal function @@ -1546,3 +1649,42 @@ void CFE_TBL_CountAccessDescHelper(CFE_TBL_AccessDescriptor_t *AccDescPtr, void ++(*Count); } + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +CFE_TBL_ValidationResult_t *CFE_TBL_CheckValidationRequest(CFE_TBL_ValidationResultId_t *ValIdPtr) +{ + CFE_TBL_ValidationResult_t * ResultPtr; + CFE_TBL_ValidationResultId_t ValId; + + ValId = *ValIdPtr; + + /* + * always clear the flag, regardless of "IsMatch" above. If it was not a match, + * that means the ID was stale, and it will never be a match (ie. it was aborted somehow) + * + * However, because this also acts as a flag, only write to the global if it was set to a value, + * do not unconditionally write undefined value here. + */ + if (CFE_RESOURCEID_TEST_DEFINED(ValId)) + { + *ValIdPtr = CFE_TBL_VALRESULTID_UNDEFINED; + + ResultPtr = CFE_TBL_LocateValidationResultByID(ValId); + } + else + { + ResultPtr = NULL; + } + + if (!CFE_TBL_ValidationResultIsMatch(ResultPtr, ValId)) + { + ResultPtr = NULL; + } + + return ResultPtr; +} diff --git a/modules/tbl/fsw/src/cfe_tbl_internal.h b/modules/tbl/fsw/src/cfe_tbl_internal.h index 76bc5bc3f..41ed69eb0 100644 --- a/modules/tbl/fsw/src/cfe_tbl_internal.h +++ b/modules/tbl/fsw/src/cfe_tbl_internal.h @@ -57,7 +57,7 @@ * \param AccDescPtr Pointer to the current access descriptor * \param Arg Opaque argument from caller (passed through) */ -typedef void (* const CFE_TBL_AccessDescFunc_t)(CFE_TBL_AccessDescriptor_t *AccDescPtr, void *Arg); +typedef void (*const CFE_TBL_AccessDescFunc_t)(CFE_TBL_AccessDescriptor_t *AccDescPtr, void *Arg); /***************************** Function Prototypes **********************************/ @@ -647,6 +647,14 @@ void CFE_TBL_HandleListRemoveLink(CFE_TBL_RegistryRec_t *RegRecPtr, CFE_TBL_Acce */ void CFE_TBL_HandleListInsertLink(CFE_TBL_RegistryRec_t *RegRecPtr, CFE_TBL_AccessDescriptor_t *AccessDescPtr); +int32 CFE_TBL_GetNextLocalBufferId(CFE_TBL_RegistryRec_t *RegRecPtr); +CFE_TBL_LoadBuff_t *CFE_TBL_GetActiveBuffer(CFE_TBL_RegistryRec_t *RegRecPtr); +CFE_TBL_LoadBuff_t *CFE_TBL_GetInactiveBuffer(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_ValidationResult_t *CFE_TBL_CheckValidationRequest(CFE_TBL_ValidationResultId_t *ValIdPtr); + /* ** Globals specific to the TBL module */ diff --git a/modules/tbl/fsw/src/cfe_tbl_resource.c b/modules/tbl/fsw/src/cfe_tbl_resource.c index 9f0113f73..06e90b987 100644 --- a/modules/tbl/fsw/src/cfe_tbl_resource.c +++ b/modules/tbl/fsw/src/cfe_tbl_resource.c @@ -32,6 +32,7 @@ ** Includes */ #include "cfe_tbl_module_all.h" +#include "cfe_core_resourceid_basevalues.h" /*---------------------------------------------------------------- * @@ -51,6 +52,18 @@ CFE_Status_t CFE_TBL_Handle_ToIndex(CFE_TBL_Handle_t TblHandle, uint32 *Idx) return CFE_SUCCESS; } +/*---------------------------------------------------------------- + * + * Implemented per public API + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +CFE_Status_t CFE_TBL_ValidationResultId_ToIndex(CFE_TBL_ValidationResultId_t ValResultId, uint32 *Idx) +{ + return CFE_ResourceId_ToIndex(CFE_RESOURCEID_UNWRAP(ValResultId), CFE_TBL_VALRESULTID_BASE, + CFE_PLATFORM_TBL_MAX_NUM_VALIDATIONS, Idx); +} + /*---------------------------------------------------------------- * * Application-scope internal function @@ -138,3 +151,57 @@ CFE_TBL_Handle_t CFE_TBL_AccessDescriptorGetHandle(const CFE_TBL_AccessDescripto /* The pointer should be to an entry within the Handles array */ return (AccessDescPtr - CFE_TBL_Global.Handles); } + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +CFE_TBL_ValidationResult_t *CFE_TBL_LocateValidationResultByID(CFE_TBL_ValidationResultId_t ValResultId) +{ + CFE_TBL_ValidationResult_t *ResultPtr; + uint32 Idx; + + if (CFE_TBL_ValidationResultId_ToIndex(ValResultId, &Idx) == CFE_SUCCESS) + { + ResultPtr = &CFE_TBL_Global.ValidationResults[Idx]; + } + else + { + ResultPtr = NULL; + } + + return ResultPtr; +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +bool CFE_TBL_CheckValidationResultSlotUsed(CFE_ResourceId_t CheckId) +{ + CFE_TBL_ValidationResult_t *BuffPtr; + + /* + * Note - The pointer here should never be NULL because the ID should always be + * within the expected range, but if it ever is NULL, this should return true + * such that the caller will _not_ attempt to use the record. + */ + BuffPtr = CFE_TBL_LocateValidationResultByID(CFE_TBL_VALRESULTID_C(CheckId)); + return (BuffPtr == NULL || CFE_TBL_ValidationResultIsUsed(BuffPtr)); +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +CFE_ResourceId_t CFE_TBL_GetNextValResultBlock(void) +{ + return CFE_ResourceId_FindNext(CFE_TBL_Global.LastValidationResultId, CFE_PLATFORM_TBL_MAX_NUM_VALIDATIONS, + CFE_TBL_CheckValidationResultSlotUsed); +} diff --git a/modules/tbl/fsw/src/cfe_tbl_resource.h b/modules/tbl/fsw/src/cfe_tbl_resource.h index 2195665ec..5eba6922b 100644 --- a/modules/tbl/fsw/src/cfe_tbl_resource.h +++ b/modules/tbl/fsw/src/cfe_tbl_resource.h @@ -24,6 +24,37 @@ * * A CFE TBL Resource ID is a common way to identify CFE-managed resources such * as registry entries, buffers, state records, and other entities. + * + * ABOUT RESOURCE TABLE ACCESSORS + * ============================== + * + * These accessors facilitate consistent lookup/matching/allocation/deallocation patterns + * across all TBL resources. The following types of resources can be managed in this + * fashion: + * + * - Access Descriptors (Table Handles, external identifiers) + * - Registry Records (Table registry, internal identifiers) + * - Load Buffers (both shared and table-specific) + * - Validation Results + * - Dump State + * - CDS registries + * + * A full set of accessors contains the following basic methods: + * + * | **Method** | **Description** | + * |:------------|:------------------------------------------------------| + * | LocateByID | Returns a pointer to the entry associated with an ID | + * | ToIndex | Converts an entry ID to a 0-based array index | + * | IsUsed | Checks if a given entry is currently in use | + * | SetUsed | Sets an entry as being in use / not available | + * | SetFree | Sets an entry as being available / not in use | + * | GetId | Gets the resource ID associated with an entry pointer | + * | IsMatch | Checks if an entry pointer is a match to the given ID | + * | GetNext | Returns the next/pending ID suitable for a new record | + * + * This file should implement each method for each supported resource type that + * implements these access patterns. + * */ #ifndef CFE_TBL_RESOURCE_H @@ -36,6 +67,205 @@ #include "cfe_core_resourceid_basevalues.h" #include "cfe_tbl_task.h" +/* + * --------------------------------------------------------------------------------------- + * + * ~~~ VALIDATION RESULT TABLE ACCESSORS ~~~ + * + * These operate on CFE_TBL_ValidationResult_t* and CFE_TBL_ValidationResultId_t types + * + * --------------------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Locate the validation result table entry correlating with a given registry ID. + * + * This only returns a pointer to the table entry where the record + * should reside, but does _not_ actually check/validate the entry. + * + * If the passed-in ID parameter is not within the acceptable range of ID + * values for applications, such that it could never be valid under + * any circumstances, then NULL is returned. Otherwise, a pointer to the + * corresponding table entry is returned, indicating the location where + * that ID should reside, if it is currently in use. + * + * @note This only returns where the ID should reside, not that it actually + * resides there. If looking up an existing ID, then caller must additionally + * confirm that the returned record is a match to the expected ID before using + * or modifying the data within the returned record pointer. + * + * The CFE_TBL_ValidationResultIsMatch() function can be used to check/confirm + * if the returned table entry is a positive match for the given ID. + * + * @sa CFE_TBL_ValidationResultIsMatch() + * + * @param[in] ValResultId the registry ID to locate + * @return pointer to Validation Result Table entry for the given registry ID, or NULL if out of range + */ +CFE_TBL_ValidationResult_t *CFE_TBL_LocateValidationResultByID(CFE_TBL_ValidationResultId_t ValResultId); + +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Get the array index correlating with a Validation Result ID + * + * Calculates the array position/index of the global array entry for + * the given result ID. + * + * @param[in] BlockID the ID/handle of the validation result block to retrieve + * @param[out] Idx Output buffer to store the index + * @returns #CFE_SUCCESS if conversion successful. @copydoc CFE_SUCCESS + * #CFE_ES_ERR_RESOURCEID_NOT_VALID if ID is outside valid range + */ +CFE_Status_t CFE_TBL_ValidationResultId_ToIndex(CFE_TBL_ValidationResultId_t ValResultId, uint32 *Idx); + +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Check if a validation result table entry is in use or free/empty + * + * This routine checks if the table entry is in use or if it is free + * + * As this dereferences fields within the record, global data must be + * locked prior to invoking this function. + * + * @note This internal helper function must only be used on result pointers + * that are known to refer to an actual table location (i.e. non-null). + * + * @param[in] BuffPtr pointer to validation result table entry + * @returns true if the entry is in use/configured, or false if it is free/empty + */ +static inline bool CFE_TBL_ValidationResultIsUsed(const CFE_TBL_ValidationResult_t *BuffPtr) +{ + return (CFE_RESOURCEID_TEST_DEFINED(BuffPtr->ValId)); +} + +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Marks a validation result table entry as in use (not avaliable) + * + * This sets the internal field(s) within this entry, and marks + * it as being associated with the given validation result ID. + * + * @note This internal helper function must only be used on record pointers + * that are known to refer to an actual table location (i.e. non-null). + * + * @param[in] BuffPtr pointer to validation result table entry + * @param[in] PendingId the ID of this entry that will be set + */ +static inline void CFE_TBL_ValidationResultSetUsed(CFE_TBL_ValidationResult_t *BuffPtr, CFE_ResourceId_t PendingId) +{ + BuffPtr->ValId = CFE_TBL_VALRESULTID_C(PendingId); +} + +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Marks a validation result table entry as available (not in use) + * + * This clears the internal field(s) within this entry, and marks + * it as not being associated with any validation result ID. + * + * @note This internal helper function must only be used on record pointers + * that are known to refer to an actual table location (i.e. non-null). + * + * @param[in] BuffPtr pointer to validation result table entry + */ +static inline void CFE_TBL_ValidationResultSetFree(CFE_TBL_ValidationResult_t *BuffPtr) +{ + BuffPtr->State = CFE_TBL_VALIDATION_FREE; /* for backward compatibility; not part of "IsUsed" check anymore */ + BuffPtr->ValId = CFE_TBL_VALRESULTID_UNDEFINED; +} + +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Get the ID value from a validation result table entry + * + * This routine converts the table entry pointer to its corresponding ID. + * + * @note This internal helper function must only be used on record pointers + * that are known to refer to an actual table location (i.e. non-null). + * + * @param[in] BuffPtr pointer to table entry + * @returns ID of entry + */ +static inline CFE_TBL_ValidationResultId_t CFE_TBL_ValidationResultGetId(const CFE_TBL_ValidationResult_t *BuffPtr) +{ + return BuffPtr->ValId; +} + +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Check if a validation result entry is a match for the given ID + * + * This routine confirms that the previously-located result record is valid + * and matches the expected validation result ID. + * + * As this dereferences fields within the record, global data must be + * locked prior to invoking this function. + * + * This function may be used in conjunction with CFE_TBL_LocateValidationResultByID() + * to confirm that the located record is a positive match to the expected ID. + * As such, the record pointer is also permitted to be NULL, to alleviate the + * need for the caller to handle this possibility explicitly. + * + * Once a record pointer has been successfully validated using this routine, + * it may be safely passed to all other internal functions. + * + * @sa CFE_TBL_LocateValidationResultByID + * + * @param[in] BuffPtr pointer to validation result table entry, or NULL + * @param[in] ValId expected validation result ID + * @returns true if the entry matches the given ID + */ +static inline bool CFE_TBL_ValidationResultIsMatch(const CFE_TBL_ValidationResult_t *BuffPtr, + CFE_TBL_ValidationResultId_t ValId) +{ + return (BuffPtr != NULL && CFE_RESOURCEID_TEST_EQUAL(BuffPtr->ValId, ValId)); +} + +/** + * @brief Determine the next ID to use for validation results + * + * Obtains an ID value that is usable for a new validation result. If no validation + * result entries are available, then UNDEFINED is returned. + * + * @returns ID to use for next result, or UNDEFINED if no slots available + */ +CFE_ResourceId_t CFE_TBL_GetNextValResultBlock(void); + +/** + * Test if a slot corresponding to a pending ID is used + * + * This is an internal helper function for CFE_ResourceId_FindNext(), and not + * typically called directly. It is prototyped here for unit testing. + * + * @returns True if used, False if available + */ +bool CFE_TBL_CheckValidationResultSlotUsed(CFE_ResourceId_t CheckId); + +/* + * --------------------------------------------------------------------------------------- + * + * ~~~ REGISTRY RECORD TABLE ACCESSORS ~~~ + * + * These operate on CFE_TBL_RegistryRec_t* and CFE_TBL_RegId_t types + * + * --------------------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Get the array index correlating with a Registry Record ID + * + * Calculates the array position/index of the global array entry for + * the given registry ID. + * + * @param[in] RegId the ID/handle of the registry record to retrieve + * @param[out] Idx Output buffer to store the index + * @returns #CFE_SUCCESS if conversion successful. @copydoc CFE_SUCCESS + * #CFE_ES_ERR_RESOURCEID_NOT_VALID if ID is outside valid range + */ +CFE_Status_t CFE_TBL_RegId_ToIndex(CFE_TBL_RegId_t RegId, uint32 *Idx); + /*---------------------------------------------------------------------------------------*/ /** * @brief Locate the registry table entry correlating with a given registry ID. @@ -125,6 +355,20 @@ static inline bool CFE_TBL_RegistryRecordIsMatch(const CFE_TBL_RegistryRec_t *Re return (RegRecPtr != NULL); } +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Get the ID value from a registry record + * + * This routine converts the registry record pointer to its corresponding ID. + * + * @note This internal helper function must only be used on record pointers + * that are known to refer to an actual table location (i.e. non-null). + * + * @param[in] RegRecPtr pointer to table entry + * @returns ID of entry + */ +CFE_TBL_RegId_t CFE_TBL_RegistryRecordGetID(const CFE_TBL_RegistryRec_t *RegRecPtr); + /*---------------------------------------------------------------------------------------*/ /** * @brief Obtain the name associated with the Application record @@ -142,6 +386,30 @@ static inline const char *CFE_TBL_RegistryRecordGetName(const CFE_TBL_RegistryRe return RegRecPtr->Name; } +/* + * --------------------------------------------------------------------------------------- + * + * ~~~ ACCESS DESCRIPTOR TABLE ACCESSORS ~~~ + * + * These operate on CFE_TBL_AccessDescriptor_t* and CFE_TBL_Handle_t types + * + * --------------------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Get the array index correlating with a table handle/access ID + * + * Calculates the array position/index of the global array entry for + * the given handle. + * + * @param[in] TblHandle the ID/handle of the access descriptor to retrieve + * @param[out] Idx Output buffer to store the index + * @returns #CFE_SUCCESS if conversion successful. @copydoc CFE_SUCCESS + * #CFE_ES_ERR_RESOURCEID_NOT_VALID if ID is outside valid range + */ +CFE_Status_t CFE_TBL_Handle_ToIndex(CFE_TBL_Handle_t TblHandle, uint32 *Idx); + /*---------------------------------------------------------------------------------------*/ /** * @brief Get the Handle ID from an an access descriptor pointer diff --git a/modules/tbl/fsw/src/cfe_tbl_task.h b/modules/tbl/fsw/src/cfe_tbl_task.h index d1e369b7c..5176d0f3f 100644 --- a/modules/tbl/fsw/src/cfe_tbl_task.h +++ b/modules/tbl/fsw/src/cfe_tbl_task.h @@ -66,7 +66,7 @@ ** This macro is used to indicate no Validation is Pending by assigning it to ** #CFE_TBL_RegistryRec_t::ValidateActiveIndex or #CFE_TBL_RegistryRec_t::ValidateInactiveIndex */ -#define CFE_TBL_NO_VALIDATION_PENDING (-1) +#define CFE_TBL_NO_VALIDATION_PENDING CFE_TBL_VALRESULTID_UNDEFINED /** \brief Value indicating when no Dump is Pending on a Dump-Only Table */ /** @@ -77,6 +77,16 @@ /************************ Internal Structure Definitions *****************************/ +/** + * @brief A type for Validation Result Buffer IDs + * + * This is the type that is used for any API accepting or returning a Validation Result ID + */ +typedef CFE_RESOURCEID_BASE_TYPE CFE_TBL_ValidationResultId_t; + +#define CFE_TBL_VALRESULTID_C(val) ((CFE_TBL_ValidationResultId_t)CFE_RESOURCEID_WRAP(val)) +#define CFE_TBL_VALRESULTID_UNDEFINED CFE_TBL_VALRESULTID_C(CFE_RESOURCEID_UNDEFINED) + /*******************************************************************************/ /** \brief Identifies the current state of a validation sequence. */ @@ -105,6 +115,8 @@ typedef enum */ typedef struct { + CFE_TBL_ValidationResultId_t ValId; + CFE_TBL_ValidationState_t State; /**< \brief Current state of this block of data */ int32 Result; /**< \brief Result returned by Application's Validation function */ uint32 CrcOfTable; /**< \brief Data Integrity Value computed on Table Buffer */ @@ -189,21 +201,23 @@ typedef struct CFE_TBL_CallbackFuncPtr_t ValidationFuncPtr; /**< \brief Ptr to Owner App's function that validates tbl contents */ CFE_TIME_SysTime_t TimeOfLastUpdate; /**< \brief Time when Table was last updated */ CFE_TBL_HandleLink_t AccessList; /**< \brief Linked List of associated access descriptors */ - int32 LoadInProgress; /**< \brief Flag identifies inactive buffer and whether load in progress */ - int32 ValidateActiveIndex; /**< \brief Index to Validation Request on Active Table Result data */ - int32 ValidateInactiveIndex; /**< \brief Index to Validation Request on Inactive Table Result data */ - int32 DumpControlIndex; /**< \brief Index to Dump Control Block */ - CFE_ES_CDSHandle_t CDSHandle; /**< \brief Handle to Critical Data Store for Critical Tables */ - CFE_MSG_FcnCode_t NotificationCC; /**< \brief Command Code of an associated management notification message */ - bool CriticalTable; /**< \brief Flag indicating whether table is a Critical Table */ - bool TableLoadedOnce; /**< \brief Flag indicating whether table has been loaded once or not */ - bool LoadPending; /**< \brief Flag indicating an inactive buffer is ready to be copied */ - bool DumpOnly; /**< \brief Flag indicating Table is NOT to be loaded */ - bool DoubleBuffered; /**< \brief Flag indicating Table has a dedicated inactive buffer */ - bool UserDefAddr; /**< \brief Flag indicating Table address was defined by Owner Application */ - bool NotifyByMsg; /**< \brief Flag indicating Table Services should notify owning App via message - when table requires management */ - uint8 ActiveBufferIndex; /**< \brief Index identifying which buffer is the active buffer */ + int32 LoadInProgress; /**< \brief Flag identifies inactive buffer and whether load in progress */ + CFE_TBL_ValidationResultId_t + ValidateActiveId; /**< \brief Index to Validation Request on Active Table Result data */ + CFE_TBL_ValidationResultId_t + ValidateInactiveId; /**< \brief Index to Validation Request on Inactive Table Result data */ + int32 DumpControlIndex; /**< \brief Index to Dump Control Block */ + CFE_ES_CDSHandle_t CDSHandle; /**< \brief Handle to Critical Data Store for Critical Tables */ + CFE_MSG_FcnCode_t NotificationCC; /**< \brief Command Code of an associated management notification message */ + bool CriticalTable; /**< \brief Flag indicating whether table is a Critical Table */ + bool TableLoadedOnce; /**< \brief Flag indicating whether table has been loaded once or not */ + bool LoadPending; /**< \brief Flag indicating an inactive buffer is ready to be copied */ + bool DumpOnly; /**< \brief Flag indicating Table is NOT to be loaded */ + bool DoubleBuffered; /**< \brief Flag indicating Table has a dedicated inactive buffer */ + bool UserDefAddr; /**< \brief Flag indicating Table address was defined by Owner Application */ + bool NotifyByMsg; /**< \brief Flag indicating Table Services should notify owning App via message + when table requires management */ + uint8 ActiveBufferIndex; /**< \brief Index identifying which buffer is the active buffer */ char Name[CFE_TBL_MAX_FULL_NAME_LEN]; /**< \brief Processor specific table name */ char LastFileLoaded[OS_MAX_PATH_LEN]; /**< \brief Filename of last file loaded into table */ } CFE_TBL_RegistryRec_t; @@ -349,6 +363,9 @@ typedef struct * Registry dump state info (background job) */ CFE_TBL_RegDumpStateInfo_t RegDumpState; + + CFE_ResourceId_t LastValidationResultId; + } CFE_TBL_Global_t; /*************************************************************************/ diff --git a/modules/tbl/fsw/src/cfe_tbl_task_cmds.c b/modules/tbl/fsw/src/cfe_tbl_task_cmds.c index afb4f5536..615676308 100644 --- a/modules/tbl/fsw/src/cfe_tbl_task_cmds.c +++ b/modules/tbl/fsw/src/cfe_tbl_task_cmds.c @@ -179,16 +179,21 @@ void CFE_TBL_GetHkData(void) /* Locate a completed, but unreported, validation request */ i = 0; - while ((i < CFE_PLATFORM_TBL_MAX_NUM_VALIDATIONS) && (ValPtr == NULL)) + while (true) { - if (CFE_TBL_Global.ValidationResults[i].State == CFE_TBL_VALIDATION_PERFORMED) + if (i >= CFE_PLATFORM_TBL_MAX_NUM_VALIDATIONS) { - ValPtr = &CFE_TBL_Global.ValidationResults[i]; + ValPtr = NULL; + break; } - else + + ValPtr = &CFE_TBL_Global.ValidationResults[i]; + if (CFE_TBL_ValidationResultIsUsed(ValPtr) && ValPtr->State == CFE_TBL_VALIDATION_PERFORMED) { - i++; + break; } + + ++i; } if (ValPtr != NULL) @@ -216,7 +221,8 @@ void CFE_TBL_GetHkData(void) ValPtr->CrcOfTable = 0; ValPtr->TableName[0] = '\0'; ValPtr->ActiveBuffer = false; - ValPtr->State = CFE_TBL_VALIDATION_FREE; + + CFE_TBL_ValidationResultSetFree(ValPtr); } CFE_TBL_Global.HkPacket.Payload.ValidationCounter = CFE_TBL_Global.ValidationCounter; @@ -798,82 +804,60 @@ CFE_TBL_CmdProcRet_t CFE_TBL_DumpToFile(const char *DumpFilename, const char *Ta int32 CFE_TBL_ValidateCmd(const CFE_TBL_ValidateCmd_t *data) { CFE_TBL_CmdProcRet_t ReturnCode = CFE_TBL_INC_ERR_CTR; /* Assume failure */ - int16 RegIndex; + CFE_TBL_TxnState_t Txn; + CFE_Status_t Status; const CFE_TBL_ValidateCmd_Payload_t *CmdPtr = &data->Payload; CFE_TBL_RegistryRec_t * RegRecPtr; - void * ValidationDataPtr = NULL; + CFE_TBL_LoadBuff_t * SelectedBufferPtr; char TableName[CFE_TBL_MAX_FULL_NAME_LEN]; uint32 CrcOfTable; - int32 ValIndex; + CFE_ResourceId_t PendingValId; + CFE_TBL_ValidationResult_t * ValResultPtr; + + SelectedBufferPtr = NULL; /* Make sure all strings are null terminated before attempting to process them */ CFE_SB_MessageStringGet(TableName, (char *)CmdPtr->TableName, NULL, sizeof(TableName), sizeof(CmdPtr->TableName)); /* Before doing anything, lets make sure the table that is to be dumped exists */ - RegIndex = CFE_TBL_FindTableInRegistry(TableName); - - if (RegIndex != CFE_TBL_NOT_FOUND) + Status = CFE_TBL_TxnStartFromName(&Txn, TableName, CFE_TBL_TxnContext_UNDEFINED); + if (Status == CFE_SUCCESS) { /* Obtain a pointer to registry information about specified table */ - RegRecPtr = &CFE_TBL_Global.Registry[RegIndex]; + RegRecPtr = CFE_TBL_TxnRegRec(&Txn); + CFE_TBL_TxnFinish(&Txn); /* Determine what data is to be validated */ - if (CmdPtr->ActiveTableFlag == CFE_TBL_BufferSelect_ACTIVE) - { - ValidationDataPtr = RegRecPtr->Buffers[RegRecPtr->ActiveBufferIndex].BufferPtr; - } - else if (CmdPtr->ActiveTableFlag == CFE_TBL_BufferSelect_INACTIVE) /* Validating Inactive Buffer */ + SelectedBufferPtr = CFE_TBL_GetSelectedBuffer(RegRecPtr, CmdPtr->ActiveTableFlag); + + if (SelectedBufferPtr == NULL) { - /* If this is a double buffered table, locating the inactive buffer is trivial */ - if (RegRecPtr->DoubleBuffered) - { - ValidationDataPtr = RegRecPtr->Buffers[(1U - RegRecPtr->ActiveBufferIndex)].BufferPtr; - } - else - { - /* For single buffered tables, the index to the inactive buffer is kept in 'LoadInProgress' */ - if (RegRecPtr->LoadInProgress != CFE_TBL_NO_LOAD_IN_PROGRESS) - { - ValidationDataPtr = CFE_TBL_Global.LoadBuffs[RegRecPtr->LoadInProgress].BufferPtr; - } - else - { - CFE_EVS_SendEvent(CFE_TBL_NO_INACTIVE_BUFFER_ERR_EID, CFE_EVS_EventType_ERROR, - "No Inactive Buffer for Table '%s' present", TableName); - } - } + CFE_EVS_SendEvent(CFE_TBL_NO_INACTIVE_BUFFER_ERR_EID, CFE_EVS_EventType_ERROR, + "No Buffer for Table '%s' present", TableName); } else { - CFE_EVS_SendEvent(CFE_TBL_ILLEGAL_BUFF_PARAM_ERR_EID, CFE_EVS_EventType_ERROR, - "Cmd for Table '%s' had illegal buffer parameter (0x%08X)", TableName, - (unsigned int)CmdPtr->ActiveTableFlag); - } + /* If we have located the data to be validated, then proceed with notifying the application, if */ + /* necessary, and computing the CRC value for the block of memory */ - /* If we have located the data to be validated, then proceed with notifying the application, if */ - /* necessary, and computing the CRC value for the block of memory */ - if (ValidationDataPtr != NULL) - { /* Find a free Validation Response Block */ - ValIndex = 0; - while ((ValIndex < CFE_PLATFORM_TBL_MAX_NUM_VALIDATIONS) && - (CFE_TBL_Global.ValidationResults[ValIndex].State != CFE_TBL_VALIDATION_FREE)) - { - ValIndex++; - } - - if (ValIndex < CFE_PLATFORM_TBL_MAX_NUM_VALIDATIONS) + PendingValId = CFE_TBL_GetNextValResultBlock(); + ValResultPtr = CFE_TBL_LocateValidationResultByID(CFE_TBL_VALRESULTID_C(PendingValId)); + if (ValResultPtr != NULL) { /* Allocate this Validation Response Block */ - CFE_TBL_Global.ValidationResults[ValIndex].State = CFE_TBL_VALIDATION_PENDING; - CFE_TBL_Global.ValidationResults[ValIndex].Result = 0; - memcpy(CFE_TBL_Global.ValidationResults[ValIndex].TableName, TableName, CFE_TBL_MAX_FULL_NAME_LEN); + ValResultPtr->State = CFE_TBL_VALIDATION_PENDING; + ValResultPtr->Result = 0; + memcpy(ValResultPtr->TableName, TableName, CFE_TBL_MAX_FULL_NAME_LEN); /* Compute the CRC on the specified table buffer */ - CrcOfTable = CFE_ES_CalculateCRC(ValidationDataPtr, RegRecPtr->Size, 0, CFE_MISSION_ES_DEFAULT_CRC); + CrcOfTable = + CFE_ES_CalculateCRC(SelectedBufferPtr->BufferPtr, RegRecPtr->Size, 0, CFE_MISSION_ES_DEFAULT_CRC); + + ValResultPtr->CrcOfTable = CrcOfTable; + ValResultPtr->ActiveBuffer = (CmdPtr->ActiveTableFlag != 0); - CFE_TBL_Global.ValidationResults[ValIndex].CrcOfTable = CrcOfTable; - CFE_TBL_Global.ValidationResults[ValIndex].ActiveBuffer = (CmdPtr->ActiveTableFlag != 0); + CFE_TBL_ValidationResultSetUsed(ValResultPtr, PendingValId); /* If owner has a validation function, then notify the */ /* table owner that there is data to be validated */ @@ -881,11 +865,11 @@ int32 CFE_TBL_ValidateCmd(const CFE_TBL_ValidateCmd_t *data) { if (CmdPtr->ActiveTableFlag) { - RegRecPtr->ValidateActiveIndex = ValIndex; + RegRecPtr->ValidateActiveId = CFE_TBL_ValidationResultGetId(ValResultPtr); } else { - RegRecPtr->ValidateInactiveIndex = ValIndex; + RegRecPtr->ValidateInactiveId = CFE_TBL_ValidationResultGetId(ValResultPtr); } /* If application requested notification by message, then do so */ @@ -904,7 +888,7 @@ int32 CFE_TBL_ValidateCmd(const CFE_TBL_ValidateCmd_t *data) /* If there isn't a validation function pointer, then the process is complete */ /* By setting this value, we are letting the Housekeeping process recognize it */ /* as data to be sent to the ground in telemetry. */ - CFE_TBL_Global.ValidationResults[ValIndex].State = CFE_TBL_VALIDATION_PERFORMED; + ValResultPtr->State = CFE_TBL_VALIDATION_PERFORMED; CFE_EVS_SendEvent(CFE_TBL_ASSUMED_VALID_INF_EID, CFE_EVS_EventType_INFORMATION, "Tbl Services assumes '%s' is valid. No Validation Function has been registered", diff --git a/modules/tbl/fsw/src/cfe_tbl_transaction.c b/modules/tbl/fsw/src/cfe_tbl_transaction.c index 68dcc92c5..479ac1e27 100644 --- a/modules/tbl/fsw/src/cfe_tbl_transaction.c +++ b/modules/tbl/fsw/src/cfe_tbl_transaction.c @@ -284,8 +284,8 @@ CFE_Status_t CFE_TBL_TxnGetTableStatus(CFE_TBL_TxnState_t *Txn) { Status = CFE_TBL_INFO_UPDATE_PENDING; } - else if ((RegRecPtr->ValidateActiveIndex != CFE_TBL_NO_VALIDATION_PENDING) || - (RegRecPtr->ValidateInactiveIndex != CFE_TBL_NO_VALIDATION_PENDING)) + else if (CFE_RESOURCEID_TEST_DEFINED(RegRecPtr->ValidateActiveId) || + CFE_RESOURCEID_TEST_DEFINED(RegRecPtr->ValidateInactiveId)) { Status = CFE_TBL_INFO_VALIDATION_PENDING; } diff --git a/modules/tbl/fsw/src/cfe_tbl_transaction.h b/modules/tbl/fsw/src/cfe_tbl_transaction.h index da61d1fe4..0d39bdeb5 100644 --- a/modules/tbl/fsw/src/cfe_tbl_transaction.h +++ b/modules/tbl/fsw/src/cfe_tbl_transaction.h @@ -32,7 +32,7 @@ /* * Required header files... -*/ + */ #include "cfe_es_api_typedefs.h" #include "cfe_tbl_api_typedefs.h" #include "cfe_platform_cfg.h" @@ -122,6 +122,11 @@ static inline CFE_TBL_Handle_t CFE_TBL_TxnHandle(const CFE_TBL_TxnState_t *Txn) return Txn->Handle; } +static inline unsigned long CFE_TBL_TxnHandleAsULong(const CFE_TBL_TxnState_t *Txn) +{ + return (unsigned long)CFE_TBL_TxnHandle(Txn); +} + /** * Gets the access descriptor object */ @@ -138,6 +143,11 @@ static inline CFE_TBL_RegId_t CFE_TBL_TxnRegId(const CFE_TBL_TxnState_t *Txn) return Txn->RegId; } +static inline unsigned long CFE_TBL_TxnRegIdAsULong(const CFE_TBL_TxnState_t *Txn) +{ + return (unsigned long)CFE_TBL_TxnRegId(Txn); +} + /** * Gets the registry record object */ @@ -156,6 +166,11 @@ static inline CFE_ES_AppId_t CFE_TBL_TxnAppId(const CFE_TBL_TxnState_t *Txn) return Txn->AppId; } +static inline unsigned long CFE_TBL_TxnAppIdAsULong(const CFE_TBL_TxnState_t *Txn) +{ + return CFE_RESOURCEID_TO_ULONG(CFE_TBL_TxnAppId(Txn)); +} + /***************************** Function Prototypes **********************************/ /*---------------------------------------------------------------------------------------*/ diff --git a/modules/tbl/ut-coverage/tbl_UT.c b/modules/tbl/ut-coverage/tbl_UT.c index b1358578f..3affe155d 100644 --- a/modules/tbl/ut-coverage/tbl_UT.c +++ b/modules/tbl/ut-coverage/tbl_UT.c @@ -113,6 +113,52 @@ void UT_TBL_SetupHeader(CFE_TBL_File_Hdr_t *TblFileHeader, size_t Offset, size_t } } +/* Sets up the indicated validation request/result buffer as VALIDATION_PENDING */ +void UT_TBL_SetupPendingValidation(uint32 ArrayIndex, bool UseActive, CFE_TBL_RegistryRec_t *RegRecPtr, + CFE_TBL_ValidationResult_t **ValResultOut) +{ + CFE_TBL_ValidationResult_t *ValResultPtr; + CFE_ResourceId_t PendingId; + + ValResultPtr = &CFE_TBL_Global.ValidationResults[ArrayIndex]; + PendingId = CFE_ResourceId_FromInteger(CFE_TBL_VALRESULTID_BASE + ArrayIndex); + + memset(ValResultPtr, 0, sizeof(*ValResultPtr)); + + ValResultPtr->State = CFE_TBL_VALIDATION_PENDING; + + ValResultPtr->ValId = CFE_TBL_VALRESULTID_C(PendingId); + ValResultPtr->ActiveBuffer = UseActive; + + snprintf(ValResultPtr->TableName, sizeof(ValResultPtr->TableName), "ut_cfe_tbl.UT_Table%u", + (unsigned int)ArrayIndex + 1); + + if (RegRecPtr != NULL) + { + if (UseActive) + { + RegRecPtr->ValidateActiveId = ValResultPtr->ValId; + } + else + { + RegRecPtr->ValidateInactiveId = ValResultPtr->ValId; + } + } + + if (ValResultOut != NULL) + { + *ValResultOut = ValResultPtr; + } +} + +/* Resets the indicated validation request/result buffer to the free/unused state */ +void UT_TBL_ResetValidationState(uint32 ArrayIndex) +{ + CFE_TBL_ValidationResult_t *ValResultPtr; + ValResultPtr = &CFE_TBL_Global.ValidationResults[ArrayIndex]; + memset(ValResultPtr, 0, sizeof(*ValResultPtr)); +} + /* ** Functions */ @@ -128,6 +174,14 @@ void UtTest_Setup(void) UT_ADD_TEST(Test_CFE_TBL_InitData); UT_ADD_TEST(Test_CFE_TBL_SearchCmdHndlrTbl); + /* + * Shared resource access patterns + * (do this early because many other APIs depend on these working correctly) + */ + UT_ADD_TEST(Test_CFE_TBL_ResourceID_ValidationResult); + UT_ADD_TEST(Test_CFE_TBL_ResourceID_RegistryRecord); + UT_ADD_TEST(Test_CFE_TBL_ResourceID_AccessDescriptor); + /* cfe_tbl_task_cmds.c functions */ /* This should be done first (it initializes working data structures) */ UT_ADD_TEST(Test_CFE_TBL_DeleteCDSCmd); @@ -209,11 +263,7 @@ void UT_ResetTableRegistry(void) /* Initialize the table validation results records */ for (i = 0; i < CFE_PLATFORM_TBL_MAX_NUM_VALIDATIONS; i++) { - CFE_TBL_Global.ValidationResults[i].State = CFE_TBL_VALIDATION_FREE; - CFE_TBL_Global.ValidationResults[i].CrcOfTable = 0; - CFE_TBL_Global.ValidationResults[i].Result = 0; - CFE_TBL_Global.ValidationResults[i].ActiveBuffer = false; - CFE_TBL_Global.ValidationResults[i].TableName[0] = '\0'; + UT_TBL_ResetValidationState(i); } /* Initialize the dump-only table dump control blocks */ @@ -673,7 +723,6 @@ void Test_CFE_TBL_ResetCmd(void) */ void Test_CFE_TBL_ValidateCmd(void) { - int i; uint8 Buff; uint8 * BuffPtr = &Buff; CFE_TBL_ValidateCmd_t ValidateCmd; @@ -696,18 +745,14 @@ void Test_CFE_TBL_ValidateCmd(void) ValidateCmd.Payload.ActiveTableFlag = CFE_TBL_BufferSelect_ACTIVE; CFE_TBL_Global.Registry[0].Buffers[CFE_TBL_Global.Registry[0].ActiveBufferIndex].BufferPtr = BuffPtr; - for (i = 0; i < CFE_PLATFORM_TBL_MAX_NUM_VALIDATIONS; i++) - { - CFE_TBL_Global.ValidationResults[i].State = CFE_TBL_VALIDATION_PENDING; - } - + UT_SetDeferredRetcode(UT_KEY(CFE_ResourceId_FindNext), 1, 0); UtAssert_INT32_EQ(CFE_TBL_ValidateCmd(&ValidateCmd), CFE_TBL_INC_ERR_CTR); /* Test where the active buffer has data, but there is no validation * function pointer */ UT_InitData(); - CFE_TBL_Global.ValidationResults[0].State = CFE_TBL_VALIDATION_FREE; + UT_TBL_ResetValidationState(0); CFE_TBL_Global.Registry[0].ValidationFuncPtr = NULL; UtAssert_INT32_EQ(CFE_TBL_ValidateCmd(&ValidateCmd), CFE_TBL_INC_CMD_CTR); @@ -715,7 +760,7 @@ void Test_CFE_TBL_ValidateCmd(void) * exists, and the active table flag is set */ UT_InitData(); - CFE_TBL_Global.ValidationResults[0].State = CFE_TBL_VALIDATION_FREE; + UT_TBL_ResetValidationState(0); CFE_TBL_Global.Registry[0].ValidationFuncPtr = ValFuncPtr; ValidateCmd.Payload.ActiveTableFlag = true; UtAssert_INT32_EQ(CFE_TBL_ValidateCmd(&ValidateCmd), CFE_TBL_INC_CMD_CTR); @@ -724,11 +769,11 @@ void Test_CFE_TBL_ValidateCmd(void) * validation function pointer exists */ UT_InitData(); + UT_TBL_ResetValidationState(0); ValidateCmd.Payload.ActiveTableFlag = CFE_TBL_BufferSelect_INACTIVE; CFE_TBL_Global.Registry[0].DoubleBuffered = true; CFE_TBL_Global.Registry[0].Buffers[1 - CFE_TBL_Global.Registry[0].ActiveBufferIndex].BufferPtr = BuffPtr; - CFE_TBL_Global.ValidationResults[0].State = CFE_TBL_VALIDATION_FREE; - CFE_TBL_Global.Registry[0].ValidationFuncPtr = ValFuncPtr; + CFE_TBL_Global.Registry[0].ValidationFuncPtr = ValFuncPtr; UtAssert_INT32_EQ(CFE_TBL_ValidateCmd(&ValidateCmd), CFE_TBL_INC_CMD_CTR); /* Test with the buffer inactive, the table is single-buffered with a @@ -736,10 +781,10 @@ void Test_CFE_TBL_ValidateCmd(void) * notification message should be sent */ UT_InitData(); + UT_TBL_ResetValidationState(0); CFE_TBL_Global.Registry[0].NotifyByMsg = false; CFE_TBL_Global.Registry[0].DoubleBuffered = false; CFE_TBL_Global.LoadBuffs[CFE_TBL_Global.Registry[0].LoadInProgress].BufferPtr = BuffPtr; - CFE_TBL_Global.ValidationResults[0].State = CFE_TBL_VALIDATION_FREE; CFE_TBL_Global.Registry[0].LoadInProgress = CFE_TBL_NO_LOAD_IN_PROGRESS + 1; UtAssert_INT32_EQ(CFE_TBL_ValidateCmd(&ValidateCmd), CFE_TBL_INC_CMD_CTR); @@ -749,10 +794,10 @@ void Test_CFE_TBL_ValidateCmd(void) */ UT_InitData(); UT_SetDeferredRetcode(UT_KEY(CFE_SB_TransmitMsg), 1, CFE_SB_INTERNAL_ERR); + UT_TBL_ResetValidationState(0); CFE_TBL_Global.Registry[0].NotifyByMsg = true; CFE_TBL_Global.Registry[0].DoubleBuffered = false; CFE_TBL_Global.LoadBuffs[CFE_TBL_Global.Registry[0].LoadInProgress].BufferPtr = BuffPtr; - CFE_TBL_Global.ValidationResults[0].State = CFE_TBL_VALIDATION_FREE; CFE_TBL_Global.Registry[0].LoadInProgress = CFE_TBL_NO_LOAD_IN_PROGRESS + 1; UtAssert_INT32_EQ(CFE_TBL_ValidateCmd(&ValidateCmd), CFE_TBL_INC_CMD_CTR); @@ -818,11 +863,12 @@ void Test_CFE_TBL_GetTblRegData(void) */ void Test_CFE_TBL_GetHkData(void) { - int i; - int32 NumLoadPendingIndex = CFE_PLATFORM_TBL_MAX_NUM_TABLES - 1; - int32 FreeSharedBuffIndex = CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS - 1; - int32 ValTableIndex = CFE_PLATFORM_TBL_MAX_NUM_VALIDATIONS - 1; - CFE_ES_AppId_t AppID; + int i; + int32 NumLoadPendingIndex = CFE_PLATFORM_TBL_MAX_NUM_TABLES - 1; + int32 FreeSharedBuffIndex = CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS - 1; + int32 ValTableIndex = CFE_PLATFORM_TBL_MAX_NUM_VALIDATIONS - 1; + CFE_ES_AppId_t AppID; + CFE_TBL_ValidationResult_t *ValResultPtr; /* Get the AppID being used for UT */ CFE_ES_GetAppID(&AppID); @@ -849,17 +895,18 @@ void Test_CFE_TBL_GetHkData(void) /* Test making a ValPtr with result = CFE_SUCCESS */ UT_InitData(); - CFE_TBL_Global.SuccessValCounter = 0; - CFE_TBL_Global.ValidationResults[ValTableIndex].State = CFE_TBL_VALIDATION_PERFORMED; - CFE_TBL_Global.ValidationResults[ValTableIndex].Result = CFE_SUCCESS; + CFE_TBL_Global.SuccessValCounter = 0; + UT_TBL_SetupPendingValidation(ValTableIndex, false, NULL, &ValResultPtr); + ValResultPtr->State = CFE_TBL_VALIDATION_PERFORMED; CFE_TBL_GetHkData(); UtAssert_UINT32_EQ(CFE_TBL_Global.SuccessValCounter, 1); /* Test making a ValPtr without result = CFE_SUCCESS */ UT_InitData(); - CFE_TBL_Global.FailedValCounter = 0; - CFE_TBL_Global.ValidationResults[ValTableIndex].State = CFE_TBL_VALIDATION_PERFORMED; - CFE_TBL_Global.ValidationResults[ValTableIndex].Result = CFE_SUCCESS - 1; + CFE_TBL_Global.FailedValCounter = 0; + UT_TBL_SetupPendingValidation(ValTableIndex, false, NULL, &ValResultPtr); + ValResultPtr->State = CFE_TBL_VALIDATION_PERFORMED; + ValResultPtr->Result = CFE_SUCCESS - 1; CFE_TBL_GetHkData(); UtAssert_UINT32_EQ(CFE_TBL_Global.FailedValCounter, 1); @@ -2469,14 +2516,19 @@ void Test_CFE_TBL_ReleaseAddresses(void) */ void Test_CFE_TBL_Validate(void) { - int16 RegIndex; - CFE_TBL_RegistryRec_t *RegRecPtr; + int16 RegIndex; + CFE_TBL_RegistryRec_t * RegRecPtr; + CFE_TBL_ValidationResult_t *ValResultPtr; + UtPrintf("Begin Test Validate"); /* Test setup */ RegIndex = CFE_TBL_FindTableInRegistry("ut_cfe_tbl.UT_Table1"); RegRecPtr = &CFE_TBL_Global.Registry[RegIndex]; + /* Refer to the test validation function */ + RegRecPtr->ValidationFuncPtr = Test_CFE_TBL_ValidationFunc; + /* Test response to attempt to validate a table that an application is * not allowed to see */ @@ -2497,39 +2549,61 @@ void Test_CFE_TBL_Validate(void) UT_InitData(); /* a. Configure table for validation */ - CFE_TBL_Global.ValidationResults[0].State = CFE_TBL_VALIDATION_PENDING; - CFE_TBL_Global.ValidationResults[0].Result = 0; - strncpy(CFE_TBL_Global.ValidationResults[0].TableName, "ut_cfe_tbl.UT_Table1", - sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1); - CFE_TBL_Global.ValidationResults[0].TableName[sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1] = '\0'; - CFE_TBL_Global.ValidationResults[0].CrcOfTable = 0; - CFE_TBL_Global.ValidationResults[0].ActiveBuffer = false; - RegRecPtr->ValidateInactiveIndex = 0; + UT_TBL_SetupPendingValidation(0, false, RegRecPtr, &ValResultPtr); + + RegRecPtr->LoadInProgress = 0; /* b. Perform failed validation */ UT_SetDeferredRetcode(UT_KEY(Test_CFE_TBL_ValidationFunc), 1, -1); CFE_UtAssert_SUCCESS(CFE_TBL_Validate(App1TblHandle1)); CFE_UtAssert_EVENTSENT(CFE_TBL_VALIDATION_ERR_EID); CFE_UtAssert_EVENTCOUNT(1); - UtAssert_INT32_EQ(CFE_TBL_Global.ValidationResults[0].Result, -1); + UtAssert_INT32_EQ(ValResultPtr->Result, -1); + + /* Test validation on table w/user-defined address (this is not a valid combo) */ + UT_InitData(); + + /* a. Configure table for validation and set UserDefAddr flag */ + UT_TBL_SetupPendingValidation(0, false, RegRecPtr, &ValResultPtr); + RegRecPtr->UserDefAddr = true; + + /* b. Perform validation */ + CFE_UtAssert_SUCCESS(CFE_TBL_Validate(App1TblHandle1)); + CFE_UtAssert_EVENTSENT(CFE_TBL_VALIDATION_ERR_EID); + CFE_UtAssert_EVENTCOUNT(1); + UtAssert_INT32_EQ(ValResultPtr->Result, -1); + RegRecPtr->UserDefAddr = false; + + /* Test case where validation request is stale */ + UT_InitData(); + + /* a. Configure table for validation and modify the ID so it will not match */ + UT_TBL_SetupPendingValidation(0, false, RegRecPtr, &ValResultPtr); + ValResultPtr->ValId = CFE_TBL_VALRESULTID_C(CFE_ResourceId_FromInteger(1)); + + /* b. Perform validation */ + UtAssert_INT32_EQ(CFE_TBL_Validate(App1TblHandle1), CFE_TBL_INFO_NO_VALIDATION_PENDING); + UtAssert_INT32_EQ(ValResultPtr->Result, CFE_SUCCESS); /* Test successful validation */ UT_InitData(); /* a. Configure table for validation */ - CFE_TBL_Global.ValidationResults[0].State = CFE_TBL_VALIDATION_PENDING; - CFE_TBL_Global.ValidationResults[0].Result = 0; - strncpy(CFE_TBL_Global.ValidationResults[0].TableName, "ut_cfe_tbl.UT_Table1", - sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1); - CFE_TBL_Global.ValidationResults[0].TableName[sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1] = '\0'; - CFE_TBL_Global.ValidationResults[0].CrcOfTable = 0; - CFE_TBL_Global.ValidationResults[0].ActiveBuffer = false; - RegRecPtr->ValidateInactiveIndex = 0; + UT_TBL_SetupPendingValidation(0, false, RegRecPtr, &ValResultPtr); - /* b. Perform failed validation */ + /* b. Perform validation */ UT_SetDeferredRetcode(UT_KEY(Test_CFE_TBL_ValidationFunc), 1, CFE_SUCCESS); CFE_UtAssert_SUCCESS(CFE_TBL_Validate(App1TblHandle1)); - UtAssert_INT32_EQ(CFE_TBL_Global.ValidationResults[0].Result, CFE_SUCCESS); + UtAssert_INT32_EQ(ValResultPtr->Result, CFE_SUCCESS); + + /* Set up a case where the entry does not have a validation function ptr */ + UT_TBL_SetupPendingValidation(0, false, RegRecPtr, &ValResultPtr); + ValResultPtr->Result = -1; + RegRecPtr->ValidationFuncPtr = NULL; + + /* b. Perform failed validation */ + CFE_UtAssert_SUCCESS(CFE_TBL_Validate(App1TblHandle1)); + UtAssert_INT32_EQ(ValResultPtr->Result, CFE_SUCCESS); } /* @@ -2545,6 +2619,7 @@ void Test_CFE_TBL_Manage(void) void * App2TblPtr; CFE_TBL_AccessDescriptor_t *AccessDescPtr; CFE_TBL_Handle_t AccessIterator; + CFE_TBL_ValidationResult_t *ValResultPtr; memset(&TestTable1, 0, sizeof(TestTable1)); @@ -2561,6 +2636,10 @@ void Test_CFE_TBL_Manage(void) /* "Load" image into inactive buffer for table */ RegIndex = CFE_TBL_FindTableInRegistry("ut_cfe_tbl.UT_Table1"); RegRecPtr = &CFE_TBL_Global.Registry[RegIndex]; + + /* Refer to the test validation function */ + RegRecPtr->ValidationFuncPtr = Test_CFE_TBL_ValidationFunc; + CFE_UtAssert_SUCCESS(CFE_TBL_GetWorkingBuffer(&WorkingBufferPtr, RegRecPtr, false)); UT_SetAppID(UT_TBL_APPID_1); UtAssert_INT32_EQ(CFE_TBL_Load(App1TblHandle1, CFE_TBL_SRC_ADDRESS, &TestTable1), CFE_TBL_ERR_LOAD_IN_PROGRESS); @@ -2573,21 +2652,14 @@ void Test_CFE_TBL_Manage(void) UT_InitData(); /* Configure table for validation */ - CFE_TBL_Global.ValidationResults[0].State = CFE_TBL_VALIDATION_PENDING; - CFE_TBL_Global.ValidationResults[0].Result = 0; - strncpy(CFE_TBL_Global.ValidationResults[0].TableName, "ut_cfe_tbl.UT_Table1", - sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1); - CFE_TBL_Global.ValidationResults[0].TableName[sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1] = '\0'; - CFE_TBL_Global.ValidationResults[0].CrcOfTable = 0; - CFE_TBL_Global.ValidationResults[0].ActiveBuffer = false; - RegRecPtr->ValidateInactiveIndex = 0; + UT_TBL_SetupPendingValidation(0, false, RegRecPtr, &ValResultPtr); /* Perform validation via manage call */ UT_SetDeferredRetcode(UT_KEY(Test_CFE_TBL_ValidationFunc), 1, -1); CFE_UtAssert_SUCCESS(CFE_TBL_Manage(App1TblHandle1)); CFE_UtAssert_EVENTSENT(CFE_TBL_VALIDATION_ERR_EID); CFE_UtAssert_EVENTCOUNT(1); - UtAssert_INT32_EQ(CFE_TBL_Global.ValidationResults[0].Result, -1); + UtAssert_INT32_EQ(ValResultPtr->Result, -1); /* Test response to processing an unsuccessful validation request on * inactive buffer ; validation function return code is invalid @@ -2595,21 +2667,14 @@ void Test_CFE_TBL_Manage(void) UT_InitData(); /* Configure table for validation */ - CFE_TBL_Global.ValidationResults[0].State = CFE_TBL_VALIDATION_PENDING; - CFE_TBL_Global.ValidationResults[0].Result = 0; - strncpy(CFE_TBL_Global.ValidationResults[0].TableName, "ut_cfe_tbl.UT_Table1", - sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1); - CFE_TBL_Global.ValidationResults[0].TableName[sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1] = '\0'; - CFE_TBL_Global.ValidationResults[0].CrcOfTable = 0; - CFE_TBL_Global.ValidationResults[0].ActiveBuffer = false; - RegRecPtr->ValidateInactiveIndex = 0; + UT_TBL_SetupPendingValidation(0, false, RegRecPtr, &ValResultPtr); /* Perform validation via manage call */ UT_SetDeferredRetcode(UT_KEY(Test_CFE_TBL_ValidationFunc), 1, 1); CFE_UtAssert_SUCCESS(CFE_TBL_Manage(App1TblHandle1)); CFE_UtAssert_EVENTSENT(CFE_TBL_VALIDATION_ERR_EID); CFE_UtAssert_EVENTCOUNT(1); - UtAssert_INT32_EQ(CFE_TBL_Global.ValidationResults[0].Result, 1); + UtAssert_INT32_EQ(ValResultPtr->Result, 1); /* Test response to processing an unsuccessful validation request; * CFE_TBL_Validate does not return CFE_SUCCESS @@ -2617,20 +2682,13 @@ void Test_CFE_TBL_Manage(void) UT_InitData(); /* Configure table for validation */ - CFE_TBL_Global.ValidationResults[0].State = CFE_TBL_VALIDATION_PENDING; - CFE_TBL_Global.ValidationResults[0].Result = 0; - strncpy(CFE_TBL_Global.ValidationResults[0].TableName, "ut_cfe_tbl.UT_Table1", - sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1); - CFE_TBL_Global.ValidationResults[0].TableName[sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1] = '\0'; - CFE_TBL_Global.ValidationResults[0].CrcOfTable = 0; - CFE_TBL_Global.ValidationResults[0].ActiveBuffer = false; - RegRecPtr->ValidateInactiveIndex = 0; + UT_TBL_SetupPendingValidation(0, false, RegRecPtr, &ValResultPtr); /* Perform validation via manage call */ UT_SetDeferredRetcode(UT_KEY(CFE_ES_GetAppID), 2, CFE_ES_ERR_RESOURCEID_NOT_VALID); UtAssert_INT32_EQ(CFE_TBL_Manage(App1TblHandle1), CFE_ES_ERR_RESOURCEID_NOT_VALID); CFE_UtAssert_EVENTCOUNT(0); - UtAssert_INT32_EQ(CFE_TBL_Global.ValidationResults[0].Result, 0); + UtAssert_INT32_EQ(ValResultPtr->Result, 0); /* Test response to processing a successful validation request on an * inactive buffer @@ -2638,21 +2696,15 @@ void Test_CFE_TBL_Manage(void) UT_InitData(); /* Configure table for validation */ - CFE_TBL_Global.ValidationResults[0].State = CFE_TBL_VALIDATION_PENDING; - CFE_TBL_Global.ValidationResults[0].Result = 1; - strncpy(CFE_TBL_Global.ValidationResults[0].TableName, "ut_cfe_tbl.UT_Table1", - sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1); - CFE_TBL_Global.ValidationResults[0].TableName[sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1] = '\0'; - CFE_TBL_Global.ValidationResults[0].CrcOfTable = 0; - CFE_TBL_Global.ValidationResults[0].ActiveBuffer = false; - RegRecPtr->ValidateInactiveIndex = 0; + UT_TBL_SetupPendingValidation(0, false, RegRecPtr, &ValResultPtr); + ValResultPtr->Result = 1; /* Perform validation via manage call */ UT_SetDeferredRetcode(UT_KEY(Test_CFE_TBL_ValidationFunc), 1, CFE_SUCCESS); CFE_UtAssert_SUCCESS(CFE_TBL_Manage(App1TblHandle1)); CFE_UtAssert_EVENTSENT(CFE_TBL_VALIDATION_INF_EID); CFE_UtAssert_EVENTCOUNT(1); - UtAssert_INT32_EQ(CFE_TBL_Global.ValidationResults[0].Result, 0); + UtAssert_INT32_EQ(ValResultPtr->Result, 0); /* Test response to processing an unsuccessful validation request on an * active buffer @@ -2660,21 +2712,14 @@ void Test_CFE_TBL_Manage(void) UT_InitData(); /* Configure table for validation */ - CFE_TBL_Global.ValidationResults[0].State = CFE_TBL_VALIDATION_PENDING; - CFE_TBL_Global.ValidationResults[0].Result = 0; - strncpy(CFE_TBL_Global.ValidationResults[0].TableName, "ut_cfe_tbl.UT_Table1", - sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1); - CFE_TBL_Global.ValidationResults[0].TableName[sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1] = '\0'; - CFE_TBL_Global.ValidationResults[0].CrcOfTable = 0; - CFE_TBL_Global.ValidationResults[0].ActiveBuffer = true; - RegRecPtr->ValidateActiveIndex = 0; + UT_TBL_SetupPendingValidation(0, true, RegRecPtr, &ValResultPtr); /* Perform validation via manage call */ UT_SetDeferredRetcode(UT_KEY(Test_CFE_TBL_ValidationFunc), 1, -1); CFE_UtAssert_SUCCESS(CFE_TBL_Manage(App1TblHandle1)); CFE_UtAssert_EVENTSENT(CFE_TBL_VALIDATION_ERR_EID); CFE_UtAssert_EVENTCOUNT(1); - UtAssert_INT32_EQ(CFE_TBL_Global.ValidationResults[0].Result, -1); + UtAssert_INT32_EQ(ValResultPtr->Result, -1); /* Test response to processing an unsuccessful validation request on * an active buffer @@ -2682,21 +2727,14 @@ void Test_CFE_TBL_Manage(void) UT_InitData(); /* Configure table for validation */ - CFE_TBL_Global.ValidationResults[0].State = CFE_TBL_VALIDATION_PENDING; - CFE_TBL_Global.ValidationResults[0].Result = 0; - strncpy(CFE_TBL_Global.ValidationResults[0].TableName, "ut_cfe_tbl.UT_Table1", - sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1); - CFE_TBL_Global.ValidationResults[0].TableName[sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1] = '\0'; - CFE_TBL_Global.ValidationResults[0].CrcOfTable = 0; - CFE_TBL_Global.ValidationResults[0].ActiveBuffer = true; - RegRecPtr->ValidateActiveIndex = 0; + UT_TBL_SetupPendingValidation(0, true, RegRecPtr, &ValResultPtr); /* Perform validation via manage call */ UT_SetDeferredRetcode(UT_KEY(Test_CFE_TBL_ValidationFunc), 1, 1); CFE_UtAssert_SUCCESS(CFE_TBL_Manage(App1TblHandle1)); CFE_UtAssert_EVENTSENT(CFE_TBL_VALIDATION_ERR_EID); CFE_UtAssert_EVENTCOUNT(1); - UtAssert_INT32_EQ(CFE_TBL_Global.ValidationResults[0].Result, 1); + UtAssert_INT32_EQ(ValResultPtr->Result, 1); /* Test response to processing a successful validation request on an * active buffer @@ -2704,21 +2742,15 @@ void Test_CFE_TBL_Manage(void) UT_InitData(); /* Configure table for validation */ - CFE_TBL_Global.ValidationResults[0].State = CFE_TBL_VALIDATION_PENDING; - CFE_TBL_Global.ValidationResults[0].Result = 1; - strncpy(CFE_TBL_Global.ValidationResults[0].TableName, "ut_cfe_tbl.UT_Table1", - sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1); - CFE_TBL_Global.ValidationResults[0].TableName[sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1] = '\0'; - CFE_TBL_Global.ValidationResults[0].CrcOfTable = 0; - CFE_TBL_Global.ValidationResults[0].ActiveBuffer = true; - RegRecPtr->ValidateActiveIndex = 0; + UT_TBL_SetupPendingValidation(0, true, RegRecPtr, &ValResultPtr); + ValResultPtr->Result = 1; /* Perform validation via manage call */ UT_SetDeferredRetcode(UT_KEY(Test_CFE_TBL_ValidationFunc), 1, CFE_SUCCESS); CFE_UtAssert_SUCCESS(CFE_TBL_Manage(App1TblHandle1)); CFE_UtAssert_EVENTSENT(CFE_TBL_VALIDATION_INF_EID); CFE_UtAssert_EVENTCOUNT(1); - UtAssert_INT32_EQ(CFE_TBL_Global.ValidationResults[0].Result, 0); + UtAssert_INT32_EQ(ValResultPtr->Result, 0); /* Test response to processing an update request on a locked table */ /* a. Test setup - part 1 */ @@ -2792,21 +2824,14 @@ void Test_CFE_TBL_Manage(void) CFE_UtAssert_SUCCESS(CFE_TBL_GetWorkingBuffer(&WorkingBufferPtr, RegRecPtr, false)); /* Configure table for validation */ - CFE_TBL_Global.ValidationResults[0].State = CFE_TBL_VALIDATION_PENDING; - CFE_TBL_Global.ValidationResults[0].Result = 0; - strncpy(CFE_TBL_Global.ValidationResults[0].TableName, "ut_cfe_tbl.UT_Table2", - sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1); - CFE_TBL_Global.ValidationResults[0].TableName[sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1] = '\0'; - CFE_TBL_Global.ValidationResults[0].CrcOfTable = 0; - CFE_TBL_Global.ValidationResults[0].ActiveBuffer = false; - RegRecPtr->ValidateInactiveIndex = 0; + UT_TBL_SetupPendingValidation(1, false, RegRecPtr, &ValResultPtr); /* Perform validation via manage call */ UT_SetDeferredRetcode(UT_KEY(Test_CFE_TBL_ValidationFunc), 1, -1); CFE_UtAssert_SUCCESS(CFE_TBL_Manage(App1TblHandle2)); CFE_UtAssert_EVENTSENT(CFE_TBL_VALIDATION_ERR_EID); CFE_UtAssert_EVENTCOUNT(1); - UtAssert_INT32_EQ(CFE_TBL_Global.ValidationResults[0].Result, -1); + UtAssert_INT32_EQ(ValResultPtr->Result, -1); /* Test successfully processing a validation request on an inactive buffer * (double buffered) @@ -2814,21 +2839,14 @@ void Test_CFE_TBL_Manage(void) UT_InitData(); /* Configure table for validation */ - CFE_TBL_Global.ValidationResults[0].State = CFE_TBL_VALIDATION_PENDING; - CFE_TBL_Global.ValidationResults[0].Result = 1; - strncpy(CFE_TBL_Global.ValidationResults[0].TableName, "ut_cfe_tbl.UT_Table2", - sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1); - CFE_TBL_Global.ValidationResults[0].TableName[sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1] = '\0'; - CFE_TBL_Global.ValidationResults[0].CrcOfTable = 0; - CFE_TBL_Global.ValidationResults[0].ActiveBuffer = false; - RegRecPtr->ValidateInactiveIndex = 0; + UT_TBL_SetupPendingValidation(1, false, RegRecPtr, &ValResultPtr); /* Perform validation via manage call */ UT_SetDeferredRetcode(UT_KEY(Test_CFE_TBL_ValidationFunc), 1, CFE_SUCCESS); CFE_UtAssert_SUCCESS(CFE_TBL_Manage(App1TblHandle2)); CFE_UtAssert_EVENTSENT(CFE_TBL_VALIDATION_INF_EID); CFE_UtAssert_EVENTCOUNT(1); - UtAssert_INT32_EQ(CFE_TBL_Global.ValidationResults[0].Result, 0); + UtAssert_INT32_EQ(ValResultPtr->Result, 0); /* Test processing an unsuccessful validation request on an active buffer * (double buffered) @@ -2836,21 +2854,14 @@ void Test_CFE_TBL_Manage(void) UT_InitData(); /* Configure table for validation */ - CFE_TBL_Global.ValidationResults[0].State = CFE_TBL_VALIDATION_PENDING; - CFE_TBL_Global.ValidationResults[0].Result = 0; - strncpy(CFE_TBL_Global.ValidationResults[0].TableName, "ut_cfe_tbl.UT_Table2", - sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1); - CFE_TBL_Global.ValidationResults[0].TableName[sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1] = '\0'; - CFE_TBL_Global.ValidationResults[0].CrcOfTable = 0; - CFE_TBL_Global.ValidationResults[0].ActiveBuffer = true; - RegRecPtr->ValidateActiveIndex = 0; + UT_TBL_SetupPendingValidation(1, true, RegRecPtr, &ValResultPtr); /* Perform validation via manage call */ UT_SetDeferredRetcode(UT_KEY(Test_CFE_TBL_ValidationFunc), 1, -1); CFE_UtAssert_SUCCESS(CFE_TBL_Manage(App1TblHandle2)); CFE_UtAssert_EVENTSENT(CFE_TBL_VALIDATION_ERR_EID); CFE_UtAssert_EVENTCOUNT(1); - UtAssert_INT32_EQ(CFE_TBL_Global.ValidationResults[0].Result, -1); + UtAssert_INT32_EQ(ValResultPtr->Result, -1); /* Test successfully processing a validation request on active buffer * (double buffered) @@ -2858,21 +2869,15 @@ void Test_CFE_TBL_Manage(void) UT_InitData(); /* Configure table for validation */ - CFE_TBL_Global.ValidationResults[0].State = CFE_TBL_VALIDATION_PENDING; - CFE_TBL_Global.ValidationResults[0].Result = 1; - strncpy(CFE_TBL_Global.ValidationResults[0].TableName, "ut_cfe_tbl.UT_Table2", - sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1); - CFE_TBL_Global.ValidationResults[0].TableName[sizeof(CFE_TBL_Global.ValidationResults[0].TableName) - 1] = '\0'; - CFE_TBL_Global.ValidationResults[0].CrcOfTable = 0; - CFE_TBL_Global.ValidationResults[0].ActiveBuffer = true; - RegRecPtr->ValidateActiveIndex = 0; + UT_TBL_SetupPendingValidation(1, true, RegRecPtr, &ValResultPtr); + ValResultPtr->Result = 1; /* Perform validation via manage call */ UT_SetDeferredRetcode(UT_KEY(Test_CFE_TBL_ValidationFunc), 1, CFE_SUCCESS); CFE_UtAssert_SUCCESS(CFE_TBL_Manage(App1TblHandle2)); CFE_UtAssert_EVENTSENT(CFE_TBL_VALIDATION_INF_EID); CFE_UtAssert_EVENTCOUNT(1); - UtAssert_INT32_EQ(CFE_TBL_Global.ValidationResults[0].Result, 0); + UtAssert_INT32_EQ(ValResultPtr->Result, 0); /* Test successfully processing a table dump request */ UT_InitData(); @@ -3999,6 +4004,105 @@ void Test_CFE_TBL_Internal(void) CFE_TBL_ERR_INVALID_SIZE); } +/* + * Tests the resource accessors for Validation Results + */ +void Test_CFE_TBL_ResourceID_ValidationResult(void) +{ + uint32 Idx; + CFE_TBL_ValidationResultId_t InvalidResultId; + CFE_TBL_ValidationResultId_t ValidResultId; + CFE_ResourceId_t PendingId; + + UT_InitData(); + + InvalidResultId = CFE_TBL_VALRESULTID_UNDEFINED; + UT_SetDefaultReturnValue(UT_KEY(CFE_ResourceId_ToIndex), CFE_ES_ERR_RESOURCEID_NOT_VALID); + UtAssert_INT32_EQ(CFE_TBL_ValidationResultId_ToIndex(InvalidResultId, &Idx), CFE_ES_ERR_RESOURCEID_NOT_VALID); + + /* by definition, looking up the undefined value should always be NULL */ + UtAssert_NULL(CFE_TBL_LocateValidationResultByID(InvalidResultId)); + UT_ResetState(UT_KEY(CFE_ResourceId_ToIndex)); + + ValidResultId = CFE_TBL_VALRESULTID_C(CFE_ResourceId_FromInteger(CFE_TBL_VALRESULTID_BASE + 1)); + UtAssert_INT32_EQ(CFE_TBL_ValidationResultId_ToIndex(ValidResultId, &Idx), CFE_SUCCESS); + + UtAssert_VOIDCALL(PendingId = CFE_TBL_GetNextValResultBlock()); + UtAssert_BOOL_TRUE(CFE_ResourceId_IsDefined(PendingId)); + + /* The slot should be available right now */ + UtAssert_BOOL_FALSE(CFE_TBL_CheckValidationResultSlotUsed(PendingId)); + + /* Make it used and confirm it is reported as not available */ + CFE_TBL_ValidationResultSetUsed(CFE_TBL_LocateValidationResultByID(CFE_TBL_VALRESULTID_C(PendingId)), PendingId); + UtAssert_BOOL_TRUE(CFE_TBL_CheckValidationResultSlotUsed(PendingId)); + + /* Test case where no ID is available */ + UT_SetDefaultReturnValue(UT_KEY(CFE_ResourceId_FindNext), 0); + UtAssert_VOIDCALL(PendingId = CFE_TBL_GetNextValResultBlock()); + UtAssert_BOOL_FALSE(CFE_ResourceId_IsDefined(PendingId)); + + /* A nonexistent slot is always "unavailable" */ + UtAssert_BOOL_TRUE(CFE_TBL_CheckValidationResultSlotUsed(PendingId)); + UT_ResetState(UT_KEY(CFE_ResourceId_FindNext)); +} + +/* + * Tests the resource accessors for Table Registry Records + */ +void Test_CFE_TBL_ResourceID_RegistryRecord(void) +{ + uint32 Idx; + CFE_TBL_RegId_t InvalidRegId; + CFE_TBL_RegId_t ValidRegId; + CFE_TBL_RegistryRec_t *RegRecPtr; + + UT_InitData(); + + InvalidRegId = (CFE_TBL_RegId_t)(-1); + UtAssert_INT32_EQ(CFE_TBL_RegId_ToIndex(InvalidRegId, &Idx), CFE_TBL_ERR_INVALID_HANDLE); + + /* by definition, looking up the undefined value should always be NULL */ + UtAssert_NULL(CFE_TBL_LocateRegistryRecordByID(InvalidRegId)); + + InvalidRegId = (CFE_TBL_RegId_t)(CFE_PLATFORM_TBL_MAX_NUM_TABLES + 1); + UtAssert_INT32_EQ(CFE_TBL_RegId_ToIndex(InvalidRegId, &Idx), CFE_TBL_ERR_INVALID_HANDLE); + + /* Now with a valid ID */ + ValidRegId = (CFE_TBL_RegId_t)(1); + UtAssert_INT32_EQ(CFE_TBL_RegId_ToIndex(ValidRegId, &Idx), CFE_SUCCESS); + UtAssert_UINT32_EQ(Idx, 1); + UtAssert_NOT_NULL(RegRecPtr = CFE_TBL_LocateRegistryRecordByID(ValidRegId)); + + UtAssert_UINT32_EQ(CFE_TBL_RegistryRecordGetID(RegRecPtr), ValidRegId); +} + +/* + * Tests the resource accessors for Table Access Descriptors + */ +void Test_CFE_TBL_ResourceID_AccessDescriptor(void) +{ + uint32 Idx; + CFE_TBL_Handle_t InvalidHandle; + CFE_TBL_Handle_t ValidHandle; + + UT_InitData(); + + InvalidHandle = (CFE_TBL_Handle_t)(-1); + UtAssert_INT32_EQ(CFE_TBL_Handle_ToIndex(InvalidHandle, &Idx), CFE_TBL_ERR_INVALID_HANDLE); + + /* by definition, looking up the undefined value should always be NULL */ + UtAssert_NULL(CFE_TBL_LocateRegistryRecordByID(InvalidHandle)); + + InvalidHandle = (CFE_TBL_Handle_t)(CFE_PLATFORM_TBL_MAX_NUM_HANDLES + 1); + UtAssert_INT32_EQ(CFE_TBL_Handle_ToIndex(InvalidHandle, &Idx), CFE_TBL_ERR_INVALID_HANDLE); + + /* Now with a valid ID */ + ValidHandle = (CFE_TBL_Handle_t)(1); + UtAssert_INT32_EQ(CFE_TBL_RegId_ToIndex(ValidHandle, &Idx), CFE_SUCCESS); + UtAssert_UINT32_EQ(Idx, 1); +} + /* ** Test function executed when the contents of a table need to be validated */ diff --git a/modules/tbl/ut-coverage/tbl_UT.h b/modules/tbl/ut-coverage/tbl_UT.h index d4f2d80c7..95fd0d97b 100644 --- a/modules/tbl/ut-coverage/tbl_UT.h +++ b/modules/tbl/ut-coverage/tbl_UT.h @@ -680,4 +680,9 @@ void Test_CFE_TBL_Internal(void); ******************************************************************************/ int32 Test_CFE_TBL_ValidationFunc(void *TblPtr); +/* Test cases for resource ID access patterns based on shared resource types */ +void Test_CFE_TBL_ResourceID_ValidationResult(void); +void Test_CFE_TBL_ResourceID_RegistryRecord(void); +void Test_CFE_TBL_ResourceID_AccessDescriptor(void); + #endif /* TBL_UT_H */