diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index 47465454c..975734f6c 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -104,8 +104,8 @@ jobs: - name: Confirm Minimum Coverage run: | - missed_branches=50 - missed_lines=17 + missed_branches=39 + missed_lines=19 branch_nums=$(grep -A 3 "Overall coverage rate" lcov_out.txt | grep branches | grep -oP "[0-9]+[0-9]*") line_nums=$(grep -A 3 "Overall coverage rate" lcov_out.txt | grep lines | grep -oP "[0-9]+[0-9]*") diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b3db8dc0..f7e98470b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## Development Build: equuleus-rc1+dev163 +- Improve CFE_SB_AllocateMessageBuffer error report +- Update CFE_PLATFORM_ES_DEFAULT_SYSLOG_MODE macro in es_verify.h +- Update comment re. limits of CFE_PLATFORM_SB_HIGHEST_VALID_MSGID +- Use size_t for variables/parameters representing size +- Remove superfluous status assignment in CFE_SB_CreatePipe +- null value in vsnprintf +- Adds JSC 2.1 Static Analysis comments +- Reduces CFE_EVS_MAX_PORT_MSG_LENGTH to prevent new line character truncation +- See , , , , , , , and + +## Development Build: equuleus-rc1+dev141 +- use resourceids for internal table validation and dump control blocks +- refactor SB to support additional use cases +- msg api test buffer overrun +- See <2551>, <2381>, and <2537> + ## Development Build: equuleus-rc1+dev137 - msg api test buffer overrun - send CMake message to stdout instead of stderr diff --git a/modules/cfe_testcase/src/tbl_content_mang_test.c b/modules/cfe_testcase/src/tbl_content_mang_test.c index d488acf01..fc4e2dab9 100644 --- a/modules/cfe_testcase/src/tbl_content_mang_test.c +++ b/modules/cfe_testcase/src/tbl_content_mang_test.c @@ -279,8 +279,8 @@ void TblTest_GenerateTblFiles(void) { osal_id_t fh1 = OS_OBJECT_ID_UNDEFINED; osal_id_t fh2 = OS_OBJECT_ID_UNDEFINED; - uint32 PartialOffset; - uint32 PartialSize; + size_t PartialOffset; + size_t PartialSize; union { uint8 u8; diff --git a/modules/core_api/fsw/inc/cfe_version.h b/modules/core_api/fsw/inc/cfe_version.h index 6da2a45c2..efc7bf9de 100644 --- a/modules/core_api/fsw/inc/cfe_version.h +++ b/modules/core_api/fsw/inc/cfe_version.h @@ -26,7 +26,7 @@ #define CFE_VERSION_H /* Development Build Macro Definitions */ -#define CFE_BUILD_NUMBER 137 /**< @brief Development: Number of development git commits since CFE_BUILD_BASELINE */ +#define CFE_BUILD_NUMBER 163 /**< @brief Development: Number of development git commits since CFE_BUILD_BASELINE */ #define CFE_BUILD_BASELINE "equuleus-rc1" /**< @brief Development: Reference git tag for build number */ #define CFE_BUILD_DEV_CYCLE "equuleus-rc2" /**< @brief Development: Release name for current development cycle */ #define CFE_BUILD_CODENAME "Equuleus" /**< @brief: Development: Code name for the current build */ diff --git a/modules/core_api/ut-stubs/src/cfe_sb_handlers.c b/modules/core_api/ut-stubs/src/cfe_sb_handlers.c index 583223e44..40cc90889 100644 --- a/modules/core_api/ut-stubs/src/cfe_sb_handlers.c +++ b/modules/core_api/ut-stubs/src/cfe_sb_handlers.c @@ -39,8 +39,8 @@ typedef struct { CFE_SB_MsgId_t MsgId; - uint32 UserLength; - uint32 TotalLength; + size_t UserLength; + size_t TotalLength; uint16 CommandCode; CFE_TIME_SysTime_t TimeStamp; } CFE_SB_StubMsg_MetaData_t; @@ -482,7 +482,7 @@ void UT_DefaultHandler_CFE_SB_GetUserData(void *UserObj, UT_EntryKey_t FuncKey, CFE_MSG_Message_t *MsgPtr = UT_Hook_GetArgValueByName(Context, "MsgPtr", CFE_MSG_Message_t *); uint8 * BytePtr; void * Result; - uint16 HdrSize; + size_t HdrSize; if (UT_Stub_CopyToLocal(UT_KEY(CFE_SB_GetUserData), &Result, sizeof(Result)) != sizeof(Result)) { diff --git a/modules/core_private/config/default_cfe_core_private_internal_cfg.h b/modules/core_private/config/default_cfe_core_private_internal_cfg.h index f654d66a2..6b9c8ba15 100644 --- a/modules/core_private/config/default_cfe_core_private_internal_cfg.h +++ b/modules/core_private/config/default_cfe_core_private_internal_cfg.h @@ -25,7 +25,7 @@ * to items in this file only affect the local module and will be transparent * to external entities that are using the public interface(s). * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ diff --git a/modules/core_private/ut-stubs/inc/ut_support.h b/modules/core_private/ut-stubs/inc/ut_support.h index db77d19ca..cbf7e0430 100644 --- a/modules/core_private/ut-stubs/inc/ut_support.h +++ b/modules/core_private/ut-stubs/inc/ut_support.h @@ -102,7 +102,7 @@ typedef struct { CFE_SB_MsgId_t MsgId; uint16 SnapshotOffset; - uint16 SnapshotSize; + size_t SnapshotSize; uint16 Count; void * SnapshotBuffer; } UT_SoftwareBusSnapshot_Entry_t; @@ -394,7 +394,7 @@ void UT_SetStatusBSPResetArea(int32 status, uint32 Signature, uint32 ClockSignal ** This function does not return a value. ** ******************************************************************************/ -void UT_SetReadBuffer(void *Buff, int NumBytes); +void UT_SetReadBuffer(void *Buff, size_t NumBytes); /*****************************************************************************/ /** @@ -414,7 +414,7 @@ void UT_SetReadBuffer(void *Buff, int NumBytes); ** This function does not return a value. ** ******************************************************************************/ -void UT_SetReadHeader(void *Hdr, int NumBytes); +void UT_SetReadHeader(void *Hdr, size_t NumBytes); /*****************************************************************************/ /** @@ -454,7 +454,7 @@ void UT_SetDummyFuncRtn(int Return); ** \sa ** ******************************************************************************/ -void UT_SetSizeofESResetArea(int32 Size); +void UT_SetSizeofESResetArea(size_t Size); /*****************************************************************************/ /** @@ -472,7 +472,7 @@ void UT_SetSizeofESResetArea(int32 Size); ** This function does not return a value. ** ******************************************************************************/ -uint8 *UT_SetCDSSize(int32 Size); +uint8 *UT_SetCDSSize(size_t Size); /*****************************************************************************/ /** diff --git a/modules/core_private/ut-stubs/src/ut_support.c b/modules/core_private/ut-stubs/src/ut_support.c index 01fbb07c0..5eb89fedb 100644 --- a/modules/core_private/ut-stubs/src/ut_support.c +++ b/modules/core_private/ut-stubs/src/ut_support.c @@ -43,7 +43,7 @@ uint8 UT_Endianess; static char UT_appname[80]; static char UT_subsys[5]; static CFE_ES_AppId_t UT_AppID; -static uint32 UT_LastCDSSize = 0; +static size_t UT_LastCDSSize = 0; typedef union { @@ -387,7 +387,7 @@ void UT_SetStatusBSPResetArea(int32 status, uint32 Signature, uint32 ClockSignal /* ** Set the contents of the buffer to read */ -void UT_SetReadBuffer(void *Buff, int NumBytes) +void UT_SetReadBuffer(void *Buff, size_t NumBytes) { UT_SetDataBuffer(UT_KEY(OS_read), Buff, NumBytes, true); } @@ -395,7 +395,7 @@ void UT_SetReadBuffer(void *Buff, int NumBytes) /* ** Set the contents of the header to read */ -void UT_SetReadHeader(void *Hdr, int NumBytes) +void UT_SetReadHeader(void *Hdr, size_t NumBytes) { UT_SetDataBuffer(UT_KEY(CFE_FS_ReadHeader), Hdr, NumBytes, true); } @@ -411,7 +411,7 @@ void UT_SetDummyFuncRtn(int Return) /* ** Set the size of the ES reset area */ -void UT_SetSizeofESResetArea(int32 Size) +void UT_SetSizeofESResetArea(size_t Size) { UT_ResetState(UT_KEY(CFE_PSP_GetResetArea)); if (Size > 0) @@ -428,12 +428,12 @@ void UT_SetSizeofESResetArea(int32 Size) /* ** Set the CDS size returned by the BSP */ -uint8 *UT_SetCDSSize(int32 Size) +uint8 *UT_SetCDSSize(size_t Size) { UT_ResetState(UT_KEY(CFE_PSP_GetCDSSize)); UT_ResetState(UT_KEY(CFE_PSP_ReadFromCDS)); UT_ResetState(UT_KEY(CFE_PSP_WriteToCDS)); - if (Size <= 0) + if (Size == 0) { UT_LastCDSSize = 0; return NULL; @@ -584,7 +584,7 @@ CFE_ES_ResetData_t *UT_GetResetDataPtr(void) ** But on the upside this concession avoids a far more complicated issue of ** needing a fully-fledged implementation of printf in the OS_printf stub. */ -static int UT_StrCmpFormatStr(const char *FormatStr, const char *TestStr, uint32 FormatLength, uint32 TestLength) +static int UT_StrCmpFormatStr(const char *FormatStr, const char *TestStr, size_t FormatLength, size_t TestLength) { const char *ChunkStart; const char *ChunkEnd; @@ -684,13 +684,13 @@ static int UT_StrCmpFormatStr(const char *FormatStr, const char *TestStr, uint32 * A string comparison function that will match exact strings only * (Printf style conversion strings are compared literally) */ -static int UT_StrCmpExact(const char *RefStr, const char *TestStr, uint32 RefLength, uint32 TestLength) +static int UT_StrCmpExact(const char *RefStr, const char *TestStr, size_t RefLength, size_t TestLength) { return (RefLength == TestLength && memcmp(RefStr, TestStr, RefLength) == 0); } static uint32 UT_GetMessageCount(const char *Msg, UT_Buffer_t *Buf, - int (*Comparator)(const char *, const char *, uint32, uint32)) + int (*Comparator)(const char *, const char *, size_t, size_t)) { uint32 Count = 0; uint32 MsgLen = strlen(Msg); diff --git a/modules/es/config/default_cfe_es_interface_cfg.h b/modules/es/config/default_cfe_es_interface_cfg.h index 5fa4c574a..989be3bf0 100644 --- a/modules/es/config/default_cfe_es_interface_cfg.h +++ b/modules/es/config/default_cfe_es_interface_cfg.h @@ -25,7 +25,7 @@ * interface, tables definitions, and any other data products that * serve to exchange information with other entities. * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ diff --git a/modules/es/config/default_cfe_es_internal_cfg.h b/modules/es/config/default_cfe_es_internal_cfg.h index cb9bbee28..0eb49760f 100644 --- a/modules/es/config/default_cfe_es_internal_cfg.h +++ b/modules/es/config/default_cfe_es_internal_cfg.h @@ -25,7 +25,7 @@ * to items in this file only affect the local module and will be transparent * to external entities that are using the public interface(s). * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ diff --git a/modules/es/config/default_cfe_es_mission_cfg.h b/modules/es/config/default_cfe_es_mission_cfg.h index 4324f4648..6ade6e0ef 100644 --- a/modules/es/config/default_cfe_es_mission_cfg.h +++ b/modules/es/config/default_cfe_es_mission_cfg.h @@ -24,7 +24,7 @@ * This is a compatibility header for the "mission_cfg.h" file that has * traditionally provided public config definitions for each CFS app. * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ diff --git a/modules/es/config/default_cfe_es_msg.h b/modules/es/config/default_cfe_es_msg.h index 712dc8f77..b4fbe16a3 100644 --- a/modules/es/config/default_cfe_es_msg.h +++ b/modules/es/config/default_cfe_es_msg.h @@ -24,7 +24,7 @@ * This is a compatibility header for the "cfe_es_msg.h" file that has * traditionally provided the message definitions for cFS apps. * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ diff --git a/modules/es/config/default_cfe_es_platform_cfg.h b/modules/es/config/default_cfe_es_platform_cfg.h index 2b3176a9b..b623d03af 100644 --- a/modules/es/config/default_cfe_es_platform_cfg.h +++ b/modules/es/config/default_cfe_es_platform_cfg.h @@ -28,7 +28,7 @@ * These definitions are now provided in two separate files, one for * the public/mission scope and one for internal scope. * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ diff --git a/modules/es/fsw/src/cfe_es_apps.c b/modules/es/fsw/src/cfe_es_apps.c index b213f7820..065ff4879 100644 --- a/modules/es/fsw/src/cfe_es_apps.c +++ b/modules/es/fsw/src/cfe_es_apps.c @@ -75,7 +75,7 @@ void CFE_ES_StartApplications(uint32 ResetType, const char *StartFilePath) const char *TokenList[CFE_ES_STARTSCRIPT_MAX_TOKENS_PER_LINE]; uint32 NumTokens; uint32 NumLines; - uint32 BuffLen; /* Length of the current buffer */ + size_t BuffLen; /* Length of the current buffer */ osal_id_t AppFile = OS_OBJECT_ID_UNDEFINED; int32 Status; int32 OsStatus; diff --git a/modules/es/fsw/src/cfe_es_start.h b/modules/es/fsw/src/cfe_es_start.h index 281d739b6..7cf34b255 100644 --- a/modules/es/fsw/src/cfe_es_start.h +++ b/modules/es/fsw/src/cfe_es_start.h @@ -71,7 +71,7 @@ typedef struct char ObjectName[OS_MAX_API_NAME]; /* task or OS object name */ CFE_ES_FuncPtrUnion_t FuncPtrUnion; /* task or function reference */ uint32 ObjectPriority; /* object priority */ - uint32 ObjectSize; /* size used for stack, queue size, etc. */ + size_t ObjectSize; /* size used for stack, queue size, etc. */ uint32 ObjectFlags; /* extra flags to pass */ } CFE_ES_ObjectTable_t; diff --git a/modules/es/fsw/src/cfe_es_task.c b/modules/es/fsw/src/cfe_es_task.c index e7ff65b44..fce73d15f 100644 --- a/modules/es/fsw/src/cfe_es_task.c +++ b/modules/es/fsw/src/cfe_es_task.c @@ -956,7 +956,7 @@ int32 CFE_ES_QueryAllCmd(const CFE_ES_QueryAllCmd_t *data) osal_id_t FileDescriptor = OS_OBJECT_ID_UNDEFINED; uint32 i; uint32 EntryCount = 0; - uint32 FileSize = 0; + size_t FileSize = 0; int32 OsStatus; int32 Result; CFE_ES_AppInfo_t AppInfo; @@ -1093,8 +1093,8 @@ int32 CFE_ES_QueryAllCmd(const CFE_ES_QueryAllCmd_t *data) OS_close(FileDescriptor); CFE_ES_Global.TaskData.CommandCounter++; CFE_EVS_SendEvent(CFE_ES_ALL_APPS_EID, CFE_EVS_EventType_DEBUG, - "App Info file written to %s, Entries=%d, FileSize=%d", QueryAllFilename, (int)EntryCount, - (int)FileSize); + "App Info file written to %s, Entries=%d, FileSize=%lu", QueryAllFilename, (int)EntryCount, + (unsigned long)FileSize); } else { @@ -1116,7 +1116,7 @@ int32 CFE_ES_QueryAllTasksCmd(const CFE_ES_QueryAllTasksCmd_t *data) osal_id_t FileDescriptor = OS_OBJECT_ID_UNDEFINED; uint32 i; uint32 EntryCount = 0; - uint32 FileSize = 0; + size_t FileSize = 0; int32 OsStatus; int32 Result; CFE_ES_TaskInfo_t TaskInfo; @@ -1245,8 +1245,8 @@ int32 CFE_ES_QueryAllTasksCmd(const CFE_ES_QueryAllTasksCmd_t *data) OS_close(FileDescriptor); CFE_ES_Global.TaskData.CommandCounter++; CFE_EVS_SendEvent(CFE_ES_TASKINFO_EID, CFE_EVS_EventType_DEBUG, - "Task Info file written to %s, Entries=%d, FileSize=%d", QueryAllFilename, (int)EntryCount, - (int)FileSize); + "Task Info file written to %s, Entries=%d, FileSize=%lu", QueryAllFilename, (int)EntryCount, + (unsigned long)FileSize); } else { diff --git a/modules/es/fsw/src/cfe_es_verify.h b/modules/es/fsw/src/cfe_es_verify.h index d8895ba26..4cffb95f4 100644 --- a/modules/es/fsw/src/cfe_es_verify.h +++ b/modules/es/fsw/src/cfe_es_verify.h @@ -118,12 +118,21 @@ #endif /* -** SysLog mode +** Default System Log Mode following Power On Reset */ -#if CFE_PLATFORM_ES_DEFAULT_SYSLOG_MODE < 0 -#error CFE_PLATFORM_ES_DEFAULT_SYSLOG_MODE cannot be less than 0! -#elif CFE_PLATFORM_ES_DEFAULT_SYSLOG_MODE > 1 -#error CFE_PLATFORM_ES_DEFAULT_SYSLOG_MODE cannot be greater than 1! +#if CFE_PLATFORM_ES_DEFAULT_POR_SYSLOG_MODE < 0 +#error CFE_PLATFORM_ES_DEFAULT_POR_SYSLOG_MODE cannot be less than 0! +#elif CFE_PLATFORM_ES_DEFAULT_POR_SYSLOG_MODE > 1 +#error CFE_PLATFORM_ES_DEFAULT_POR_SYSLOG_MODE cannot be greater than 1! +#endif + +/* +** Default System Log Mode following Processor Reset +*/ +#if CFE_PLATFORM_ES_DEFAULT_PR_SYSLOG_MODE < 0 +#error CFE_PLATFORM_ES_DEFAULT_PR_SYSLOG_MODE cannot be less than 0! +#elif CFE_PLATFORM_ES_DEFAULT_PR_SYSLOG_MODE > 1 +#error CFE_PLATFORM_ES_DEFAULT_PR_SYSLOG_MODE cannot be greater than 1! #endif /* diff --git a/modules/es/ut-coverage/es_UT.c b/modules/es/ut-coverage/es_UT.c index 1511de87b..78b9c130a 100644 --- a/modules/es/ut-coverage/es_UT.c +++ b/modules/es/ut-coverage/es_UT.c @@ -470,7 +470,7 @@ void ES_UT_SetupMemPoolId(CFE_ES_MemPoolRecord_t **OutPoolRecPtr) } } -void ES_UT_SetupCDSGlobal(uint32 CDS_Size) +void ES_UT_SetupCDSGlobal(size_t CDS_Size) { CFE_ES_CDS_Instance_t *CDS = &CFE_ES_Global.CDSVars; @@ -1145,7 +1145,7 @@ static void ES_UT_Config_IterateAll(void *UserObj, UT_EntryKey_t FuncKey, const void TestApps(void) { - int NumBytes; + size_t NumBytes; CFE_ES_AppInfo_t AppInfo; CFE_ES_AppId_t AppId; CFE_ES_TaskId_t TaskId; @@ -3996,7 +3996,7 @@ void TestAPI(void) osal_id_t TestObjId; char AppName[OS_MAX_API_NAME + 12]; char SysLogBuf[CFE_TIME_PRINTED_STRING_SIZE + 20]; - uint32 SysLogBufSize; + size_t SysLogBufSize; uint32 StackBuf[8]; uint8 Data[12]; uint32 ResetType; @@ -4554,9 +4554,9 @@ void TestAPI(void) UT_SetHandlerFunction(UT_KEY(CFE_TIME_Print), ES_UT_FillBuffer, &SysLogBufSize); UtAssert_VOIDCALL(ES_UT_SysLog_snprintf(SysLogBuf, sizeof(SysLogBuf), "b")); - /* Force a vsnprintf failure */ + /* Force a vsnprintf to return 0 */ ES_ResetUnitTest(); - UtAssert_VOIDCALL(ES_UT_SysLog_snprintf(SysLogBuf, sizeof(SysLogBuf), NULL)); + UtAssert_VOIDCALL(ES_UT_SysLog_snprintf(SysLogBuf, sizeof(SysLogBuf), "")); /* Test run loop with an application error status */ ES_ResetUnitTest(); @@ -4739,7 +4739,7 @@ void TestCDS() CFE_ES_CDSHandle_t CDSHandle; CFE_ES_CDS_RegRec_t *UtCDSRegRecPtr; uint32 i; - uint32 TempSize; + size_t TempSize; uint8 BlockData[ES_UT_CDS_BLOCK_SIZE]; UtPrintf("Begin Test CDS"); diff --git a/modules/evs/config/default_cfe_evs_interface_cfg.h b/modules/evs/config/default_cfe_evs_interface_cfg.h index a8f6643fc..8f26f44f6 100644 --- a/modules/evs/config/default_cfe_evs_interface_cfg.h +++ b/modules/evs/config/default_cfe_evs_interface_cfg.h @@ -25,7 +25,7 @@ * interface, tables definitions, and any other data products that * serve to exchange information with other entities. * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ diff --git a/modules/evs/config/default_cfe_evs_internal_cfg.h b/modules/evs/config/default_cfe_evs_internal_cfg.h index d4fc64b0c..3169013b8 100644 --- a/modules/evs/config/default_cfe_evs_internal_cfg.h +++ b/modules/evs/config/default_cfe_evs_internal_cfg.h @@ -25,7 +25,7 @@ * to items in this file only affect the local module and will be transparent * to external entities that are using the public interface(s). * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ diff --git a/modules/evs/config/default_cfe_evs_mission_cfg.h b/modules/evs/config/default_cfe_evs_mission_cfg.h index 5146773c2..c7d28e3f8 100644 --- a/modules/evs/config/default_cfe_evs_mission_cfg.h +++ b/modules/evs/config/default_cfe_evs_mission_cfg.h @@ -24,7 +24,7 @@ * This is a compatibility header for the "mission_cfg.h" file that has * traditionally provided public config definitions for each CFS app. * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ diff --git a/modules/evs/config/default_cfe_evs_msg.h b/modules/evs/config/default_cfe_evs_msg.h index 394780cda..035f7f5d6 100644 --- a/modules/evs/config/default_cfe_evs_msg.h +++ b/modules/evs/config/default_cfe_evs_msg.h @@ -24,7 +24,7 @@ * This is a compatibility header for the "cfe_evs_msg.h" file that has * traditionally provided the message definitions for cFS apps. * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ diff --git a/modules/evs/config/default_cfe_evs_platform_cfg.h b/modules/evs/config/default_cfe_evs_platform_cfg.h index 83f40168c..19fb26fc5 100644 --- a/modules/evs/config/default_cfe_evs_platform_cfg.h +++ b/modules/evs/config/default_cfe_evs_platform_cfg.h @@ -28,7 +28,7 @@ * These definitions are now provided in two separate files, one for * the public/mission scope and one for internal scope. * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ diff --git a/modules/evs/fsw/src/cfe_evs_task.h b/modules/evs/fsw/src/cfe_evs_task.h index e765adecd..8cacfe0f4 100644 --- a/modules/evs/fsw/src/cfe_evs_task.h +++ b/modules/evs/fsw/src/cfe_evs_task.h @@ -60,14 +60,17 @@ #define CFE_EVS_MAX_FILTER_COUNT 65535 #define CFE_EVS_MAX_SQUELCH_COUNT 255 #define CFE_EVS_PIPE_NAME "EVS_CMD_PIPE" -#define CFE_EVS_MAX_PORT_MSG_LENGTH (CFE_MISSION_EVS_MAX_MESSAGE_LENGTH + OS_MAX_API_NAME + 30) +#define CFE_EVS_MAX_PORT_MSG_LENGTH (CFE_MISSION_EVS_MAX_MESSAGE_LENGTH + OS_MAX_API_NAME + 19) /* Since CFE_EVS_MAX_PORT_MSG_LENGTH is the size of the buffer that is sent to * print out (using OS_printf), we need to check to make sure that the buffer - * size the OS uses is big enough. This check has to be made here because it is - * the first spot after CFE_EVS_MAX_PORT_MSG_LENGTH is defined */ -#if OS_BUFFER_SIZE < CFE_EVS_MAX_PORT_MSG_LENGTH -#error CFE_EVS_MAX_PORT_MSG_LENGTH cannot be greater than OS_BUFFER_SIZE! + * size the OS uses is big enough. The buffer needs to have at least 11 extra + * characters to accommodate the format string "EVS Port%u %s\n" used in + * downstream processing for sending messages via ports. This check has to be + * made here because it is the first spot after CFE_EVS_MAX_PORT_MSG_LENGTH + * is defined. */ +#if OS_BUFFER_SIZE < CFE_EVS_MAX_PORT_MSG_LENGTH + 11 +#error CFE_EVS_MAX_PORT_MSG_LENGTH cannot be greater than OS_BUFFER_SIZE - 11! #endif /************************ Internal Structure Definitions *****************************/ diff --git a/modules/evs/fsw/src/cfe_evs_utils.c b/modules/evs/fsw/src/cfe_evs_utils.c index 03a39a95a..db3afd915 100644 --- a/modules/evs/fsw/src/cfe_evs_utils.c +++ b/modules/evs/fsw/src/cfe_evs_utils.c @@ -545,6 +545,7 @@ void EVS_SendViaPorts(CFE_EVS_LongEventTlm_t *EVS_PktPtr) CFE_MSG_GetMsgTime(CFE_MSG_PTR(EVS_PktPtr->TelemetryHeader), &PktTime); CFE_TIME_Print(TimeBuffer, PktTime); + /* SAD: No need to check snprintf return; CFE_EVS_MAX_PORT_MSG_LENGTH is sized to accommodate buffer limits */ snprintf(PortMessage, sizeof(PortMessage), "%s %u/%u/%s %u: %s", TimeBuffer, (unsigned int)EVS_PktPtr->Payload.PacketID.SpacecraftID, (unsigned int)EVS_PktPtr->Payload.PacketID.ProcessorID, EVS_PktPtr->Payload.PacketID.AppName, diff --git a/modules/evs/ut-coverage/evs_UT.c b/modules/evs/ut-coverage/evs_UT.c index fa42ae1ea..709a6e222 100644 --- a/modules/evs/ut-coverage/evs_UT.c +++ b/modules/evs/ut-coverage/evs_UT.c @@ -172,7 +172,7 @@ static int32 UT_EVS_MSGInitHook(void *UserObj, int32 StubRetcode, uint32 CallCou return StubRetcode; } -static void UT_EVS_DoDispatchCheckEvents_Impl(void *MsgPtr, uint32 MsgSize, UT_TaskPipeDispatchId_t DispatchId, +static void UT_EVS_DoDispatchCheckEvents_Impl(void *MsgPtr, size_t MsgSize, UT_TaskPipeDispatchId_t DispatchId, const UT_SoftwareBusSnapshot_Entry_t *SnapshotCfg, UT_EVS_EventCapture_t * EventCapture) { @@ -189,13 +189,13 @@ static void UT_EVS_DoDispatchCheckEvents_Impl(void *MsgPtr, uint32 MsgSize, UT_T UT_SetHookFunction(UT_KEY(CFE_SB_TransmitMsg), NULL, NULL); } -static void UT_EVS_DoDispatchCheckEvents(void *MsgPtr, uint32 MsgSize, UT_TaskPipeDispatchId_t DispatchId, +static void UT_EVS_DoDispatchCheckEvents(void *MsgPtr, size_t MsgSize, UT_TaskPipeDispatchId_t DispatchId, UT_EVS_EventCapture_t *EventCapture) { UT_EVS_DoDispatchCheckEvents_Impl(MsgPtr, MsgSize, DispatchId, &UT_EVS_LONGFMT_SNAPSHOTDATA, EventCapture); } -static void UT_EVS_DoDispatchCheckEventsShort(void *MsgPtr, uint32 MsgSize, UT_TaskPipeDispatchId_t DispatchId, +static void UT_EVS_DoDispatchCheckEventsShort(void *MsgPtr, size_t MsgSize, UT_TaskPipeDispatchId_t DispatchId, UT_EVS_EventCapture_t *EventCapture) { UT_EVS_DoDispatchCheckEvents_Impl(MsgPtr, MsgSize, DispatchId, &UT_EVS_SHORTFMT_SNAPSHOTDATA, EventCapture); diff --git a/modules/fs/config/default_cfe_fs_mission_cfg.h b/modules/fs/config/default_cfe_fs_mission_cfg.h index 23a583325..fde2f7ac0 100644 --- a/modules/fs/config/default_cfe_fs_mission_cfg.h +++ b/modules/fs/config/default_cfe_fs_mission_cfg.h @@ -24,7 +24,7 @@ * This is a compatibility header for the "mission_cfg.h" file that has * traditionally provided public config definitions for each CFS app. * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ diff --git a/modules/fs/fsw/src/cfe_fs_api.c b/modules/fs/fsw/src/cfe_fs_api.c index fbd0e54a0..40812f7b2 100644 --- a/modules/fs/fsw/src/cfe_fs_api.c +++ b/modules/fs/fsw/src/cfe_fs_api.c @@ -354,6 +354,7 @@ void CFE_FS_ByteSwapUint32(uint32 *Uint32ToSwapPtr) char *InPtr = (char *)&Temp; char *OutPtr = (char *)Uint32ToSwapPtr; + /* SAD: Safe access to InPtr[0-3] and OutPtr[0-3] as both manipulate bytes within 4-byte integers. */ OutPtr[0] = InPtr[3]; OutPtr[1] = InPtr[2]; OutPtr[2] = InPtr[1]; diff --git a/modules/resourceid/fsw/inc/cfe_core_resourceid_basevalues.h b/modules/resourceid/fsw/inc/cfe_core_resourceid_basevalues.h index 3c851430b..a2011ba51 100644 --- a/modules/resourceid/fsw/inc/cfe_core_resourceid_basevalues.h +++ b/modules/resourceid/fsw/inc/cfe_core_resourceid_basevalues.h @@ -70,6 +70,11 @@ 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, + CFE_RESOURCEID_TBL_DUMPCTRLID_BASE_OFFSET = OS_OBJECT_TYPE_USER + 9, + }; /* @@ -92,6 +97,11 @@ 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), + CFE_TBL_DUMPCTRLID_BASE = CFE_RESOURCEID_MAKE_BASE(CFE_RESOURCEID_TBL_DUMPCTRLID_BASE_OFFSET), + }; /** @} */ diff --git a/modules/sb/config/default_cfe_sb_fcncodes.h b/modules/sb/config/default_cfe_sb_fcncodes.h index 87c17fd65..8f25585c4 100644 --- a/modules/sb/config/default_cfe_sb_fcncodes.h +++ b/modules/sb/config/default_cfe_sb_fcncodes.h @@ -11,7 +11,7 @@ * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTISB OR CONDITIONS OF ANY KIND, either express or implied. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ************************************************************************/ diff --git a/modules/sb/config/default_cfe_sb_interface_cfg.h b/modules/sb/config/default_cfe_sb_interface_cfg.h index 359f5f415..4d766dcbf 100644 --- a/modules/sb/config/default_cfe_sb_interface_cfg.h +++ b/modules/sb/config/default_cfe_sb_interface_cfg.h @@ -11,7 +11,7 @@ * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTISB OR CONDITIONS OF ANY KIND, either express or implied. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ************************************************************************/ @@ -25,7 +25,7 @@ * interface, tables definitions, and any other data products that * serve to exchange information with other entities. * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ diff --git a/modules/sb/config/default_cfe_sb_internal_cfg.h b/modules/sb/config/default_cfe_sb_internal_cfg.h index ef34dd381..c02046c05 100644 --- a/modules/sb/config/default_cfe_sb_internal_cfg.h +++ b/modules/sb/config/default_cfe_sb_internal_cfg.h @@ -11,7 +11,7 @@ * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTISB OR CONDITIONS OF ANY KIND, either express or implied. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ************************************************************************/ @@ -25,7 +25,7 @@ * to items in this file only affect the local module and will be transparent * to external entities that are using the public interface(s). * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ @@ -134,8 +134,7 @@ ** this value is set the same across all mission platforms to avoid this complexity. ** ** \par Limits -** CFE_SB_INVALID_MSG is set to the maximum representable number of type CFE_SB_MsgId_t. -** CFE_PLATFORM_SB_HIGHEST_VALID_MSGID lower limit is 1, up to CFE_SB_INVALID_MSG_ID - 1. +** This parameter has a lower limit is 1, and an upper limit of 0xFFFFFFFE. ** ** When using the direct message map implementation for software bus routing, this ** value is used to size the map where a value of 0x1FFF results in a 16 KBytes map diff --git a/modules/sb/config/default_cfe_sb_mission_cfg.h b/modules/sb/config/default_cfe_sb_mission_cfg.h index cbe188ae7..69e2b1b42 100644 --- a/modules/sb/config/default_cfe_sb_mission_cfg.h +++ b/modules/sb/config/default_cfe_sb_mission_cfg.h @@ -11,7 +11,7 @@ * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTISB OR CONDITIONS OF ANY KIND, either express or implied. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ************************************************************************/ @@ -24,7 +24,7 @@ * This is a compatibility header for the "mission_cfg.h" file that has * traditionally provided public config definitions for each CFS app. * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ diff --git a/modules/sb/config/default_cfe_sb_msg.h b/modules/sb/config/default_cfe_sb_msg.h index 607374a78..01ad0f4a7 100644 --- a/modules/sb/config/default_cfe_sb_msg.h +++ b/modules/sb/config/default_cfe_sb_msg.h @@ -11,7 +11,7 @@ * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTISB OR CONDITIONS OF ANY KIND, either express or implied. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ************************************************************************/ @@ -24,7 +24,7 @@ * This is a compatibility header for the "cfe_sb_msg.h" file that has * traditionally provided the message definitions for cFS apps. * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ diff --git a/modules/sb/config/default_cfe_sb_msgdefs.h b/modules/sb/config/default_cfe_sb_msgdefs.h index 97d452b62..0e2d61fea 100644 --- a/modules/sb/config/default_cfe_sb_msgdefs.h +++ b/modules/sb/config/default_cfe_sb_msgdefs.h @@ -11,7 +11,7 @@ * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTISB OR CONDITIONS OF ANY KIND, either express or implied. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ************************************************************************/ diff --git a/modules/sb/config/default_cfe_sb_msgids.h b/modules/sb/config/default_cfe_sb_msgids.h index 338684d62..ea67cc143 100644 --- a/modules/sb/config/default_cfe_sb_msgids.h +++ b/modules/sb/config/default_cfe_sb_msgids.h @@ -11,7 +11,7 @@ * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTISB OR CONDITIONS OF ANY KIND, either express or implied. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ************************************************************************/ diff --git a/modules/sb/config/default_cfe_sb_msgstruct.h b/modules/sb/config/default_cfe_sb_msgstruct.h index 1b3d9a005..a1866afc4 100644 --- a/modules/sb/config/default_cfe_sb_msgstruct.h +++ b/modules/sb/config/default_cfe_sb_msgstruct.h @@ -11,7 +11,7 @@ * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTISB OR CONDITIONS OF ANY KIND, either express or implied. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ************************************************************************/ diff --git a/modules/sb/config/default_cfe_sb_platform_cfg.h b/modules/sb/config/default_cfe_sb_platform_cfg.h index 50cbbe905..6c999f6a6 100644 --- a/modules/sb/config/default_cfe_sb_platform_cfg.h +++ b/modules/sb/config/default_cfe_sb_platform_cfg.h @@ -11,7 +11,7 @@ * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTISB OR CONDITIONS OF ANY KIND, either express or implied. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ************************************************************************/ @@ -28,7 +28,7 @@ * These definitions are now provided in two separate files, one for * the public/mission scope and one for internal scope. * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ diff --git a/modules/sb/config/default_cfe_sb_topicids.h b/modules/sb/config/default_cfe_sb_topicids.h index 1009385ca..486498bfe 100644 --- a/modules/sb/config/default_cfe_sb_topicids.h +++ b/modules/sb/config/default_cfe_sb_topicids.h @@ -11,7 +11,7 @@ * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTISB OR CONDITIONS OF ANY KIND, either express or implied. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ************************************************************************/ diff --git a/modules/sb/fsw/src/cfe_sb_api.c b/modules/sb/fsw/src/cfe_sb_api.c index bc4280ece..2eb3eedee 100644 --- a/modules/sb/fsw/src/cfe_sb_api.c +++ b/modules/sb/fsw/src/cfe_sb_api.c @@ -161,12 +161,7 @@ CFE_Status_t CFE_SB_CreatePipe(CFE_SB_PipeId_t *PipeIdPtr, uint16 Depth, const c { /* create the queue */ OsStatus = OS_QueueCreate(&SysQueueId, PipeName, Depth, sizeof(CFE_SB_BufferD_t *), 0); - if (OsStatus == OS_SUCCESS) - { - /* just translate the RC to CFE */ - Status = CFE_SUCCESS; - } - else + if (OsStatus != OS_SUCCESS) { if (OsStatus == OS_ERR_NAME_TAKEN) { @@ -225,6 +220,40 @@ CFE_Status_t CFE_SB_CreatePipe(CFE_SB_PipeId_t *PipeIdPtr, uint16 Depth, const c CFE_SB_UnlockSharedData(__func__, __LINE__); /* Send any pending events now, after final unlock */ + switch (PendingEventId) + { + case CFE_SB_CR_PIPE_BAD_ARG_EID: + CFE_EVS_SendEventWithAppID(CFE_SB_CR_PIPE_BAD_ARG_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, + "CreatePipeErr:Bad Input Arg:app=%s,ptr=0x%lx,depth=%d,maxdepth=%d", + CFE_SB_GetAppTskName(TskId, FullName), (unsigned long)PipeIdPtr, (int)Depth, + OS_QUEUE_MAX_DEPTH); + break; + + case CFE_SB_MAX_PIPES_MET_EID: + CFE_EVS_SendEventWithAppID(CFE_SB_MAX_PIPES_MET_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, + "CreatePipeErr:Max Pipes(%d)In Use.app %s", CFE_PLATFORM_SB_MAX_PIPES, + CFE_SB_GetAppTskName(TskId, FullName)); + break; + case CFE_SB_CR_PIPE_NAME_TAKEN_EID: + CFE_EVS_SendEventWithAppID(CFE_SB_CR_PIPE_NAME_TAKEN_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, + "CreatePipeErr:OS_QueueCreate failed, name taken (app=%s, name=%s)", + CFE_SB_GetAppTskName(TskId, FullName), PipeName); + break; + case CFE_SB_CR_PIPE_NO_FREE_EID: + CFE_EVS_SendEventWithAppID(CFE_SB_CR_PIPE_NO_FREE_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, + "CreatePipeErr:OS_QueueCreate failed, no free id's (app=%s)", + CFE_SB_GetAppTskName(TskId, FullName)); + break; + case CFE_SB_CR_PIPE_ERR_EID: + CFE_EVS_SendEventWithAppID(CFE_SB_CR_PIPE_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, + "CreatePipeErr:OS_QueueCreate returned %ld,app %s", (long)OsStatus, + CFE_SB_GetAppTskName(TskId, FullName)); + break; + + default: + break; + } + if (Status == CFE_SUCCESS) { /* send debug event */ @@ -235,39 +264,6 @@ CFE_Status_t CFE_SB_CreatePipe(CFE_SB_PipeId_t *PipeIdPtr, uint16 Depth, const c /* give the pipe handle to the caller */ *PipeIdPtr = CFE_SB_PIPEID_C(PendingPipeId); } - else - { - switch (PendingEventId) - { - case CFE_SB_CR_PIPE_BAD_ARG_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_CR_PIPE_BAD_ARG_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "CreatePipeErr:Bad Input Arg:app=%s,ptr=0x%lx,depth=%d,maxdepth=%d", - CFE_SB_GetAppTskName(TskId, FullName), (unsigned long)PipeIdPtr, (int)Depth, - OS_QUEUE_MAX_DEPTH); - break; - - case CFE_SB_MAX_PIPES_MET_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_MAX_PIPES_MET_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "CreatePipeErr:Max Pipes(%d)In Use.app %s", CFE_PLATFORM_SB_MAX_PIPES, - CFE_SB_GetAppTskName(TskId, FullName)); - break; - case CFE_SB_CR_PIPE_NAME_TAKEN_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_CR_PIPE_NAME_TAKEN_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "CreatePipeErr:OS_QueueCreate failed, name taken (app=%s, name=%s)", - CFE_SB_GetAppTskName(TskId, FullName), PipeName); - break; - case CFE_SB_CR_PIPE_NO_FREE_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_CR_PIPE_NO_FREE_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "CreatePipeErr:OS_QueueCreate failed, no free id's (app=%s)", - CFE_SB_GetAppTskName(TskId, FullName)); - break; - case CFE_SB_CR_PIPE_ERR_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_CR_PIPE_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "CreatePipeErr:OS_QueueCreate returned %ld,app %s", (long)OsStatus, - CFE_SB_GetAppTskName(TskId, FullName)); - break; - } - } return Status; } @@ -431,13 +427,43 @@ int32 CFE_SB_DeletePipeFull(CFE_SB_PipeId_t PipeId, CFE_ES_AppId_t AppId) CFE_SB_PipeDescSetFree(PipeDscPtr); --CFE_SB_Global.StatTlmMsg.Payload.PipesInUse; } - else if (PendingEventID != 0) + else { CFE_SB_Global.HKTlmMsg.Payload.CreatePipeErrorCounter++; } CFE_SB_UnlockSharedData(__func__, __LINE__); + /* Send Events */ + if (PendingEventID != 0) + { + /* get TaskId and name of caller for events */ + CFE_ES_GetTaskID(&TskId); + CFE_SB_GetAppTskName(TskId, FullName); + } + else + { + TskId = CFE_ES_TASKID_UNDEFINED; + FullName[0] = 0; + } + + switch (PendingEventID) + { + case CFE_SB_DEL_PIPE_ERR1_EID: + CFE_EVS_SendEventWithAppID(CFE_SB_DEL_PIPE_ERR1_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, + "Pipe Delete Error:Bad Argument,PipedId %ld,Requestor %s", + CFE_RESOURCEID_TO_ULONG(PipeId), FullName); + break; + case CFE_SB_DEL_PIPE_ERR2_EID: + CFE_EVS_SendEventWithAppID(CFE_SB_DEL_PIPE_ERR2_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, + "Pipe Delete Error:Caller(%s) is not the owner of pipe %ld", FullName, + CFE_RESOURCEID_TO_ULONG(PipeId)); + break; + + default: + break; + } + if (Status == CFE_SUCCESS) { /* @@ -451,26 +477,6 @@ int32 CFE_SB_DeletePipeFull(CFE_SB_PipeId_t PipeId, CFE_ES_AppId_t AppId) CFE_EVS_SendEventWithAppID(CFE_SB_PIPE_DELETED_EID, CFE_EVS_EventType_DEBUG, CFE_SB_Global.AppId, "Pipe Deleted:id %d,owner %s", (int)CFE_RESOURCEID_TO_ULONG(PipeId), FullName); } - else - { - /* get TaskId and name of caller for events */ - CFE_ES_GetTaskID(&TskId); - CFE_SB_GetAppTskName(TskId, FullName); - - switch (PendingEventID) - { - case CFE_SB_DEL_PIPE_ERR1_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_DEL_PIPE_ERR1_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "Pipe Delete Error:Bad Argument,PipedId %ld,Requestor %s", - CFE_RESOURCEID_TO_ULONG(PipeId), FullName); - break; - case CFE_SB_DEL_PIPE_ERR2_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_DEL_PIPE_ERR2_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "Pipe Delete Error:Caller(%s) is not the owner of pipe %ld", FullName, - CFE_RESOURCEID_TO_ULONG(PipeId)); - break; - } - } return Status; } @@ -528,7 +534,34 @@ CFE_Status_t CFE_SB_SetPipeOpts(CFE_SB_PipeId_t PipeId, uint8 Opts) CFE_SB_UnlockSharedData(__func__, __LINE__); - /* Send events after unlocking SB */ + /* Send Events */ + if (PendingEventID != 0) + { + /* get TaskId of caller for events */ + CFE_ES_GetTaskID(&TskId); + } + else + { + TskId = CFE_ES_TASKID_UNDEFINED; + } + + switch (PendingEventID) + { + case CFE_SB_SETPIPEOPTS_ID_ERR_EID: + CFE_EVS_SendEventWithAppID(CFE_SB_SETPIPEOPTS_ID_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, + "Pipe Opts Error:Bad Argument,PipedId %lu,Requestor %s", + CFE_RESOURCEID_TO_ULONG(PipeId), CFE_SB_GetAppTskName(TskId, FullName)); + break; + case CFE_SB_SETPIPEOPTS_OWNER_ERR_EID: + CFE_EVS_SendEventWithAppID(CFE_SB_SETPIPEOPTS_OWNER_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, + "Pipe Opts Set Error: Caller(%s) is not the owner of pipe %lu", + CFE_SB_GetAppTskName(TskId, FullName), CFE_RESOURCEID_TO_ULONG(PipeId)); + break; + + default: + break; + } + if (Status == CFE_SUCCESS) { /* get AppID of caller for events */ @@ -538,26 +571,6 @@ CFE_Status_t CFE_SB_SetPipeOpts(CFE_SB_PipeId_t PipeId, uint8 Opts) "Pipe opts set:id %lu,owner %s, opts=0x%02x", CFE_RESOURCEID_TO_ULONG(PipeId), FullName, (unsigned int)Opts); } - else - { - /* get TaskId of caller for events */ - CFE_ES_GetTaskID(&TskId); - - switch (PendingEventID) - { - case CFE_SB_SETPIPEOPTS_ID_ERR_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_SETPIPEOPTS_ID_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "Pipe Opts Error:Bad Argument,PipedId %lu,Requestor %s", - CFE_RESOURCEID_TO_ULONG(PipeId), CFE_SB_GetAppTskName(TskId, FullName)); - break; - case CFE_SB_SETPIPEOPTS_OWNER_ERR_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_SETPIPEOPTS_OWNER_ERR_EID, CFE_EVS_EventType_ERROR, - CFE_SB_Global.AppId, - "Pipe Opts Set Error: Caller(%s) is not the owner of pipe %lu", - CFE_SB_GetAppTskName(TskId, FullName), CFE_RESOURCEID_TO_ULONG(PipeId)); - break; - } - } return Status; } @@ -607,31 +620,38 @@ CFE_Status_t CFE_SB_GetPipeOpts(CFE_SB_PipeId_t PipeId, uint8 *OptsPtr) CFE_SB_UnlockSharedData(__func__, __LINE__); - /* Send events after unlocking SB */ - if (Status == CFE_SUCCESS) + /* Send Events */ + if (PendingEventID != 0) { - CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPEOPTS_EID, CFE_EVS_EventType_DEBUG, CFE_SB_Global.AppId, - "Pipe opts get:id %lu, opts=0x%02x", CFE_RESOURCEID_TO_ULONG(PipeId), - (unsigned int)*OptsPtr); + /* get TaskId of caller for events */ + CFE_ES_GetTaskID(&TskId); } else { - /* get TaskId of caller for events */ - CFE_ES_GetTaskID(&TskId); + TskId = CFE_ES_TASKID_UNDEFINED; + } - switch (PendingEventID) - { - case CFE_SB_GETPIPEOPTS_PTR_ERR_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPEOPTS_PTR_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "Pipe Opts Error:Bad Argument,Requestor %s", - CFE_SB_GetAppTskName(TskId, FullName)); - break; - case CFE_SB_GETPIPEOPTS_ID_ERR_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPEOPTS_ID_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "Pipe Opts Error:Bad Argument,PipedId %lu,Requestor %s", - CFE_RESOURCEID_TO_ULONG(PipeId), CFE_SB_GetAppTskName(TskId, FullName)); - break; - } + switch (PendingEventID) + { + case CFE_SB_GETPIPEOPTS_PTR_ERR_EID: + CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPEOPTS_PTR_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, + "Pipe Opts Error:Bad Argument,Requestor %s", + CFE_SB_GetAppTskName(TskId, FullName)); + break; + case CFE_SB_GETPIPEOPTS_ID_ERR_EID: + CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPEOPTS_ID_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, + "Pipe Opts Error:Bad Argument,PipedId %lu,Requestor %s", + CFE_RESOURCEID_TO_ULONG(PipeId), CFE_SB_GetAppTskName(TskId, FullName)); + break; + default: + break; + } + + if (Status == CFE_SUCCESS) + { + CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPEOPTS_EID, CFE_EVS_EventType_DEBUG, CFE_SB_Global.AppId, + "Pipe opts get:id %lu, opts=0x%02x", CFE_RESOURCEID_TO_ULONG(PipeId), + (unsigned int)*OptsPtr); } return Status; @@ -698,6 +718,33 @@ CFE_Status_t CFE_SB_GetPipeName(char *PipeNameBuf, size_t PipeNameSize, CFE_SB_P } /* Send Events */ + if (PendingEventID != 0) + { + /* get TaskId of caller for events */ + CFE_ES_GetTaskID(&TskId); + } + else + { + TskId = CFE_ES_TASKID_UNDEFINED; + } + + switch (PendingEventID) + { + case CFE_SB_GETPIPENAME_NULL_PTR_EID: + CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPENAME_NULL_PTR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, + "Pipe Name Error:NullPtr,Requestor %s", CFE_SB_GetAppTskName(TskId, FullName)); + break; + + case CFE_SB_GETPIPENAME_ID_ERR_EID: + CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPENAME_ID_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, + "Pipe Id Error:Bad Argument,Id=%lu,Requestor %s", + CFE_RESOURCEID_TO_ULONG(PipeId), CFE_SB_GetAppTskName(TskId, FullName)); + break; + + default: + break; + } + if (Status == CFE_SUCCESS) { CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPENAME_EID, CFE_EVS_EventType_DEBUG, CFE_SB_Global.AppId, @@ -705,22 +752,6 @@ CFE_Status_t CFE_SB_GetPipeName(char *PipeNameBuf, size_t PipeNameSize, CFE_SB_P } else { - CFE_ES_GetTaskID(&TskId); - - switch (PendingEventID) - { - case CFE_SB_GETPIPENAME_NULL_PTR_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPENAME_NULL_PTR_EID, CFE_EVS_EventType_ERROR, - CFE_SB_Global.AppId, "Pipe Name Error:NullPtr,Requestor %s", - CFE_SB_GetAppTskName(TskId, FullName)); - break; - case CFE_SB_GETPIPENAME_ID_ERR_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPENAME_ID_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "Pipe Id Error:Bad Argument,Id=%lu,Requestor %s", - CFE_RESOURCEID_TO_ULONG(PipeId), CFE_SB_GetAppTskName(TskId, FullName)); - break; - } - if (PipeNameBuf != NULL && PipeNameSize > 0) { memset(PipeNameBuf, 0, PipeNameSize); @@ -805,30 +836,38 @@ CFE_Status_t CFE_SB_GetPipeIdByName(CFE_SB_PipeId_t *PipeIdPtr, const char *Pipe CFE_SB_UnlockSharedData(__func__, __LINE__); /* Send Events */ - if (Status == CFE_SUCCESS) + if (PendingEventID != 0) { - CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPEIDBYNAME_EID, CFE_EVS_EventType_DEBUG, CFE_SB_Global.AppId, - "PipeIdByName name=%s id=%lu", PipeName, CFE_RESOURCEID_TO_ULONG(*PipeIdPtr)); + /* get TaskId of caller for events */ + CFE_ES_GetTaskID(&TskId); } else { - /* get TaskId of caller for events */ - CFE_ES_GetTaskID(&TskId); + TskId = CFE_ES_TASKID_UNDEFINED; + } - switch (PendingEventID) - { - case CFE_SB_GETPIPEIDBYNAME_NULL_ERR_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPEIDBYNAME_NULL_ERR_EID, CFE_EVS_EventType_ERROR, - CFE_SB_Global.AppId, "Pipe ID By Name Error:Bad Argument,Requestor %s", - CFE_SB_GetAppTskName(TskId, FullName)); - break; + switch (PendingEventID) + { + case CFE_SB_GETPIPEIDBYNAME_NULL_ERR_EID: + CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPEIDBYNAME_NULL_ERR_EID, CFE_EVS_EventType_ERROR, + CFE_SB_Global.AppId, "Pipe ID By Name Error:Bad Argument,Requestor %s", + CFE_SB_GetAppTskName(TskId, FullName)); + break; - case CFE_SB_GETPIPEIDBYNAME_NAME_ERR_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPEIDBYNAME_NAME_ERR_EID, CFE_EVS_EventType_ERROR, - CFE_SB_Global.AppId, "Pipe ID By Name Error:Bad Argument,Requestor %s", - CFE_SB_GetAppTskName(TskId, FullName)); - break; - } + case CFE_SB_GETPIPEIDBYNAME_NAME_ERR_EID: + CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPEIDBYNAME_NAME_ERR_EID, CFE_EVS_EventType_ERROR, + CFE_SB_Global.AppId, "Pipe ID By Name Error:Bad Argument,Requestor %s", + CFE_SB_GetAppTskName(TskId, FullName)); + break; + + default: + break; + } + + if (Status == CFE_SUCCESS) + { + CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPEIDBYNAME_EID, CFE_EVS_EventType_DEBUG, CFE_SB_Global.AppId, + "PipeIdByName name=%s id=%lu", PipeName, CFE_RESOURCEID_TO_ULONG(*PipeIdPtr)); } return Status; @@ -1027,65 +1066,73 @@ int32 CFE_SB_SubscribeFull(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId, CFE_SB_ CFE_SB_UnlockSharedData(__func__, __LINE__); - /* Send events now */ + /* Send events now - get the pipe name only if something is pending */ if (PendingEventID != 0) { CFE_SB_GetPipeName(PipeName, sizeof(PipeName), PipeId); + } + else + { + PipeName[0] = 0; /* make empty string */ + } - switch (PendingEventID) - { - case CFE_SB_DUP_SUBSCRIP_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_DUP_SUBSCRIP_EID, CFE_EVS_EventType_INFORMATION, CFE_SB_Global.AppId, - "Duplicate Subscription,MsgId 0x%x on %s pipe,app %s", - (unsigned int)CFE_SB_MsgIdToValue(MsgId), PipeName, - CFE_SB_GetAppTskName(TskId, FullName)); - break; + switch (PendingEventID) + { + case CFE_SB_DUP_SUBSCRIP_EID: + CFE_EVS_SendEventWithAppID(CFE_SB_DUP_SUBSCRIP_EID, CFE_EVS_EventType_INFORMATION, CFE_SB_Global.AppId, + "Duplicate Subscription,MsgId 0x%x on %s pipe,app %s", + (unsigned int)CFE_SB_MsgIdToValue(MsgId), PipeName, + CFE_SB_GetAppTskName(TskId, FullName)); + break; - case CFE_SB_SUB_INV_CALLER_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_SUB_INV_CALLER_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "Subscribe Err:Caller(%s) is not the owner of pipe %lu,Msg=0x%x", - CFE_SB_GetAppTskName(TskId, FullName), CFE_RESOURCEID_TO_ULONG(PipeId), - (unsigned int)CFE_SB_MsgIdToValue(MsgId)); - break; + case CFE_SB_SUB_INV_CALLER_EID: + CFE_EVS_SendEventWithAppID(CFE_SB_SUB_INV_CALLER_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, + "Subscribe Err:Caller(%s) is not the owner of pipe %lu,Msg=0x%x", + CFE_SB_GetAppTskName(TskId, FullName), CFE_RESOURCEID_TO_ULONG(PipeId), + (unsigned int)CFE_SB_MsgIdToValue(MsgId)); + break; - case CFE_SB_SUB_INV_PIPE_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_SUB_INV_PIPE_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "Subscribe Err:Invalid Pipe Id,Msg=0x%x,PipeId=%lu,App %s", - (unsigned int)CFE_SB_MsgIdToValue(MsgId), CFE_RESOURCEID_TO_ULONG(PipeId), - CFE_SB_GetAppTskName(TskId, FullName)); - break; + case CFE_SB_SUB_INV_PIPE_EID: + CFE_EVS_SendEventWithAppID(CFE_SB_SUB_INV_PIPE_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, + "Subscribe Err:Invalid Pipe Id,Msg=0x%x,PipeId=%lu,App %s", + (unsigned int)CFE_SB_MsgIdToValue(MsgId), CFE_RESOURCEID_TO_ULONG(PipeId), + CFE_SB_GetAppTskName(TskId, FullName)); + break; - case CFE_SB_DEST_BLK_ERR_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_DEST_BLK_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "Subscribe Err:Request for Destination Blk failed for Msg 0x%x", - (unsigned int)CFE_SB_MsgIdToValue(MsgId)); - break; + case CFE_SB_DEST_BLK_ERR_EID: + CFE_EVS_SendEventWithAppID(CFE_SB_DEST_BLK_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, + "Subscribe Err:Request for Destination Blk failed for Msg 0x%x", + (unsigned int)CFE_SB_MsgIdToValue(MsgId)); + break; - case CFE_SB_MAX_DESTS_MET_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_MAX_DESTS_MET_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "Subscribe Err:Max Dests(%d)In Use For Msg 0x%x,pipe %s,app %s", - CFE_PLATFORM_SB_MAX_DEST_PER_PKT, (unsigned int)CFE_SB_MsgIdToValue(MsgId), - PipeName, CFE_SB_GetAppTskName(TskId, FullName)); - break; + case CFE_SB_MAX_DESTS_MET_EID: + CFE_EVS_SendEventWithAppID(CFE_SB_MAX_DESTS_MET_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, + "Subscribe Err:Max Dests(%d)In Use For Msg 0x%x,pipe %s,app %s", + CFE_PLATFORM_SB_MAX_DEST_PER_PKT, (unsigned int)CFE_SB_MsgIdToValue(MsgId), + PipeName, CFE_SB_GetAppTskName(TskId, FullName)); + break; - case CFE_SB_MAX_MSGS_MET_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_MAX_MSGS_MET_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "Subscribe Err:Max Msgs(%d)In Use,MsgId 0x%x,pipe %s,app %s", - CFE_PLATFORM_SB_MAX_MSG_IDS, (unsigned int)CFE_SB_MsgIdToValue(MsgId), - PipeName, CFE_SB_GetAppTskName(TskId, FullName)); - break; + case CFE_SB_MAX_MSGS_MET_EID: + CFE_EVS_SendEventWithAppID(CFE_SB_MAX_MSGS_MET_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, + "Subscribe Err:Max Msgs(%d)In Use,MsgId 0x%x,pipe %s,app %s", + CFE_PLATFORM_SB_MAX_MSG_IDS, (unsigned int)CFE_SB_MsgIdToValue(MsgId), PipeName, + CFE_SB_GetAppTskName(TskId, FullName)); + break; - case CFE_SB_SUB_ARG_ERR_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_SUB_ARG_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "Subscribe Err:Bad Arg,MsgId 0x%x,PipeId %lu,app %s,scope %d", - (unsigned int)CFE_SB_MsgIdToValue(MsgId), CFE_RESOURCEID_TO_ULONG(PipeId), - CFE_SB_GetAppTskName(TskId, FullName), Scope); - break; - } + case CFE_SB_SUB_ARG_ERR_EID: + CFE_EVS_SendEventWithAppID(CFE_SB_SUB_ARG_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, + "Subscribe Err:Bad Arg,MsgId 0x%x,PipeId %lu,app %s,scope %d", + (unsigned int)CFE_SB_MsgIdToValue(MsgId), CFE_RESOURCEID_TO_ULONG(PipeId), + CFE_SB_GetAppTskName(TskId, FullName), Scope); + break; + + default: + break; } - else if (Status == CFE_SUCCESS) + + /* If no other event pending, send a debug event indicating success */ + if (Status == CFE_SUCCESS && PendingEventID == 0) { - /* If no other event pending, send a debug event indicating success */ CFE_EVS_SendEventWithAppID(CFE_SB_SUBSCRIPTION_RCVD_EID, CFE_EVS_EventType_DEBUG, CFE_SB_Global.AppId, "Subscription Rcvd:MsgId 0x%x on PipeId %lu,app %s", (unsigned int)CFE_SB_MsgIdToValue(MsgId), CFE_RESOURCEID_TO_ULONG(PipeId), @@ -1236,43 +1283,44 @@ int32 CFE_SB_UnsubscribeFull(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId, uint8 CFE_SB_UnlockSharedData(__func__, __LINE__); - if (PendingEventID != 0) + switch (PendingEventID) { - switch (PendingEventID) - { - case CFE_SB_UNSUB_NO_SUBS_EID: - CFE_SB_GetPipeName(PipeName, sizeof(PipeName), PipeId); - CFE_EVS_SendEventWithAppID(CFE_SB_UNSUB_NO_SUBS_EID, CFE_EVS_EventType_INFORMATION, CFE_SB_Global.AppId, - "Unsubscribe Err:No subs for Msg 0x%x on %s,app %s", - (unsigned int)CFE_SB_MsgIdToValue(MsgId), PipeName, - CFE_SB_GetAppTskName(TskId, FullName)); - break; + case CFE_SB_UNSUB_NO_SUBS_EID: + CFE_SB_GetPipeName(PipeName, sizeof(PipeName), PipeId); + CFE_EVS_SendEventWithAppID(CFE_SB_UNSUB_NO_SUBS_EID, CFE_EVS_EventType_INFORMATION, CFE_SB_Global.AppId, + "Unsubscribe Err:No subs for Msg 0x%x on %s,app %s", + (unsigned int)CFE_SB_MsgIdToValue(MsgId), PipeName, + CFE_SB_GetAppTskName(TskId, FullName)); + break; - case CFE_SB_UNSUB_INV_PIPE_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_UNSUB_INV_PIPE_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "Unsubscribe Err:Invalid Pipe Id Msg=0x%x,Pipe=%lu,app=%s", - (unsigned int)CFE_SB_MsgIdToValue(MsgId), CFE_RESOURCEID_TO_ULONG(PipeId), - CFE_SB_GetAppTskName(TskId, FullName)); - break; + case CFE_SB_UNSUB_INV_PIPE_EID: + CFE_EVS_SendEventWithAppID(CFE_SB_UNSUB_INV_PIPE_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, + "Unsubscribe Err:Invalid Pipe Id Msg=0x%x,Pipe=%lu,app=%s", + (unsigned int)CFE_SB_MsgIdToValue(MsgId), CFE_RESOURCEID_TO_ULONG(PipeId), + CFE_SB_GetAppTskName(TskId, FullName)); + break; - case CFE_SB_UNSUB_INV_CALLER_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_UNSUB_INV_CALLER_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "Unsubscribe Err:Caller(%s) is not the owner of pipe %lu,Msg=0x%x", - CFE_SB_GetAppTskName(TskId, FullName), CFE_RESOURCEID_TO_ULONG(PipeId), - (unsigned int)CFE_SB_MsgIdToValue(MsgId)); - break; + case CFE_SB_UNSUB_INV_CALLER_EID: + CFE_EVS_SendEventWithAppID(CFE_SB_UNSUB_INV_CALLER_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, + "Unsubscribe Err:Caller(%s) is not the owner of pipe %lu,Msg=0x%x", + CFE_SB_GetAppTskName(TskId, FullName), CFE_RESOURCEID_TO_ULONG(PipeId), + (unsigned int)CFE_SB_MsgIdToValue(MsgId)); + break; - case CFE_SB_UNSUB_ARG_ERR_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_UNSUB_ARG_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "Unsubscribe Err:Bad Arg,MsgId 0x%x,PipeId %lu,app %s,scope %d", - (unsigned int)CFE_SB_MsgIdToValue(MsgId), CFE_RESOURCEID_TO_ULONG(PipeId), - CFE_SB_GetAppTskName(TskId, FullName), (int)Scope); - break; - } + case CFE_SB_UNSUB_ARG_ERR_EID: + CFE_EVS_SendEventWithAppID(CFE_SB_UNSUB_ARG_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, + "Unsubscribe Err:Bad Arg,MsgId 0x%x,PipeId %lu,app %s,scope %d", + (unsigned int)CFE_SB_MsgIdToValue(MsgId), CFE_RESOURCEID_TO_ULONG(PipeId), + CFE_SB_GetAppTskName(TskId, FullName), (int)Scope); + break; + + default: + break; } - else if (Status == CFE_SUCCESS) + + /* if no other event pending, send a debug event for successful unsubscribe */ + if (Status == CFE_SUCCESS && PendingEventID == 0) { - /* if no other event pending, send a debug event for successful unsubscribe */ CFE_EVS_SendEventWithAppID(CFE_SB_SUBSCRIPTION_REMOVED_EID, CFE_EVS_EventType_DEBUG, CFE_SB_Global.AppId, "Subscription Removed:Msg 0x%x on pipe %lu,app %s", (unsigned int)CFE_SB_MsgIdToValue(MsgId), CFE_RESOURCEID_TO_ULONG(PipeId), @@ -1288,712 +1336,44 @@ int32 CFE_SB_UnsubscribeFull(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId, uint8 * See description in header file for argument/return detail * *-----------------------------------------------------------------*/ -CFE_Status_t CFE_SB_TransmitMsg(const CFE_MSG_Message_t *MsgPtr, bool IsOrigination) +CFE_Status_t CFE_SB_ReceiveBuffer(CFE_SB_Buffer_t **BufPtr, CFE_SB_PipeId_t PipeId, int32 TimeOut) { - int32 Status; - CFE_MSG_Size_t Size = 0; - CFE_SB_MsgId_t MsgId = CFE_SB_INVALID_MSG_ID; - CFE_ES_TaskId_t TskId; - char FullName[(OS_MAX_API_NAME * 2)]; - CFE_SB_BufferD_t *BufDscPtr; - CFE_SBR_RouteId_t RouteId; - uint16 PendingEventID; - - PendingEventID = 0; - BufDscPtr = NULL; - RouteId = CFE_SBR_INVALID_ROUTE_ID; - - Status = CFE_SB_TransmitMsgValidate(MsgPtr, &MsgId, &Size, &RouteId); - - CFE_SB_LockSharedData(__func__, __LINE__); + CFE_SB_ReceiveTxn_State_t TxnBuf; + CFE_SB_MessageTxn_State_t *Txn; - if (Status == CFE_SUCCESS && CFE_SBR_IsValidRouteId(RouteId)) - { - /* Get buffer - note this pre-initializes the returned buffer with - * a use count of 1, which refers to this task as it fills the buffer. */ - BufDscPtr = CFE_SB_GetBufferFromPool(Size); - if (BufDscPtr == NULL) - { - PendingEventID = CFE_SB_GET_BUF_ERR_EID; - Status = CFE_SB_BUF_ALOC_ERR; - } - } + Txn = CFE_SB_ReceiveTxn_Init(&TxnBuf, BufPtr); - /* - * Increment the MsgSendErrorCounter only if there was a real error, - * such as a validation issue or failure to allocate a buffer. - * - * (This should NOT be done if simply no route) - */ - if (Status != CFE_SUCCESS) + if (CFE_SB_MessageTxn_IsOK(Txn)) { - CFE_SB_Global.HKTlmMsg.Payload.MsgSendErrorCounter++; + CFE_SB_MessageTxn_SetTimeout(Txn, TimeOut); } - CFE_SB_UnlockSharedData(__func__, __LINE__); - - /* - * If a buffer was obtained above, then copy the content into it - * and broadcast it to all subscribers in the route. - * - * Note - if there is no route / no subscribers, the "Status" will - * be CFE_SUCCESS because CFE_SB_TransmitMsgValidate() succeeded, - * but there will be no buffer because CFE_SBR_IsValidRouteId() returned - * false. - * - * But if the descriptor is non-null it means the message is valid and - * there is a route to send it to. - */ - if (BufDscPtr != NULL) + if (CFE_SB_MessageTxn_IsOK(Txn)) { - /* Copy actual message content into buffer and set its metadata */ - memcpy(&BufDscPtr->Content, MsgPtr, Size); - BufDscPtr->MsgId = MsgId; - BufDscPtr->ContentSize = Size; - BufDscPtr->NeedsUpdate = IsOrigination; - CFE_MSG_GetType(MsgPtr, &BufDscPtr->ContentType); + CFE_SB_ReceiveTxn_SetPipeId(Txn, PipeId); /* - * This routine will use best-effort to send to all subscribers, - * increment the buffer use count for every successful delivery, - * and send an event/increment counter for any unsuccessful delivery. + * Set the verify flag true by default - + * in the default impl verify is a no-op that always succeeds. + * If an actual implementation is provided, it will be used here. */ - CFE_SB_BroadcastBufferToRoute(BufDscPtr, RouteId); + CFE_SB_MessageTxn_SetEndpoint(Txn, true); + } + if (BufPtr != NULL) + { /* - * The broadcast function consumes the buffer, so it should not be - * accessed in this function anymore + * Note - the API should qualify the parameter as "const", but this is + * kept non-const for backward compatibility. Callers should never write to + * the returned buffer, it is const in practice. */ - BufDscPtr = NULL; + *BufPtr = (CFE_SB_Buffer_t *)CFE_SB_ReceiveTxn_Execute(Txn); } - if (PendingEventID == CFE_SB_GET_BUF_ERR_EID) - { - /* Get task id for events and Sender Info*/ - CFE_ES_GetTaskID(&TskId); - - if (CFE_SB_RequestToSendEvent(TskId, CFE_SB_GET_BUF_ERR_EID_BIT) == CFE_SB_GRANTED) - { - CFE_EVS_SendEventWithAppID(CFE_SB_GET_BUF_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "Send Err:Request for Buffer Failed. MsgId 0x%x,app %s,size %d", - (unsigned int)CFE_SB_MsgIdToValue(MsgId), CFE_SB_GetAppTskName(TskId, FullName), - (int)Size); + CFE_SB_MessageTxn_ReportEvents(Txn); - /* clear the bit so the task may send this event again */ - CFE_SB_FinishSendEvent(TskId, CFE_SB_GET_BUF_ERR_EID_BIT); - } - } - - return Status; -} - -/*---------------------------------------------------------------- - * - * Application-scope internal function - * See description in header file for argument/return detail - * - *-----------------------------------------------------------------*/ -int32 CFE_SB_TransmitMsgValidate(const CFE_MSG_Message_t *MsgPtr, CFE_SB_MsgId_t *MsgIdPtr, CFE_MSG_Size_t *SizePtr, - CFE_SBR_RouteId_t *RouteIdPtr) -{ - CFE_ES_TaskId_t TskId; - char FullName[(OS_MAX_API_NAME * 2)]; - uint16 PendingEventID; - int32 Status; - - PendingEventID = 0; - Status = CFE_SUCCESS; - - /* check input parameter */ - if (MsgPtr == NULL) - { - PendingEventID = CFE_SB_SEND_BAD_ARG_EID; - Status = CFE_SB_BAD_ARGUMENT; - } - - if (Status == CFE_SUCCESS) - { - CFE_MSG_GetMsgId(MsgPtr, MsgIdPtr); - - /* validate the msgid in the message */ - if (!CFE_SB_IsValidMsgId(*MsgIdPtr)) - { - PendingEventID = CFE_SB_SEND_INV_MSGID_EID; - Status = CFE_SB_BAD_ARGUMENT; - } - } - - if (Status == CFE_SUCCESS) - { - CFE_MSG_GetSize(MsgPtr, SizePtr); - - /* Verify the size of the pkt is < or = the mission defined max */ - if (*SizePtr > CFE_MISSION_SB_MAX_SB_MSG_SIZE) - { - PendingEventID = CFE_SB_MSG_TOO_BIG_EID; - Status = CFE_SB_MSG_TOO_BIG; - } - } - - if (Status == CFE_SUCCESS) - { - /* check the route, which should be done while locked */ - CFE_SB_LockSharedData(__func__, __LINE__); - - /* Get the routing id */ - *RouteIdPtr = CFE_SBR_GetRouteId(*MsgIdPtr); - - /* if there have been no subscriptions for this pkt, */ - /* increment the dropped pkt cnt, send event and return success */ - if (!CFE_SBR_IsValidRouteId(*RouteIdPtr)) - { - CFE_SB_Global.HKTlmMsg.Payload.NoSubscribersCounter++; - PendingEventID = CFE_SB_SEND_NO_SUBS_EID; - } - - CFE_SB_UnlockSharedData(__func__, __LINE__); - } - - if (PendingEventID != 0) - { - /* get task id for events */ - CFE_ES_GetTaskID(&TskId); - - switch (PendingEventID) - { - case CFE_SB_SEND_BAD_ARG_EID: - if (CFE_SB_RequestToSendEvent(TskId, CFE_SB_SEND_BAD_ARG_EID_BIT) == CFE_SB_GRANTED) - { - CFE_EVS_SendEventWithAppID(CFE_SB_SEND_BAD_ARG_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "Send Err:Bad input argument,Arg 0x%lx,App %s", (unsigned long)MsgPtr, - CFE_SB_GetAppTskName(TskId, FullName)); - - /* clear the bit so the task may send this event again */ - CFE_SB_FinishSendEvent(TskId, CFE_SB_SEND_BAD_ARG_EID_BIT); - } - break; - - case CFE_SB_SEND_INV_MSGID_EID: - if (CFE_SB_RequestToSendEvent(TskId, CFE_SB_SEND_INV_MSGID_EID_BIT) == CFE_SB_GRANTED) - { - CFE_EVS_SendEventWithAppID(CFE_SB_SEND_INV_MSGID_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "Send Err:Invalid MsgId(0x%x)in msg,App %s", - (unsigned int)CFE_SB_MsgIdToValue(*MsgIdPtr), - CFE_SB_GetAppTskName(TskId, FullName)); - - /* clear the bit so the task may send this event again */ - CFE_SB_FinishSendEvent(TskId, CFE_SB_SEND_INV_MSGID_EID_BIT); - } - break; - - case CFE_SB_MSG_TOO_BIG_EID: - if (CFE_SB_RequestToSendEvent(TskId, CFE_SB_MSG_TOO_BIG_EID_BIT) == CFE_SB_GRANTED) - { - CFE_EVS_SendEventWithAppID(CFE_SB_MSG_TOO_BIG_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "Send Err:Msg Too Big MsgId=0x%x,app=%s,size=%d,MaxSz=%d", - (unsigned int)CFE_SB_MsgIdToValue(*MsgIdPtr), - CFE_SB_GetAppTskName(TskId, FullName), (int)*SizePtr, - CFE_MISSION_SB_MAX_SB_MSG_SIZE); - - /* clear the bit so the task may send this event again */ - CFE_SB_FinishSendEvent(TskId, CFE_SB_MSG_TOO_BIG_EID_BIT); - } - break; - - case CFE_SB_SEND_NO_SUBS_EID: - /* Determine if event can be sent without causing recursive event problem */ - if (CFE_SB_RequestToSendEvent(TskId, CFE_SB_SEND_NO_SUBS_EID_BIT) == CFE_SB_GRANTED) - { - CFE_EVS_SendEventWithAppID(CFE_SB_SEND_NO_SUBS_EID, CFE_EVS_EventType_INFORMATION, - CFE_SB_Global.AppId, "No subscribers for MsgId 0x%x,sender %s", - (unsigned int)CFE_SB_MsgIdToValue(*MsgIdPtr), - CFE_SB_GetAppTskName(TskId, FullName)); - - /* clear the bit so the task may send this event again */ - CFE_SB_FinishSendEvent(TskId, CFE_SB_SEND_NO_SUBS_EID_BIT); - } - break; - } - } - - return Status; -} - -/*---------------------------------------------------------------- - * - * Application-scope internal function - * See description in header file for argument/return detail - * - *-----------------------------------------------------------------*/ -void CFE_SB_BroadcastBufferToRoute(CFE_SB_BufferD_t *BufDscPtr, CFE_SBR_RouteId_t RouteId) -{ - CFE_ES_AppId_t AppId; - CFE_ES_TaskId_t TskId; - CFE_SB_DestinationD_t *DestPtr; - CFE_SB_PipeD_t * PipeDscPtr; - CFE_SB_EventBuf_t SBSndErr; - int32 OsStatus; - uint32 i; - char FullName[(OS_MAX_API_NAME * 2)]; - char PipeName[OS_MAX_API_NAME]; - bool IsAcceptable; - - SBSndErr.EvtsToSnd = 0; - IsAcceptable = true; - - /* get app id for loopback testing */ - CFE_ES_GetAppID(&AppId); - - /* get task id for events and Sender Info*/ - CFE_ES_GetTaskID(&TskId); - - /* take semaphore to prevent a task switch during processing */ - CFE_SB_LockSharedData(__func__, __LINE__); - - /* For an invalid route / no subscribers this whole logic can be skipped */ - if (CFE_SBR_IsValidRouteId(RouteId)) - { - /* Set the seq count if requested (while locked) before actually sending */ - if (BufDscPtr->NeedsUpdate) - { - CFE_SBR_IncrementSequenceCounter(RouteId); - - CFE_MSG_SetSequenceCount(&BufDscPtr->Content.Msg, CFE_SBR_GetSequenceCounter(RouteId)); - - /* Update all MSG headers based on the current sequence */ - CFE_MSG_OriginationAction(&BufDscPtr->Content.Msg, BufDscPtr->ContentSize, &IsAcceptable); - - /* Clear the flag, just in case */ - BufDscPtr->NeedsUpdate = false; - } - - /* Send the packet to all destinations */ - for (DestPtr = CFE_SBR_GetDestListHeadPtr(RouteId); DestPtr != NULL; DestPtr = DestPtr->Next) - { - if (DestPtr->Active == CFE_SB_ACTIVE) /* destination is active */ - { - PipeDscPtr = CFE_SB_LocatePipeDescByID(DestPtr->PipeId); - } - else - { - PipeDscPtr = NULL; - } - - if (!CFE_SB_PipeDescIsMatch(PipeDscPtr, DestPtr->PipeId)) - { - continue; - } - - if ((PipeDscPtr->Opts & CFE_SB_PIPEOPTS_IGNOREMINE) != 0 && - CFE_RESOURCEID_TEST_EQUAL(PipeDscPtr->AppId, AppId)) - { - continue; - } - - /* if Msg limit exceeded, log event, increment counter */ - /* and go to next destination */ - if (DestPtr->BuffCount >= DestPtr->MsgId2PipeLim) - { - SBSndErr.EvtBuf[SBSndErr.EvtsToSnd].PipeId = DestPtr->PipeId; - SBSndErr.EvtBuf[SBSndErr.EvtsToSnd].EventId = CFE_SB_MSGID_LIM_ERR_EID; - SBSndErr.EvtsToSnd++; - CFE_SB_Global.HKTlmMsg.Payload.MsgLimitErrorCounter++; - PipeDscPtr->SendErrors++; - - continue; - } - - /* - ** Write the buffer descriptor to the queue of the pipe. If the write - ** failed, log info and increment the pipe's error counter. - */ - OsStatus = OS_QueuePut(PipeDscPtr->SysQueueId, &BufDscPtr, sizeof(BufDscPtr), 0); - - if (OsStatus == OS_SUCCESS) - { - /* The queue now holds a ref to the buffer, so increment its ref count. */ - CFE_SB_IncrBufUseCnt(BufDscPtr); - - DestPtr->BuffCount++; /* used for checking MsgId2PipeLimit */ - DestPtr->DestCnt++; /* used for statistics */ - ++PipeDscPtr->CurrentQueueDepth; - if (PipeDscPtr->CurrentQueueDepth >= PipeDscPtr->PeakQueueDepth) - { - PipeDscPtr->PeakQueueDepth = PipeDscPtr->CurrentQueueDepth; - } - } - else - { - SBSndErr.EvtBuf[SBSndErr.EvtsToSnd].PipeId = DestPtr->PipeId; - if (OsStatus == OS_QUEUE_FULL) - { - SBSndErr.EvtBuf[SBSndErr.EvtsToSnd].EventId = CFE_SB_Q_FULL_ERR_EID; - CFE_SB_Global.HKTlmMsg.Payload.PipeOverflowErrorCounter++; - } - else - { - /* Unexpected error while writing to queue. */ - SBSndErr.EvtBuf[SBSndErr.EvtsToSnd].EventId = CFE_SB_Q_WR_ERR_EID; - SBSndErr.EvtBuf[SBSndErr.EvtsToSnd].OsStatus = OsStatus; - CFE_SB_Global.HKTlmMsg.Payload.InternalErrorCounter++; - } - SBSndErr.EvtsToSnd++; - PipeDscPtr->SendErrors++; - } /*end if */ - - } /* end loop over destinations */ - } - - /* - * If any specific delivery issues occurred, also increment the - * general error count before releasing the lock. - */ - if (SBSndErr.EvtsToSnd > 0) - { - CFE_SB_Global.HKTlmMsg.Payload.MsgSendErrorCounter++; - } - - /* - * Remove this from whatever list it was in - * - * If it was a singleton/new buffer this has no effect. - * If it was a zero-copy buffer this removes it from the ZeroCopyList. - */ - CFE_SB_TrackingListRemove(&BufDscPtr->Link); - - /* clear the AppID field in case it was a zero copy buffer, - * as it is no longer owned by that app after broadcasting */ - BufDscPtr->AppId = CFE_ES_APPID_UNDEFINED; - - /* track the buffer as an in-transit message */ - CFE_SB_TrackingListAdd(&CFE_SB_Global.InTransitList, &BufDscPtr->Link); - - /* - ** Decrement the buffer UseCount and free buffer if cnt=0. This decrement is done - ** because the use cnt is initialized to 1 in CFE_SB_GetBufferFromPool. - ** Initializing the count to 1 (as opposed to zero) and decrementing it here are - ** done to ensure the buffer gets released when there are destinations that have - ** been disabled via ground command. - */ - CFE_SB_DecrBufUseCnt(BufDscPtr); - - /* release the semaphore */ - CFE_SB_UnlockSharedData(__func__, __LINE__); - - /* send an event for each pipe write error that may have occurred */ - for (i = 0; i < SBSndErr.EvtsToSnd; i++) - { - if (SBSndErr.EvtBuf[i].EventId == CFE_SB_MSGID_LIM_ERR_EID) - { - /* Determine if event can be sent without causing recursive event problem */ - if (CFE_SB_RequestToSendEvent(TskId, CFE_SB_MSGID_LIM_ERR_EID_BIT) == CFE_SB_GRANTED) - { - CFE_SB_GetPipeName(PipeName, sizeof(PipeName), SBSndErr.EvtBuf[i].PipeId); - - CFE_ES_PerfLogEntry(CFE_MISSION_SB_MSG_LIM_PERF_ID); - CFE_ES_PerfLogExit(CFE_MISSION_SB_MSG_LIM_PERF_ID); - - CFE_EVS_SendEventWithAppID(CFE_SB_MSGID_LIM_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "Msg Limit Err,MsgId 0x%x,pipe %s,sender %s", - (unsigned int)CFE_SB_MsgIdToValue(BufDscPtr->MsgId), PipeName, - CFE_SB_GetAppTskName(TskId, FullName)); - - /* clear the bit so the task may send this event again */ - CFE_SB_FinishSendEvent(TskId, CFE_SB_MSGID_LIM_ERR_EID_BIT); - } - } - else if (SBSndErr.EvtBuf[i].EventId == CFE_SB_Q_FULL_ERR_EID) - { - /* Determine if event can be sent without causing recursive event problem */ - if (CFE_SB_RequestToSendEvent(TskId, CFE_SB_Q_FULL_ERR_EID_BIT) == CFE_SB_GRANTED) - { - CFE_SB_GetPipeName(PipeName, sizeof(PipeName), SBSndErr.EvtBuf[i].PipeId); - - CFE_ES_PerfLogEntry(CFE_MISSION_SB_PIPE_OFLOW_PERF_ID); - CFE_ES_PerfLogExit(CFE_MISSION_SB_PIPE_OFLOW_PERF_ID); - - CFE_EVS_SendEventWithAppID(CFE_SB_Q_FULL_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "Pipe Overflow,MsgId 0x%x,pipe %s,sender %s", - (unsigned int)CFE_SB_MsgIdToValue(BufDscPtr->MsgId), PipeName, - CFE_SB_GetAppTskName(TskId, FullName)); - - /* clear the bit so the task may send this event again */ - CFE_SB_FinishSendEvent(TskId, CFE_SB_Q_FULL_ERR_EID_BIT); - } - } - else - { - /* Determine if event can be sent without causing recursive event problem */ - if (CFE_SB_RequestToSendEvent(TskId, CFE_SB_Q_WR_ERR_EID_BIT) == CFE_SB_GRANTED) - { - CFE_SB_GetPipeName(PipeName, sizeof(PipeName), SBSndErr.EvtBuf[i].PipeId); - - CFE_EVS_SendEventWithAppID(CFE_SB_Q_WR_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "Pipe Write Err,MsgId 0x%x,pipe %s,sender %s,stat %ld", - (unsigned int)CFE_SB_MsgIdToValue(BufDscPtr->MsgId), PipeName, - CFE_SB_GetAppTskName(TskId, FullName), (long)(SBSndErr.EvtBuf[i].OsStatus)); - - /* clear the bit so the task may send this event again */ - CFE_SB_FinishSendEvent(TskId, CFE_SB_Q_WR_ERR_EID_BIT); - } - } - } -} - -/*---------------------------------------------------------------- - * - * Implemented per public API - * See description in header file for argument/return detail - * - *-----------------------------------------------------------------*/ -CFE_Status_t CFE_SB_ReceiveBuffer(CFE_SB_Buffer_t **BufPtr, CFE_SB_PipeId_t PipeId, int32 TimeOut) -{ - int32 Status; - int32 OsStatus; - CFE_SB_BufferD_t * BufDscPtr; - size_t BufDscSize; - CFE_SB_PipeD_t * PipeDscPtr; - CFE_SB_DestinationD_t *DestPtr; - CFE_SBR_RouteId_t RouteId; - CFE_ES_TaskId_t TskId; - uint16 PendingEventID; - osal_id_t SysQueueId; - int32 SysTimeout; - char FullName[(OS_MAX_API_NAME * 2)]; - - PendingEventID = 0; - Status = CFE_SUCCESS; - SysTimeout = OS_PEND; - SysQueueId = OS_OBJECT_ID_UNDEFINED; - PipeDscPtr = NULL; - BufDscPtr = NULL; - DestPtr = NULL; - BufDscSize = 0; - OsStatus = OS_SUCCESS; - - /* - * Check input args and see if any are bad, which require - * a "BAD_ARG_EID" to be generated. - * - * Also translate the timeout here. Timeouts greater than 0 - * may be passed to OSAL directly, but the two fixed constants - * CFE_SB_PEND_FOREVER and CFE_SB_POLL are checked explicitly, - * to maintain API independence - even though the values are - * currently defined the same. - */ - - if (BufPtr == NULL) - { - PendingEventID = CFE_SB_RCV_BAD_ARG_EID; - Status = CFE_SB_BAD_ARGUMENT; - } - else if (TimeOut > 0) - { - /* time outs greater than 0 can be passed to OSAL directly */ - SysTimeout = TimeOut; - } - else if (TimeOut == CFE_SB_POLL) - { - SysTimeout = OS_CHECK; - } - else if (TimeOut != CFE_SB_PEND_FOREVER) - { - /* any other timeout value is invalid */ - PendingEventID = CFE_SB_RCV_BAD_ARG_EID; - Status = CFE_SB_BAD_ARGUMENT; - } - - /* If OK, then lock and pull relevant info from Pipe Descriptor */ - if (Status == CFE_SUCCESS) - { - CFE_SB_LockSharedData(__func__, __LINE__); - - PipeDscPtr = CFE_SB_LocatePipeDescByID(PipeId); - - /* If the pipe does not exist or PipeId is out of range... */ - if (!CFE_SB_PipeDescIsMatch(PipeDscPtr, PipeId)) - { - PendingEventID = CFE_SB_BAD_PIPEID_EID; - Status = CFE_SB_BAD_ARGUMENT; - } - else - { - /* Grab the queue ID */ - SysQueueId = PipeDscPtr->SysQueueId; - - /* - * Un-reference any previous buffer from the last call. - * - * NOTE: This is historical behavior where apps call CFE_SB_ReceiveBuffer() - * in the loop within the app's main task. There is currently no separate - * API to "free" or unreference a buffer that was returned from SB. - * - * Instead, each time this function is invoked, it is implicitly interpreted - * as an indication that the caller is done with the previous buffer. - * - * Unfortunately this prevents pipe IDs from being serviced/shared across - * multiple child tasks in a worker pattern design. This may be changed - * in a future version of CFE to decouple these actions, to allow for - * multiple workers to service the same pipe. - */ - if (PipeDscPtr->LastBuffer != NULL) - { - /* Decrement the Buffer Use Count, which will Free buffer if it becomes 0 */ - CFE_SB_DecrBufUseCnt(PipeDscPtr->LastBuffer); - PipeDscPtr->LastBuffer = NULL; - } - } - - CFE_SB_UnlockSharedData(__func__, __LINE__); - } - - /* - * If everything validated, then proceed to get a buffer from the queue. - * This must be done OUTSIDE the SB lock, as this call likely blocks. - */ - if (Status == CFE_SUCCESS) - { - /* Read the buffer descriptor address from the queue. */ - OsStatus = OS_QueueGet(SysQueueId, &BufDscPtr, sizeof(BufDscPtr), &BufDscSize, SysTimeout); - - /* - * translate the return value - - * - * CFE functions have their own set of RC values should not directly return OSAL codes - * The size should always match. If it does not, then generate CFE_SB_Q_RD_ERR_EID. - */ - if (OsStatus == OS_SUCCESS && BufDscPtr != NULL && BufDscSize == sizeof(BufDscPtr)) - { - /* Pass through */ - } - else if (OsStatus == OS_QUEUE_EMPTY) - { - /* normal if using CFE_SB_POLL */ - Status = CFE_SB_NO_MESSAGE; - } - else if (OsStatus == OS_QUEUE_TIMEOUT) - { - /* normal if using a nonzero timeout */ - Status = CFE_SB_TIME_OUT; - } - else - { - /* off-nominal condition, report an error event */ - PendingEventID = CFE_SB_Q_RD_ERR_EID; - Status = CFE_SB_PIPE_RD_ERR; - } - } - - /* Now re-lock to store the buffer in the pipe descriptor */ - CFE_SB_LockSharedData(__func__, __LINE__); - - if (Status == CFE_SUCCESS) - { - /* - * NOTE: This uses the same PipeDscPtr that was found earlier. - * Technically it is possible that the pipe was changed between now and then, - * but the current PipeID definition doesn't really allow this to be detected. - */ - if (CFE_SB_PipeDescIsMatch(PipeDscPtr, PipeId)) - { - /* - ** Load the pipe tables 'CurrentBuff' with the buffer descriptor - ** ptr corresponding to the message just read. This is done so that - ** the buffer can be released on the next receive call for this pipe. - ** - ** This counts as a new reference as it is being stored in the PipeDsc - */ - CFE_SB_IncrBufUseCnt(BufDscPtr); - PipeDscPtr->LastBuffer = BufDscPtr; - - /* - * Also set the Receivers pointer to the address of the actual message - * (currently this is "borrowing" the ref above, not its own ref) - */ - *BufPtr = &BufDscPtr->Content; - - /* get pointer to destination to be used in decrementing msg limit cnt*/ - RouteId = CFE_SBR_GetRouteId(BufDscPtr->MsgId); - DestPtr = CFE_SB_GetDestPtr(RouteId, PipeId); - - /* - ** DestPtr would be NULL if the msg is unsubscribed to while it is on - ** the pipe. The BuffCount may be zero if the msg is unsubscribed to and - ** then resubscribed to while it is on the pipe. Both of these cases are - ** considered nominal and are handled by the code below. - */ - if (DestPtr != NULL && DestPtr->BuffCount > 0) - { - DestPtr->BuffCount--; - } - - if (PipeDscPtr->CurrentQueueDepth > 0) - { - --PipeDscPtr->CurrentQueueDepth; - } - } - else - { - /* should send the bad pipe ID event here too */ - PendingEventID = CFE_SB_BAD_PIPEID_EID; - Status = CFE_SB_PIPE_RD_ERR; - } - - /* Always decrement the use count, for the ref that was in the queue */ - CFE_SB_DecrBufUseCnt(BufDscPtr); - } - - /* Before unlocking, increment relevant error counter if needed */ - if (Status != CFE_SUCCESS && Status != CFE_SB_NO_MESSAGE && Status != CFE_SB_TIME_OUT) - { - if (PendingEventID == CFE_SB_RCV_BAD_ARG_EID || PendingEventID == CFE_SB_BAD_PIPEID_EID) - { - ++CFE_SB_Global.HKTlmMsg.Payload.MsgReceiveErrorCounter; - } - else - { - /* For any other unexpected error (e.g. CFE_SB_Q_RD_ERR_EID) */ - ++CFE_SB_Global.HKTlmMsg.Payload.InternalErrorCounter; - } - } - - CFE_SB_UnlockSharedData(__func__, __LINE__); - - /* Now actually send the event, after unlocking (do not call EVS with SB locked) */ - if (PendingEventID != 0) - { - /* get task id for events */ - CFE_ES_GetTaskID(&TskId); - - switch (PendingEventID) - { - case CFE_SB_Q_RD_ERR_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_Q_RD_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "Pipe Read Err,pipe %lu,app %s,stat %ld", CFE_RESOURCEID_TO_ULONG(PipeId), - CFE_SB_GetAppTskName(TskId, FullName), (long)OsStatus); - break; - case CFE_SB_RCV_BAD_ARG_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_RCV_BAD_ARG_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "Rcv Err:Bad Input Arg:BufPtr 0x%lx,pipe %lu,t/o %d,app %s", - (unsigned long)BufPtr, CFE_RESOURCEID_TO_ULONG(PipeId), (int)TimeOut, - CFE_SB_GetAppTskName(TskId, FullName)); - break; - case CFE_SB_BAD_PIPEID_EID: - CFE_EVS_SendEventWithAppID(CFE_SB_BAD_PIPEID_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId, - "Rcv Err:PipeId %lu does not exist,app %s", CFE_RESOURCEID_TO_ULONG(PipeId), - CFE_SB_GetAppTskName(TskId, FullName)); - break; - } - } - - /* If not successful, set the output pointer to NULL */ - if (Status != CFE_SUCCESS && BufPtr != NULL) - { - *BufPtr = NULL; - } - - return Status; -} + return CFE_SB_MessageTxn_GetStatus(Txn); +} /*---------------------------------------------------------------- * @@ -2004,21 +1384,27 @@ CFE_Status_t CFE_SB_ReceiveBuffer(CFE_SB_Buffer_t **BufPtr, CFE_SB_PipeId_t Pipe CFE_SB_Buffer_t *CFE_SB_AllocateMessageBuffer(size_t MsgSize) { CFE_ES_AppId_t AppId; + char AppName[OS_MAX_API_NAME] = {""}; CFE_SB_BufferD_t *BufDscPtr; CFE_SB_Buffer_t * BufPtr; + CFE_Status_t Status; AppId = CFE_ES_APPID_UNDEFINED; BufDscPtr = NULL; BufPtr = NULL; + Status = CFE_ES_GetAppID(&AppId); + if (MsgSize > CFE_MISSION_SB_MAX_SB_MSG_SIZE) { - CFE_ES_WriteToSysLog("%s: ZeroCopyGetPtr-Failed, MsgSize is too large\n", __func__); + CFE_ES_GetAppName(AppName, AppId, sizeof(AppName)); + CFE_ES_WriteToSysLog("%s %s: Failed, requested size %ld larger than allowed %d\n", + AppName, __func__, MsgSize, CFE_MISSION_SB_MAX_SB_MSG_SIZE); return NULL; } /* get callers AppId */ - if (CFE_ES_GetAppID(&AppId) == CFE_SUCCESS) + if (Status == CFE_SUCCESS) { CFE_SB_LockSharedData(__func__, __LINE__); @@ -2055,13 +1441,14 @@ CFE_SB_Buffer_t *CFE_SB_AllocateMessageBuffer(size_t MsgSize) /*---------------------------------------------------------------- * - * Application-scope internal function + * Implemented per public API * See description in header file for argument/return detail * *-----------------------------------------------------------------*/ -int32 CFE_SB_ZeroCopyBufferValidate(CFE_SB_Buffer_t *BufPtr, CFE_SB_BufferD_t **BufDscPtr) +CFE_Status_t CFE_SB_ReleaseMessageBuffer(CFE_SB_Buffer_t *BufPtr) { - cpuaddr BufDscAddr; + CFE_SB_BufferD_t *BufDscPtr; + int32 Status; /* * Sanity Check that the pointers are not NULL @@ -2071,23 +1458,19 @@ int32 CFE_SB_ZeroCopyBufferValidate(CFE_SB_Buffer_t *BufPtr, CFE_SB_BufferD_t ** return CFE_SB_BAD_ARGUMENT; } - /* - * Calculate descriptor pointer from buffer pointer - - * The buffer is just a member (offset) in the descriptor - */ - BufDscAddr = (cpuaddr)BufPtr - offsetof(CFE_SB_BufferD_t, Content); - *BufDscPtr = (CFE_SB_BufferD_t *)BufDscAddr; + CFE_SB_LockSharedData(__func__, __LINE__); - /* - * Check that the descriptor is actually a "zero copy" type, - */ - if (!CFE_RESOURCEID_TEST_DEFINED((*BufDscPtr)->AppId)) + Status = CFE_SB_ZeroCopyBufferValidate(BufPtr, &BufDscPtr); + if (Status == CFE_SUCCESS) { - return CFE_SB_BUFFER_INVALID; + /* Clear the ownership app ID and decrement use count (may also free) */ + BufDscPtr->AppId = CFE_ES_APPID_UNDEFINED; + CFE_SB_DecrBufUseCnt(BufDscPtr); } - /* Basic sanity check passed */ - return CFE_SUCCESS; + CFE_SB_UnlockSharedData(__func__, __LINE__); + + return Status; } /*---------------------------------------------------------------- @@ -2096,25 +1479,31 @@ int32 CFE_SB_ZeroCopyBufferValidate(CFE_SB_Buffer_t *BufPtr, CFE_SB_BufferD_t ** * See description in header file for argument/return detail * *-----------------------------------------------------------------*/ -CFE_Status_t CFE_SB_ReleaseMessageBuffer(CFE_SB_Buffer_t *BufPtr) +CFE_Status_t CFE_SB_TransmitBuffer(CFE_SB_Buffer_t *BufPtr, bool IsOrigination) { - CFE_SB_BufferD_t *BufDscPtr; - int32 Status; + CFE_SB_TransmitTxn_State_t TxnBuf; + CFE_SB_MessageTxn_State_t *Txn; - Status = CFE_SB_ZeroCopyBufferValidate(BufPtr, &BufDscPtr); + Txn = CFE_SB_TransmitTxn_Init(&TxnBuf, BufPtr); - CFE_SB_LockSharedData(__func__, __LINE__); + /* In this context, the user should have set the the size and MsgId in the content */ + if (CFE_SB_MessageTxn_IsOK(Txn)) + { + CFE_SB_TransmitTxn_SetupFromMsg(Txn, &BufPtr->Msg); + } - if (Status == CFE_SUCCESS) + if (CFE_SB_MessageTxn_IsOK(Txn)) { - /* Clear the ownership app ID and decrement use count (may also free) */ - BufDscPtr->AppId = CFE_ES_APPID_UNDEFINED; - CFE_SB_DecrBufUseCnt(BufDscPtr); + /* Save passed-in parameters */ + CFE_SB_MessageTxn_SetEndpoint(Txn, IsOrigination); + + CFE_SB_TransmitTxn_Execute(Txn, BufPtr); } - CFE_SB_UnlockSharedData(__func__, __LINE__); + /* send an event for each pipe write error that may have occurred */ + CFE_SB_MessageTxn_ReportEvents(Txn); - return Status; + return CFE_SB_MessageTxn_GetStatus(Txn); } /*---------------------------------------------------------------- @@ -2123,52 +1512,63 @@ CFE_Status_t CFE_SB_ReleaseMessageBuffer(CFE_SB_Buffer_t *BufPtr) * See description in header file for argument/return detail * *-----------------------------------------------------------------*/ -CFE_Status_t CFE_SB_TransmitBuffer(CFE_SB_Buffer_t *BufPtr, bool IsOrigination) +CFE_Status_t CFE_SB_TransmitMsg(const CFE_MSG_Message_t *MsgPtr, bool IsOrigination) { - int32 Status; - CFE_SB_BufferD_t *BufDscPtr; - CFE_SBR_RouteId_t RouteId; + CFE_SB_TransmitTxn_State_t TxnBuf; + CFE_SB_MessageTxn_State_t *Txn; + CFE_SB_Buffer_t * BufPtr; - Status = CFE_SB_ZeroCopyBufferValidate(BufPtr, &BufDscPtr); + BufPtr = NULL; + Txn = CFE_SB_TransmitTxn_Init(&TxnBuf, MsgPtr); - if (Status == CFE_SUCCESS) + /* In this context, the user should have set the the size and MsgId in the content */ + if (CFE_SB_MessageTxn_IsOK(Txn)) { - /* Validate the content and get the MsgId, store it in the descriptor */ - Status = CFE_SB_TransmitMsgValidate(&BufPtr->Msg, &BufDscPtr->MsgId, &BufDscPtr->ContentSize, &RouteId); + CFE_SB_TransmitTxn_SetupFromMsg(Txn, MsgPtr); + } - /* - * Broadcast the message if validation succeeded. - * - * Note that for the case of no subscribers, the validation returns CFE_SUCCESS - * but the actual route ID may be invalid. This is OK and considered normal- - * the validation will increment the NoSubscribers count, but we should NOT - * increment the MsgSendErrorCounter here - it is not really a sending error to - * have no subscribers. CFE_SB_BroadcastBufferToRoute() will not send to - * anything if the route is not valid (benign). - */ - if (Status == CFE_SUCCESS) + if (CFE_SB_MessageTxn_IsOK(Txn)) + { + /* Get buffer - note this pre-initializes the returned buffer with + * a use count of 1, which refers to this task as it fills the buffer. */ + BufPtr = CFE_SB_AllocateMessageBuffer(CFE_SB_MessageTxn_GetContentSize(Txn)); + if (BufPtr == NULL) { - BufDscPtr->NeedsUpdate = IsOrigination; - CFE_MSG_GetType(&BufPtr->Msg, &BufDscPtr->ContentType); - - /* Now broadcast the message, which consumes the buffer */ - CFE_SB_BroadcastBufferToRoute(BufDscPtr, RouteId); - - /* - * IMPORTANT - the descriptor might be freed at any time after this, - * so the descriptor should not be accessed again after this point. - */ - BufDscPtr = NULL; + CFE_SB_MessageTxn_SetEventAndStatus(Txn, CFE_SB_GET_BUF_ERR_EID, CFE_SB_BUF_ALOC_ERR); } } - if (Status != CFE_SUCCESS) + /* + * If a buffer was obtained above, then copy the content into it + * and broadcast it to all subscribers in the route. + * + * Note - if there is no route / no subscribers, the "Status" will + * be CFE_SUCCESS because CFE_SB_TransmitMsgValidate() succeeded, + * but there will be no buffer because CFE_SBR_IsValidRouteId() returned + * false. + * + * But if the descriptor is non-null it means the message is valid and + * there is a route to send it to. + */ + if (CFE_SB_MessageTxn_IsOK(Txn)) { - /* Increment send error counter for validation failure */ - CFE_SB_LockSharedData(__func__, __LINE__); - CFE_SB_Global.HKTlmMsg.Payload.MsgSendErrorCounter++; - CFE_SB_UnlockSharedData(__func__, __LINE__); + /* Copy actual message content into buffer */ + memcpy(&BufPtr->Msg, MsgPtr, CFE_SB_MessageTxn_GetContentSize(Txn)); + + /* Save passed-in parameters */ + CFE_SB_MessageTxn_SetEndpoint(Txn, IsOrigination); + + CFE_SB_TransmitTxn_Execute(Txn, BufPtr); + + /* + * The broadcast function consumes the buffer, so it should not be + * accessed in this function anymore + */ + BufPtr = NULL; } - return Status; + /* send an event for each pipe write error that may have occurred */ + CFE_SB_MessageTxn_ReportEvents(Txn); + + return CFE_SB_MessageTxn_GetStatus(Txn); } diff --git a/modules/sb/fsw/src/cfe_sb_buf.c b/modules/sb/fsw/src/cfe_sb_buf.c index 1f5dd0156..5853cefb6 100644 --- a/modules/sb/fsw/src/cfe_sb_buf.c +++ b/modules/sb/fsw/src/cfe_sb_buf.c @@ -128,7 +128,6 @@ CFE_SB_BufferD_t *CFE_SB_GetBufferFromPool(size_t MaxMsgSize) bd = (CFE_SB_BufferD_t *)addr; memset(bd, 0, CFE_SB_BUFFERD_CONTENT_OFFSET); - bd->MsgId = CFE_SB_INVALID_MSG_ID; bd->UseCount = 1; bd->AllocatedSize = AllocSize; diff --git a/modules/sb/fsw/src/cfe_sb_priv.c b/modules/sb/fsw/src/cfe_sb_priv.c index a48f77481..e898dc2ee 100644 --- a/modules/sb/fsw/src/cfe_sb_priv.c +++ b/modules/sb/fsw/src/cfe_sb_priv.c @@ -291,10 +291,15 @@ char *CFE_SB_GetAppTskName(CFE_ES_TaskId_t TaskId, char *FullName) * See description in header file for argument/return detail * *-----------------------------------------------------------------*/ -uint32 CFE_SB_RequestToSendEvent(CFE_ES_TaskId_t TaskId, uint32 Bit) +uint32 CFE_SB_RequestToSendEvent(CFE_ES_TaskId_t TaskId, int32 Bit) { uint32 Indx; + if (Bit < 0) + { + return CFE_SB_GRANTED; + } + if (CFE_ES_TaskID_ToIndex(TaskId, &Indx) != CFE_SUCCESS) { return CFE_SB_DENIED; @@ -318,10 +323,15 @@ uint32 CFE_SB_RequestToSendEvent(CFE_ES_TaskId_t TaskId, uint32 Bit) * See description in header file for argument/return detail * *-----------------------------------------------------------------*/ -void CFE_SB_FinishSendEvent(CFE_ES_TaskId_t TaskId, uint32 Bit) +void CFE_SB_FinishSendEvent(CFE_ES_TaskId_t TaskId, int32 Bit) { uint32 Indx; + if (Bit < 0) + { + return; + } + if (CFE_ES_TaskID_ToIndex(TaskId, &Indx) != CFE_SUCCESS) { return; @@ -470,3 +480,1048 @@ int32 CFE_SB_ZeroCopyReleaseAppId(CFE_ES_AppId_t AppId) return CFE_SUCCESS; } + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +int32 CFE_SB_ZeroCopyBufferValidate(CFE_SB_Buffer_t *BufPtr, CFE_SB_BufferD_t **BufDscPtr) +{ + cpuaddr BufDscAddr; + + /* + * Calculate descriptor pointer from buffer pointer - + * The buffer is just a member (offset) in the descriptor + */ + BufDscAddr = (cpuaddr)BufPtr - offsetof(CFE_SB_BufferD_t, Content); + *BufDscPtr = (CFE_SB_BufferD_t *)BufDscAddr; + + /* + * Check that the descriptor is actually a "zero copy" type, + */ + if (!CFE_RESOURCEID_TEST_DEFINED((*BufDscPtr)->AppId)) + { + return CFE_SB_BUFFER_INVALID; + } + + /* Basic sanity check passed */ + return CFE_SUCCESS; +} + +/****************************************************************** + * + * MESSAGE TRANSACTION IMPLEMENTATION FUNCTIONS + * + ******************************************************************/ + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +void CFE_SB_MessageTxn_Init(CFE_SB_MessageTxn_State_t *TxnPtr, CFE_SB_PipeSetEntry_t *PipeSet, uint16 MaxPipes, + const void *RefMemPtr) +{ + memset(TxnPtr, 0, offsetof(CFE_SB_TransmitTxn_State_t, DestSet)); + TxnPtr->PipeSet = PipeSet; + TxnPtr->MaxPipes = MaxPipes; + + /* The reference pointer is kept just for (potential) reporting in events, etc. + * It is not dereferenced from here. */ + TxnPtr->RefMemPtr = RefMemPtr; +} + +/*---------------------------------------------------------------- + * + * Local Helper function + * Not invoked outside of this unit + * + *-----------------------------------------------------------------*/ +void CFE_SB_MessageTxn_SetTimeout(CFE_SB_MessageTxn_State_t *TxnPtr, int32 Timeout) +{ + TxnPtr->UserTimeoutParam = Timeout; + if (Timeout > 0) + { + /* Convert to an absolute timeout */ + TxnPtr->TimeoutMode = CFE_SB_MessageTxn_TimeoutMode_TIMED; + CFE_PSP_GetTime(&TxnPtr->AbsTimeout); + TxnPtr->AbsTimeout = OS_TimeAdd(TxnPtr->AbsTimeout, OS_TimeFromTotalMilliseconds(Timeout)); + } + else if (Timeout == CFE_SB_POLL) + { + TxnPtr->TimeoutMode = CFE_SB_MessageTxn_TimeoutMode_POLL; + } + else if (Timeout == CFE_SB_PEND_FOREVER) + { + TxnPtr->TimeoutMode = CFE_SB_MessageTxn_TimeoutMode_PEND; + } + else + { + CFE_SB_MessageTxn_SetEventAndStatus(TxnPtr, CFE_SB_RCV_BAD_ARG_EID, CFE_SB_BAD_ARGUMENT); + } +} + +/*---------------------------------------------------------------- + * + * Local Helper function + * Not invoked outside of this unit + * + *-----------------------------------------------------------------*/ +void CFE_SB_MessageTxn_GetEventDetails(const CFE_SB_MessageTxn_State_t *TxnPtr, const CFE_SB_PipeSetEntry_t *ContextPtr, + uint16 EventId, CFE_ES_TaskId_t TskId, char *EvtMsg, size_t EvtMsgSize, + CFE_EVS_EventType_Enum_t *EventType, int32 *ReqBit) +{ + char FullName[(OS_MAX_API_NAME * 2)]; + char PipeName[OS_MAX_API_NAME]; + int32 LocalOsStatus; + + if (ContextPtr == NULL) + { + LocalOsStatus = INT32_MIN; /* should not be used; do not alias any actual OS status */ + } + else + { + LocalOsStatus = ContextPtr->OsStatus; + if (ContextPtr->PendingEventId == CFE_SB_BAD_PIPEID_EID) + { + /* do not attempt to map to a pipe name if reporting a bad pipeID event - use its ID */ + snprintf(PipeName, sizeof(PipeName), "%lu", CFE_RESOURCEID_TO_ULONG(ContextPtr->PipeId)); + } + else + { + CFE_SB_GetPipeName(PipeName, sizeof(PipeName), ContextPtr->PipeId); + } + } + + switch (EventId) + { + case CFE_SB_SEND_BAD_ARG_EID: + *ReqBit = CFE_SB_SEND_BAD_ARG_EID_BIT; + *EventType = CFE_EVS_EventType_ERROR; + + snprintf(EvtMsg, EvtMsgSize, "Send Err:Bad input argument,Arg 0x%lx,App %s", + (unsigned long)TxnPtr->RefMemPtr, CFE_SB_GetAppTskName(TskId, FullName)); + break; + + case CFE_SB_SEND_INV_MSGID_EID: + *ReqBit = CFE_SB_SEND_INV_MSGID_EID_BIT; + *EventType = CFE_EVS_EventType_ERROR; + + snprintf(EvtMsg, EvtMsgSize, "Send Err:Invalid MsgId(0x%x)in msg,App %s", + (unsigned int)CFE_SB_MsgIdToValue(TxnPtr->RoutingMsgId), CFE_SB_GetAppTskName(TskId, FullName)); + break; + + case CFE_SB_MSG_TOO_BIG_EID: + *ReqBit = CFE_SB_MSG_TOO_BIG_EID_BIT; + *EventType = CFE_EVS_EventType_ERROR; + + snprintf(EvtMsg, EvtMsgSize, "Send Err:Msg Too Big MsgId=0x%x,app=%s,size=%d,MaxSz=%d", + (unsigned int)CFE_SB_MsgIdToValue(TxnPtr->RoutingMsgId), CFE_SB_GetAppTskName(TskId, FullName), + (int)TxnPtr->ContentSize, CFE_MISSION_SB_MAX_SB_MSG_SIZE); + break; + + case CFE_SB_SEND_NO_SUBS_EID: + *ReqBit = CFE_SB_SEND_NO_SUBS_EID_BIT; + *EventType = CFE_EVS_EventType_INFORMATION; + + snprintf(EvtMsg, EvtMsgSize, "No subscribers for MsgId 0x%x,sender %s", + (unsigned int)CFE_SB_MsgIdToValue(TxnPtr->RoutingMsgId), CFE_SB_GetAppTskName(TskId, FullName)); + break; + + case CFE_SB_GET_BUF_ERR_EID: + *ReqBit = CFE_SB_GET_BUF_ERR_EID_BIT; + *EventType = CFE_EVS_EventType_ERROR; + + snprintf(EvtMsg, EvtMsgSize, "Send Err:Request for Buffer Failed. MsgId 0x%x,app %s,size %d", + (unsigned int)CFE_SB_MsgIdToValue(TxnPtr->RoutingMsgId), CFE_SB_GetAppTskName(TskId, FullName), + (int)TxnPtr->ContentSize); + break; + + case CFE_SB_MSGID_LIM_ERR_EID: + *ReqBit = CFE_SB_MSGID_LIM_ERR_EID_BIT; + *EventType = CFE_EVS_EventType_ERROR; + + snprintf(EvtMsg, EvtMsgSize, "Msg Limit Err,MsgId 0x%x,pipe %s,sender %s", + (unsigned int)CFE_SB_MsgIdToValue(TxnPtr->RoutingMsgId), PipeName, + CFE_SB_GetAppTskName(TskId, FullName)); + break; + + case CFE_SB_Q_FULL_ERR_EID: + *ReqBit = CFE_SB_Q_FULL_ERR_EID_BIT; + *EventType = CFE_EVS_EventType_ERROR; + + snprintf(EvtMsg, EvtMsgSize, "Pipe Overflow,MsgId 0x%x,pipe %s,sender %s", + (unsigned int)CFE_SB_MsgIdToValue(TxnPtr->RoutingMsgId), PipeName, + CFE_SB_GetAppTskName(TskId, FullName)); + break; + + case CFE_SB_Q_WR_ERR_EID: + *ReqBit = CFE_SB_Q_WR_ERR_EID_BIT; + *EventType = CFE_EVS_EventType_ERROR; + + snprintf(EvtMsg, EvtMsgSize, "Pipe Write Err,MsgId 0x%x,pipe %s,sender %s,stat %ld", + (unsigned int)CFE_SB_MsgIdToValue(TxnPtr->RoutingMsgId), PipeName, + CFE_SB_GetAppTskName(TskId, FullName), (long)LocalOsStatus); + break; + + case CFE_SB_Q_RD_ERR_EID: + *ReqBit = -1; + *EventType = CFE_EVS_EventType_ERROR; + + snprintf(EvtMsg, EvtMsgSize, "Pipe Read Err,pipe %s,app %s,stat %ld", PipeName, + CFE_SB_GetAppTskName(TskId, FullName), (long)LocalOsStatus); + break; + case CFE_SB_RCV_BAD_ARG_EID: + *ReqBit = -1; + *EventType = CFE_EVS_EventType_ERROR; + + snprintf(EvtMsg, EvtMsgSize, "Rcv Err:Bad Input Arg:BufPtr 0x%lx,pipe %s,t/o %d,app %s", + (unsigned long)TxnPtr->RefMemPtr, PipeName, (int)TxnPtr->UserTimeoutParam, + CFE_SB_GetAppTskName(TskId, FullName)); + break; + case CFE_SB_BAD_PIPEID_EID: + *ReqBit = -1; + *EventType = CFE_EVS_EventType_ERROR; + + snprintf(EvtMsg, EvtMsgSize, "Rcv Err:PipeId %s does not exist,app %s", PipeName, + CFE_SB_GetAppTskName(TskId, FullName)); + break; + + default: + EvtMsg[0] = 0; + *ReqBit = 0; + *EventType = 0; + break; + } +} + +/*---------------------------------------------------------------- + * + * Local Helper function + * Not invoked outside of this unit + * + *-----------------------------------------------------------------*/ +bool CFE_SB_MessageTxn_ReportSingleEvent(const CFE_SB_MessageTxn_State_t *TxnPtr, + const CFE_SB_PipeSetEntry_t *ContextPtr, uint16 EventId) +{ + CFE_ES_TaskId_t TskId; + CFE_EVS_EventType_Enum_t EventType; + char Message[CFE_MISSION_EVS_MAX_MESSAGE_LENGTH]; + int32 ReqBit; + + /* get task id for events and Sender Info*/ + CFE_ES_GetTaskID(&TskId); + + CFE_SB_MessageTxn_GetEventDetails(TxnPtr, ContextPtr, EventId, TskId, Message, sizeof(Message), &EventType, + &ReqBit); + + if (EventType > 0 && CFE_SB_RequestToSendEvent(TskId, ReqBit) == CFE_SB_GRANTED) + { + CFE_EVS_SendEventWithAppID(EventId, EventType, CFE_SB_Global.AppId, "%s", Message); + + /* clear the bit so the task may send this event again */ + CFE_SB_FinishSendEvent(TskId, ReqBit); + } + + /* If the event type was an error, this should increment the general error counter */ + return (EventType >= CFE_EVS_EventType_ERROR); +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +void CFE_SB_MessageTxn_ReportEvents(const CFE_SB_MessageTxn_State_t *TxnPtr) +{ + uint32 i; + uint32 NumErrors; + bool IsError; + + NumErrors = 0; + + if (TxnPtr->TransactionEventId != 0) + { + IsError = CFE_SB_MessageTxn_ReportSingleEvent(TxnPtr, NULL, TxnPtr->TransactionEventId); + if (IsError) + { + ++NumErrors; + } + } + + for (i = 0; i < TxnPtr->NumPipes; ++i) + { + if (TxnPtr->PipeSet[i].PendingEventId != 0) + { + IsError = + CFE_SB_MessageTxn_ReportSingleEvent(TxnPtr, &TxnPtr->PipeSet[i], TxnPtr->PipeSet[i].PendingEventId); + if (IsError) + { + ++NumErrors; + } + } + } + + if (NumErrors > 0) + { + /* + * Increment the error only if there was a real error, + * such as a validation issue or failure to allocate a buffer. + * + * Note that transmit side just has one error counter, whereas + * receive side has two - these differeniate between a bad passed-in + * arg vs some other internal error such as queue access. + */ + CFE_SB_LockSharedData(__func__, __LINE__); + + if (TxnPtr->IsTransmit) + { + CFE_SB_Global.HKTlmMsg.Payload.MsgSendErrorCounter++; + } + else if (TxnPtr->Status == CFE_SB_BAD_ARGUMENT) + { + ++CFE_SB_Global.HKTlmMsg.Payload.MsgReceiveErrorCounter; + } + else + { + /* For any other unexpected error (e.g. CFE_SB_Q_RD_ERR_EID) */ + ++CFE_SB_Global.HKTlmMsg.Payload.InternalErrorCounter; + } + + CFE_SB_UnlockSharedData(__func__, __LINE__); + } +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +void CFE_SB_MessageTxn_SetEventAndStatus(CFE_SB_MessageTxn_State_t *TxnPtr, uint16 EventId, CFE_Status_t Status) +{ + if (TxnPtr->TransactionEventId == 0) + { + TxnPtr->TransactionEventId = EventId; + } + if (TxnPtr->Status == CFE_SUCCESS) + { + TxnPtr->Status = Status; + } +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +void CFE_SB_MessageTxn_SetRoutingMsgId(CFE_SB_MessageTxn_State_t *TxnPtr, CFE_SB_MsgId_t RoutingMsgId) +{ + /* validate the msgid in the message */ + if (!CFE_SB_IsValidMsgId(RoutingMsgId)) + { + CFE_SB_MessageTxn_SetEventAndStatus(TxnPtr, CFE_SB_SEND_INV_MSGID_EID, CFE_SB_BAD_ARGUMENT); + } + else + { + TxnPtr->RoutingMsgId = RoutingMsgId; + } +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +void CFE_SB_MessageTxn_SetContentSize(CFE_SB_MessageTxn_State_t *TxnPtr, size_t ContentSize) +{ + if (ContentSize > CFE_MISSION_SB_MAX_SB_MSG_SIZE) + { + CFE_SB_MessageTxn_SetEventAndStatus(TxnPtr, CFE_SB_MSG_TOO_BIG_EID, CFE_SB_MSG_TOO_BIG); + } + else + { + TxnPtr->ContentSize = ContentSize; + } +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +void CFE_SB_TransmitTxn_SetupFromMsg(CFE_SB_MessageTxn_State_t *TxnPtr, const CFE_MSG_Message_t *MsgPtr) +{ + CFE_Status_t Status; + CFE_MSG_Size_t MsgSize; + CFE_SB_MsgId_t MsgId; + + if (CFE_SB_MessageTxn_IsOK(TxnPtr)) + { + /* In this context, the user should have set the the size and MsgId in the content */ + Status = CFE_MSG_GetMsgId(MsgPtr, &MsgId); + if (Status == CFE_SUCCESS) + { + CFE_SB_MessageTxn_SetRoutingMsgId(TxnPtr, MsgId); + } + else + { + CFE_SB_MessageTxn_SetEventAndStatus(TxnPtr, CFE_SB_SEND_BAD_ARG_EID, Status); + } + } + + if (CFE_SB_MessageTxn_IsOK(TxnPtr)) + { + Status = CFE_MSG_GetSize(MsgPtr, &MsgSize); + if (Status == CFE_SUCCESS) + { + CFE_SB_MessageTxn_SetContentSize(TxnPtr, MsgSize); + } + else + { + CFE_SB_MessageTxn_SetEventAndStatus(TxnPtr, CFE_SB_SEND_BAD_ARG_EID, Status); + } + } +} + +/****************************************************************** + * + * TRANSMIT TRANSACTION IMPLEMENTATION FUNCTIONS + * + ******************************************************************/ + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +CFE_SB_MessageTxn_State_t *CFE_SB_TransmitTxn_Init(CFE_SB_TransmitTxn_State_t *TxnPtr, const void *RefMemPtr) +{ + CFE_SB_MessageTxn_Init(&TxnPtr->MessageTxn_State, TxnPtr->DestSet, CFE_PLATFORM_SB_MAX_DEST_PER_PKT, RefMemPtr); + TxnPtr->MessageTxn_State.IsTransmit = true; + + /* No matter what, the mem pointer from the caller should not be NULL */ + if (RefMemPtr == NULL) + { + CFE_SB_MessageTxn_SetEventAndStatus(&TxnPtr->MessageTxn_State, CFE_SB_SEND_BAD_ARG_EID, CFE_SB_BAD_ARGUMENT); + } + + return &TxnPtr->MessageTxn_State; +} + +/*---------------------------------------------------------------- + * + * Local Helper function + * Not invoked outside of this unit + * + *-----------------------------------------------------------------*/ +void CFE_SB_TransmitTxn_FindDestinations(CFE_SB_MessageTxn_State_t *TxnPtr, CFE_SB_BufferD_t *BufDscPtr) +{ + CFE_SB_PipeD_t * PipeDscPtr; + CFE_SB_DestinationD_t *DestPtr; + CFE_SB_PipeSetEntry_t *ContextPtr; + CFE_ES_AppId_t AppId; + bool IsAcceptable; + CFE_Status_t Status; + + /* + * get app id for loopback testing - + * This is only used if one or more of the destinations has its "IGNOREMINE" option set, + * but it should NOT be gotten while locked. So since we do not know (yet) if we need it, + * it is better to get it and not need it than need it and not have it. + */ + CFE_ES_GetAppID(&AppId); + + /* take semaphore to prevent a task switch during processing */ + CFE_SB_LockSharedData(__func__, __LINE__); + + /* Get the routing id */ + BufDscPtr->DestRouteId = CFE_SBR_GetRouteId(TxnPtr->RoutingMsgId); + + /* For an invalid route / no subscribers this whole logic can be skipped */ + if (CFE_SBR_IsValidRouteId(BufDscPtr->DestRouteId)) + { + /* If this is the origination, then update the message content (while locked) before actually sending */ + if (TxnPtr->IsEndpoint) + { + CFE_SBR_IncrementSequenceCounter(BufDscPtr->DestRouteId); + + /* Set the sequence count from the route */ + CFE_MSG_SetSequenceCount(&BufDscPtr->Content.Msg, CFE_SBR_GetSequenceCounter(BufDscPtr->DestRouteId)); + } + + /* Send the packet to all destinations */ + DestPtr = CFE_SBR_GetDestListHeadPtr(BufDscPtr->DestRouteId); + while (DestPtr != NULL && TxnPtr->NumPipes < TxnPtr->MaxPipes) + { + ContextPtr = NULL; + + if (DestPtr->Active == CFE_SB_ACTIVE) /* destination is active */ + { + PipeDscPtr = CFE_SB_LocatePipeDescByID(DestPtr->PipeId); + } + else + { + PipeDscPtr = NULL; + } + + if (CFE_SB_PipeDescIsMatch(PipeDscPtr, DestPtr->PipeId)) + { + if ((PipeDscPtr->Opts & CFE_SB_PIPEOPTS_IGNOREMINE) == 0 || + !CFE_RESOURCEID_TEST_EQUAL(PipeDscPtr->AppId, AppId)) + { + ContextPtr = &TxnPtr->PipeSet[TxnPtr->NumPipes]; + ++TxnPtr->NumPipes; + } + } + + if (ContextPtr != NULL) + { + memset(ContextPtr, 0, sizeof(*ContextPtr)); + + ContextPtr->PipeId = DestPtr->PipeId; + ContextPtr->SysQueueId = PipeDscPtr->SysQueueId; + + /* if Msg limit exceeded, log event, increment counter */ + /* and go to next destination */ + if (DestPtr->BuffCount >= DestPtr->MsgId2PipeLim) + { + ContextPtr->PendingEventId = CFE_SB_MSGID_LIM_ERR_EID; + ++CFE_SB_Global.HKTlmMsg.Payload.MsgLimitErrorCounter; + ++PipeDscPtr->SendErrors; + ++TxnPtr->NumPipeErrs; + } + else + { + CFE_SB_IncrBufUseCnt(BufDscPtr); + ++DestPtr->BuffCount; + + ++PipeDscPtr->CurrentQueueDepth; + if (PipeDscPtr->CurrentQueueDepth > PipeDscPtr->PeakQueueDepth) + { + PipeDscPtr->PeakQueueDepth = PipeDscPtr->CurrentQueueDepth; + } + } + } + + DestPtr = DestPtr->Next; + } + } + else + { + /* if there have been no subscriptions for this pkt, */ + /* increment the dropped pkt cnt, send event and return success */ + CFE_SB_Global.HKTlmMsg.Payload.NoSubscribersCounter++; + CFE_SB_MessageTxn_SetEventAndStatus(TxnPtr, CFE_SB_SEND_NO_SUBS_EID, CFE_SUCCESS); + } + + /* + * Remove this from whatever list it was in + * + * If it was a singleton/new buffer this has no effect. + * If it was a zero-copy buffer this removes it from the ZeroCopyList. + */ + CFE_SB_TrackingListRemove(&BufDscPtr->Link); + + /* clear the AppID field in case it was a zero copy buffer, + * as it is no longer owned by that app after broadcasting */ + BufDscPtr->AppId = CFE_ES_APPID_UNDEFINED; + + /* track the buffer as an in-transit message */ + CFE_SB_TrackingListAdd(&CFE_SB_Global.InTransitList, &BufDscPtr->Link); + + CFE_SB_UnlockSharedData(__func__, __LINE__); + + /* + * Lastly, if this is the origination point, now that all headers should + * have known values (including sequence) - invoke the mission-specific + * message origination action. This may update timestamps and/or compute + * any required error control fields. + */ + if (CFE_SB_MessageTxn_IsOK(TxnPtr) && TxnPtr->IsEndpoint) + { + /* Update any other system-specific MSG headers based on the current sequence */ + Status = CFE_MSG_OriginationAction(&BufDscPtr->Content.Msg, BufDscPtr->AllocatedSize, &IsAcceptable); + if (Status != CFE_SUCCESS || !IsAcceptable) + { + CFE_SB_MessageTxn_SetEventAndStatus(TxnPtr, CFE_SB_SEND_MESSAGE_INTEGRITY_FAIL_EID, Status); + } + } +} + +/*---------------------------------------------------------------- + * + * Local Helper function + * Not invoked outside of this unit + * + *-----------------------------------------------------------------*/ +int32 CFE_SB_MessageTxn_GetOsTimeout(const CFE_SB_MessageTxn_State_t *TxnPtr) +{ + int32 OsTimeout; + OS_time_t TimeNow; + + switch (TxnPtr->TimeoutMode) + { + case CFE_SB_MessageTxn_TimeoutMode_PEND: + OsTimeout = OS_PEND; + break; + case CFE_SB_MessageTxn_TimeoutMode_TIMED: + CFE_PSP_GetTime(&TimeNow); + OsTimeout = OS_TimeGetTotalMilliseconds(OS_TimeSubtract(TxnPtr->AbsTimeout, TimeNow)); + if (OsTimeout < 0) + { + /* timeout has already expired, so all remaining pipes should be CHECK only */ + OsTimeout = OS_CHECK; + } + break; + case CFE_SB_MessageTxn_TimeoutMode_POLL: + default: + OsTimeout = OS_CHECK; + break; + } + + return OsTimeout; +} + +/*---------------------------------------------------------------- + * + * Local Helper function + * Not invoked outside of this unit + * + *-----------------------------------------------------------------*/ +bool CFE_SB_TransmitTxn_PipeHandler(CFE_SB_MessageTxn_State_t *TxnPtr, CFE_SB_PipeSetEntry_t *ContextPtr, void *Arg) +{ + CFE_SB_DestinationD_t *DestPtr; + CFE_SB_PipeD_t * PipeDscPtr; + CFE_SB_BufferD_t * BufDscPtr; + + BufDscPtr = Arg; + + /* + * Write the buffer descriptor to the queue of the pipe. Note that + * accounting for depth and buffer limits was already done as part + * of "FindDestinations" assuming this write will be successful - which + * is the expected/typical result here. + */ + ContextPtr->OsStatus = + OS_QueuePut(ContextPtr->SysQueueId, &BufDscPtr, sizeof(BufDscPtr), CFE_SB_MessageTxn_GetOsTimeout(TxnPtr)); + + /* + * If it succeeded, nothing else to do. But if it fails then we must undo the + * optimistic depth accounting done earlier. + */ + if (ContextPtr->OsStatus != OS_SUCCESS) + { + ++TxnPtr->NumPipeErrs; + + CFE_SB_LockSharedData(__func__, __LINE__); + + if (ContextPtr->OsStatus == OS_QUEUE_FULL) + { + ContextPtr->PendingEventId = CFE_SB_Q_FULL_ERR_EID; + CFE_SB_Global.HKTlmMsg.Payload.PipeOverflowErrorCounter++; + } + else + { + /* Unexpected error while writing to queue. */ + ContextPtr->PendingEventId = CFE_SB_Q_WR_ERR_EID; + CFE_SB_Global.HKTlmMsg.Payload.InternalErrorCounter++; + } + + PipeDscPtr = CFE_SB_LocatePipeDescByID(ContextPtr->PipeId); + if (CFE_SB_PipeDescIsMatch(PipeDscPtr, ContextPtr->PipeId) && PipeDscPtr->CurrentQueueDepth > 0) + { + --PipeDscPtr->CurrentQueueDepth; + } + + DestPtr = CFE_SB_GetDestPtr(BufDscPtr->DestRouteId, ContextPtr->PipeId); + if (DestPtr != NULL && DestPtr->BuffCount > 0) + { + DestPtr->BuffCount--; + } + + CFE_SB_DecrBufUseCnt(BufDscPtr); + + CFE_SB_UnlockSharedData(__func__, __LINE__); + } + + /* always keep going when sending (broadcast) */ + return true; +} + +/*---------------------------------------------------------------- + * + * Local Helper function + * Not invoked outside of this unit + * + *-----------------------------------------------------------------*/ +void CFE_SB_MessageTxn_ProcessPipes(CFE_SB_MessageTxn_PipeHandler_t HandlerFunc, CFE_SB_MessageTxn_State_t *TxnPtr, + void *Arg) +{ + uint32 i; + CFE_SB_PipeSetEntry_t *ContextPtr; + bool should_continue; + + should_continue = true; + for (i = 0; should_continue && i < TxnPtr->NumPipes; ++i) + { + ContextPtr = &TxnPtr->PipeSet[i]; + + if (ContextPtr->PendingEventId == 0) + { + should_continue = HandlerFunc(TxnPtr, ContextPtr, Arg); + } + } +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +void CFE_SB_TransmitTxn_Execute(CFE_SB_MessageTxn_State_t *TxnPtr, CFE_SB_Buffer_t *BufPtr) +{ + int32 Status; + CFE_SB_BufferD_t *BufDscPtr; + + /* Sanity check on the input buffer - if this doesn't work, stop now */ + Status = CFE_SB_ZeroCopyBufferValidate(BufPtr, &BufDscPtr); + if (Status != CFE_SUCCESS) + { + /* There is currently no event defined for this */ + CFE_SB_MessageTxn_SetEventAndStatus(TxnPtr, 0, Status); + return; + } + + /* Save passed-in routing parameters into the descriptor */ + BufDscPtr->ContentSize = CFE_SB_MessageTxn_GetContentSize(TxnPtr); + BufDscPtr->MsgId = CFE_SB_MessageTxn_GetRoutingMsgId(TxnPtr); + + /* Convert the route to a set of pipes/destinations */ + CFE_SB_TransmitTxn_FindDestinations(TxnPtr, BufDscPtr); + + /* Note the above function always succeeds - even if no pipes are subscribed, + * the transaction will simply have 0 pipes and this next call becomes a no-op */ + CFE_SB_MessageTxn_ProcessPipes(CFE_SB_TransmitTxn_PipeHandler, TxnPtr, BufDscPtr); + + /* + * Decrement the buffer UseCount - This means that the caller + * should not use the buffer anymore after this call. + */ + CFE_SB_LockSharedData(__func__, __LINE__); + CFE_SB_DecrBufUseCnt(BufDscPtr); + CFE_SB_UnlockSharedData(__func__, __LINE__); +} + +/****************************************************************** + * + * RECEIVE TRANSACTION IMPLEMENTATION FUNCTIONS + * + ******************************************************************/ + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +CFE_SB_MessageTxn_State_t *CFE_SB_ReceiveTxn_Init(CFE_SB_ReceiveTxn_State_t *TxnPtr, const void *RefMemPtr) +{ + CFE_SB_MessageTxn_Init(&TxnPtr->MessageTxn_State, &TxnPtr->Source, 1, RefMemPtr); + TxnPtr->MessageTxn_State.IsTransmit = false; + + /* No matter what, the mem pointer from the caller should not be NULL */ + /* note that the event ID is different between send and recv */ + if (RefMemPtr == NULL) + { + CFE_SB_MessageTxn_SetEventAndStatus(&TxnPtr->MessageTxn_State, CFE_SB_RCV_BAD_ARG_EID, CFE_SB_BAD_ARGUMENT); + } + + return &TxnPtr->MessageTxn_State; +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +void CFE_SB_MessageTxn_SetEndpoint(CFE_SB_MessageTxn_State_t *TxnPtr, bool IsEndpoint) +{ + TxnPtr->IsEndpoint = IsEndpoint; +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +void CFE_SB_ReceiveTxn_SetPipeId(CFE_SB_MessageTxn_State_t *TxnPtr, CFE_SB_PipeId_t PipeId) +{ + CFE_SB_PipeD_t * PipeDscPtr; + CFE_SB_PipeSetEntry_t *ContextPtr; + + /* For now, there is just one of these */ + ContextPtr = TxnPtr->PipeSet; + memset(ContextPtr, 0, sizeof(*ContextPtr)); + ContextPtr->PipeId = PipeId; + TxnPtr->NumPipes = 1; + + PipeDscPtr = CFE_SB_LocatePipeDescByID(PipeId); + + CFE_SB_LockSharedData(__func__, __LINE__); + + /* If the pipe does not exist or PipeId is out of range... */ + if (!CFE_SB_PipeDescIsMatch(PipeDscPtr, PipeId)) + { + ContextPtr->PendingEventId = CFE_SB_BAD_PIPEID_EID; + CFE_SB_MessageTxn_SetEventAndStatus(TxnPtr, 0, CFE_SB_BAD_ARGUMENT); + ++TxnPtr->NumPipeErrs; + } + else + { + ContextPtr->SysQueueId = PipeDscPtr->SysQueueId; + + /* + * Un-reference any previous buffer from the last call. + * + * NOTE: This is historical behavior where apps call CFE_SB_ReceiveBuffer() + * in the loop within the app's main task. There is currently no separate + * API to "free" or unreference a buffer that was returned from SB. + * + * Instead, each time this function is invoked, it is implicitly interpreted + * as an indication that the caller is done with the previous buffer. + * + * Unfortunately this prevents pipe IDs from being serviced/shared across + * multiple child tasks in a worker pattern design. This may be changed + * in a future version of CFE to decouple these actions, to allow for + * multiple workers to service the same pipe. + */ + if (PipeDscPtr->LastBuffer != NULL) + { + /* Decrement the Buffer Use Count, which will Free buffer if it becomes 0 */ + CFE_SB_DecrBufUseCnt(PipeDscPtr->LastBuffer); + PipeDscPtr->LastBuffer = NULL; + } + } + + CFE_SB_UnlockSharedData(__func__, __LINE__); +} + +/*---------------------------------------------------------------- + * + * Local Helper function + * Not invoked outside of this unit + * + *-----------------------------------------------------------------*/ +void CFE_SB_ReceiveTxn_ExportReference(CFE_SB_MessageTxn_State_t *TxnPtr, CFE_SB_PipeSetEntry_t *ContextPtr, + CFE_SB_BufferD_t *BufDscPtr, CFE_SB_BufferD_t **ParentBufDscPtrP) +{ + CFE_SB_PipeD_t * PipeDscPtr; + CFE_SB_DestinationD_t *DestPtr; + + PipeDscPtr = CFE_SB_LocatePipeDescByID(ContextPtr->PipeId); + + /* Now re-lock to store the buffer in the pipe descriptor */ + CFE_SB_LockSharedData(__func__, __LINE__); + + /* + * NOTE: This uses the same PipeDscPtr that was found earlier. + * But it has to be revalidated because its theoretically possible + * the pipe got deleted between now and then. + */ + if (CFE_SB_PipeDescIsMatch(PipeDscPtr, ContextPtr->PipeId)) + { + /* + ** Load the pipe tables 'CurrentBuff' with the buffer descriptor + ** ptr corresponding to the message just read. This is done so that + ** the buffer can be released on the next receive call for this pipe. + ** + ** This counts as a new reference as it is being stored in the PipeDsc + */ + CFE_SB_IncrBufUseCnt(BufDscPtr); + PipeDscPtr->LastBuffer = BufDscPtr; + + /* + * Also set the Receivers pointer to the address of the actual message + * (currently this is "borrowing" the ref above, not its own ref) + */ + *ParentBufDscPtrP = BufDscPtr; + + /* get pointer to destination to be used in decrementing msg limit cnt*/ + DestPtr = CFE_SB_GetDestPtr(BufDscPtr->DestRouteId, ContextPtr->PipeId); + + /* + ** DestPtr would be NULL if the msg is unsubscribed to while it is on + ** the pipe. The BuffCount may be zero if the msg is unsubscribed to and + ** then resubscribed to while it is on the pipe. Both of these cases are + ** considered nominal and are handled by the code below. + */ + if (DestPtr != NULL && DestPtr->BuffCount > 0) + { + DestPtr->BuffCount--; + } + + if (PipeDscPtr->CurrentQueueDepth > 0) + { + --PipeDscPtr->CurrentQueueDepth; + } + } + else + { + CFE_SB_MessageTxn_SetEventAndStatus(TxnPtr, 0, CFE_SB_PIPE_RD_ERR); + + /* should send the bad pipe ID event here too */ + ContextPtr->PendingEventId = CFE_SB_BAD_PIPEID_EID; + } + + /* Always decrement the use count, for the ref that was in the queue */ + CFE_SB_DecrBufUseCnt(BufDscPtr); + + CFE_SB_UnlockSharedData(__func__, __LINE__); +} + +/*---------------------------------------------------------------- + * + * Local Helper function + * Not invoked outside of this unit + * + *-----------------------------------------------------------------*/ +bool CFE_SB_ReceiveTxn_PipeHandler(CFE_SB_MessageTxn_State_t *TxnPtr, CFE_SB_PipeSetEntry_t *ContextPtr, void *Arg) +{ + CFE_SB_BufferD_t * BufDscPtr; + CFE_SB_BufferD_t **ParentBufDscPtrP; + size_t BufDscSize; + + ParentBufDscPtrP = Arg; + + /* Read the buffer descriptor address from the queue. */ + ContextPtr->OsStatus = OS_QueueGet(ContextPtr->SysQueueId, &BufDscPtr, sizeof(BufDscPtr), &BufDscSize, + CFE_SB_MessageTxn_GetOsTimeout(TxnPtr)); + + /* + * translate the return value - + * + * CFE functions have their own set of RC values should not directly return OSAL codes + * The size should always match. If it does not, then generate CFE_SB_Q_RD_ERR_EID. + */ + + if (ContextPtr->OsStatus == OS_SUCCESS && BufDscPtr != NULL && BufDscSize == sizeof(BufDscPtr)) + { + CFE_SB_ReceiveTxn_ExportReference(TxnPtr, ContextPtr, BufDscPtr, ParentBufDscPtrP); + } + else + { + *ParentBufDscPtrP = NULL; + + if (ContextPtr->OsStatus == OS_QUEUE_EMPTY) + { + /* normal if using CFE_SB_POLL */ + CFE_SB_MessageTxn_SetEventAndStatus(TxnPtr, 0, CFE_SB_NO_MESSAGE); + } + else if (ContextPtr->OsStatus == OS_QUEUE_TIMEOUT) + { + /* normal if using a nonzero timeout */ + CFE_SB_MessageTxn_SetEventAndStatus(TxnPtr, 0, CFE_SB_TIME_OUT); + } + else + { + /* off-nominal condition, report an error event */ + CFE_SB_MessageTxn_SetEventAndStatus(TxnPtr, 0, CFE_SB_PIPE_RD_ERR); + ContextPtr->PendingEventId = CFE_SB_Q_RD_ERR_EID; + } + } + + /* Read ops only process one pipe */ + return false; +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +const CFE_SB_Buffer_t *CFE_SB_ReceiveTxn_Execute(CFE_SB_MessageTxn_State_t *TxnPtr) +{ + CFE_SB_BufferD_t * BufDscPtr; + const CFE_SB_Buffer_t *Result; + bool IsAcceptable; + CFE_Status_t Status; + + Result = NULL; + + while (CFE_SB_MessageTxn_IsOK(TxnPtr)) + { + BufDscPtr = NULL; + + /* + * Read from the pipe(s). Currently this is just one but someday could + * become more than one e.g. a high-pri and a low-pri queue. + */ + CFE_SB_MessageTxn_ProcessPipes(CFE_SB_ReceiveTxn_PipeHandler, TxnPtr, &BufDscPtr); + + /* If nothing received, then quit */ + if (BufDscPtr == NULL) + { + TxnPtr->RoutingMsgId = CFE_SB_INVALID_MSG_ID; + TxnPtr->ContentSize = 0; + Result = NULL; + break; + } + + if (TxnPtr->IsEndpoint) + { + Status = CFE_MSG_VerificationAction(&BufDscPtr->Content.Msg, BufDscPtr->AllocatedSize, &IsAcceptable); + if (Status != CFE_SUCCESS) + { + /* This typically should not happen - only if VerificationAction got bad arguments */ + IsAcceptable = false; + } + } + else + { + /* If no verification being done at this stage - consider everything "good" */ + IsAcceptable = true; + } + + if (IsAcceptable) + { + /* + * Replicate the buffer descriptor MsgId and ContentSize in the transaction. + * + * This does not use the functions that check the values because that will + * send an event and set an error status if they are bad. But on the recv side, + * it is already here - whatever we got should be returned. Error checking for + * size and MsgId should have been done on the transmit side, so they should never + * be bad at this point. + */ + TxnPtr->RoutingMsgId = BufDscPtr->MsgId; + TxnPtr->ContentSize = BufDscPtr->ContentSize; + Result = &BufDscPtr->Content; + break; + } + + /* Report an event indicating the buffer is being dropped */ + CFE_SB_MessageTxn_ReportSingleEvent(TxnPtr, TxnPtr->PipeSet, CFE_SB_RCV_MESSAGE_INTEGRITY_FAIL_EID); + + /* + * Also need to re-set the PipeId for proper accounting. This buffer will be dropped, + * and this decrements the use count and removes it from the LastBuffer pointer in the + * Pipe Descriptor + */ + CFE_SB_ReceiveTxn_SetPipeId(TxnPtr, TxnPtr->PipeSet->PipeId); + } + + return Result; +} diff --git a/modules/sb/fsw/src/cfe_sb_priv.h b/modules/sb/fsw/src/cfe_sb_priv.h index 737682936..b4a93014a 100644 --- a/modules/sb/fsw/src/cfe_sb_priv.h +++ b/modules/sb/fsw/src/cfe_sb_priv.h @@ -124,16 +124,18 @@ typedef struct CFE_SB_BufferD CFE_SB_BufferLink_t Link; /**< Links for inclusion in the tracking lists */ /** - * Actual MsgId of the content, cached here to avoid repeat - * calls into CFE_MSG API during traversal/delivery of the message. + * MsgId that should be used for routing/delivering the message. Traditionally, + * this is the same as the MsgId inside the content, but cached for easier access. + * However, the user may also choose to route messages explicitly and thus this + * message ID could differ from the one inside the message content. * - * MsgId is set for buffers which contain actual data in transit. AppId is unset - * while in transit, as it may be sent to multiple apps. + * MsgId is set for buffers in transit. AppId is unset while in transit, as it + * may be sent to multiple apps. * * During zero copy buffer initial allocation, the MsgId is not known at this time * and should be set to the invalid msg ID. */ - CFE_SB_MsgId_t MsgId; + CFE_SBR_RouteId_t DestRouteId; /** * Current owner of the buffer, if owned by a single app. @@ -146,11 +148,10 @@ typedef struct CFE_SB_BufferD */ CFE_ES_AppId_t AppId; - size_t AllocatedSize; /**< Total size of this descriptor (including descriptor itself) */ - size_t ContentSize; /**< Actual size of message content currently stored in the buffer */ - CFE_MSG_Type_t ContentType; /**< Type of message content currently stored in the buffer */ + CFE_SB_MsgId_t MsgId; - bool NeedsUpdate; /**< If message should get its header fields automatically updated */ + size_t AllocatedSize; /**< Total size of this descriptor (including descriptor itself) */ + size_t ContentSize; /**< Actual size of message content currently stored in the buffer */ uint16 UseCount; /**< Number of active references to this buffer in the system */ @@ -168,10 +169,10 @@ typedef struct CFE_SB_BufferD typedef struct { CFE_SB_PipeId_t PipeId; - uint8 Opts; - uint8 Spare; CFE_ES_AppId_t AppId; osal_id_t SysQueueId; + uint8 Opts; + uint8 Spare; uint16 SendErrors; uint16 MaxQueueDepth; uint16 CurrentQueueDepth; @@ -259,29 +260,82 @@ typedef struct } CFE_SB_Global_t; /****************************************************************************** -** Typedef: CFE_SB_SendErrEventBuf_t -** -** Purpose: -** This structure is used to store event information during a send. -*/ + * Typedef: CFE_SB_PipeSetEntry_t + */ typedef struct { - uint32 EventId; - int32 OsStatus; CFE_SB_PipeId_t PipeId; -} CFE_SB_SendErrEventBuf_t; + osal_id_t SysQueueId; + uint16 PendingEventId; + int32 OsStatus; +} CFE_SB_PipeSetEntry_t; -/****************************************************************************** -** Typedef: CFE_SB_EventBuf_t -** -** Purpose: -** This structure is used to store event information during a send. -*/ +typedef enum +{ + CFE_SB_MessageTxn_TimeoutMode_POLL, /**< Transaction should not block */ + CFE_SB_MessageTxn_TimeoutMode_PEND, /**< Transaction should block indefinitely */ + CFE_SB_MessageTxn_TimeoutMode_TIMED /**< Transaction should block for a limited amount of time */ +} CFE_SB_MessageTxn_TimeoutMode_t; + +/** + * \brief Tracks the status of a message/buffer transmit transaction + * + * This includes the list of destinations to send to, and the status of each, + * as well as any pending event IDs from the transaction setup. + * + */ +typedef struct +{ + bool IsTransmit; + bool IsEndpoint; + + uint16 NumPipes; + uint16 MaxPipes; + uint16 NumPipeErrs; + uint16 TransactionEventId; + + CFE_SB_MessageTxn_TimeoutMode_t TimeoutMode; + int32_t UserTimeoutParam; + OS_time_t AbsTimeout; + + CFE_Status_t Status; + size_t ContentSize; + CFE_SB_MsgId_t RoutingMsgId; + + const void *RefMemPtr; + + CFE_SB_PipeSetEntry_t *PipeSet; +} CFE_SB_MessageTxn_State_t; + +/** + * \brief Tracks the status of a message/buffer transmit transaction + * + * This includes the list of destinations to send to, and the status of each, + * as well as any pending event IDs from the transaction setup. + * + */ +typedef struct +{ + CFE_SB_MessageTxn_State_t MessageTxn_State; + + CFE_SB_PipeSetEntry_t DestSet[CFE_PLATFORM_SB_MAX_DEST_PER_PKT]; +} CFE_SB_TransmitTxn_State_t; + +/** + * \brief Tracks the status of a message/buffer transmit transaction + * + * This includes the list of destinations to send to, and the status of each, + * as well as any pending event IDs from the transaction setup. + * + */ typedef struct { - uint32 EvtsToSnd; - CFE_SB_SendErrEventBuf_t EvtBuf[CFE_PLATFORM_SB_MAX_DEST_PER_PKT]; -} CFE_SB_EventBuf_t; + CFE_SB_MessageTxn_State_t MessageTxn_State; + + CFE_SB_PipeSetEntry_t Source; +} CFE_SB_ReceiveTxn_State_t; + +typedef bool (*CFE_SB_MessageTxn_PipeHandler_t)(CFE_SB_MessageTxn_State_t *, CFE_SB_PipeSetEntry_t *, void *); /* ** Software Bus Function Prototypes @@ -410,20 +464,6 @@ int32 CFE_SB_UnsubscribeWithAppId(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId, */ int32 CFE_SB_UnsubscribeFull(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId, uint8 Scope, CFE_ES_AppId_t AppId); -/*---------------------------------------------------------------------------------------*/ -/** - * \brief Internal routine to validate a transmit message before sending - * - * \param[in] MsgPtr Pointer to the message to validate - * \param[out] MsgIdPtr Message Id of message - * \param[out] SizePtr Size of message - * \param[out] RouteIdPtr Route ID of the message (invalid if none) - * - * \return Execution status, see \ref CFEReturnCodes - */ -int32 CFE_SB_TransmitMsgValidate(const CFE_MSG_Message_t *MsgPtr, CFE_SB_MsgId_t *MsgIdPtr, CFE_MSG_Size_t *SizePtr, - CFE_SBR_RouteId_t *RouteIdPtr); - /*---------------------------------------------------------------------------------------*/ /** * Release all zero-copy buffers associated with the given app ID. @@ -513,7 +553,7 @@ int32 CFE_SB_SendSubscriptionReport(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId * * @returns grant/deny status */ -uint32 CFE_SB_RequestToSendEvent(CFE_ES_TaskId_t TaskId, uint32 Bit); +uint32 CFE_SB_RequestToSendEvent(CFE_ES_TaskId_t TaskId, int32 Bit); /*---------------------------------------------------------------------------------------*/ /** @@ -521,7 +561,7 @@ uint32 CFE_SB_RequestToSendEvent(CFE_ES_TaskId_t TaskId, uint32 Bit); * * This should be called after a successful CFE_SB_RequestToSendEvent() */ -void CFE_SB_FinishSendEvent(CFE_ES_TaskId_t TaskId, uint32 Bit); +void CFE_SB_FinishSendEvent(CFE_ES_TaskId_t TaskId, int32 Bit); /*---------------------------------------------------------------------------------------*/ /** @@ -619,41 +659,6 @@ CFE_SB_BufferD_t *CFE_SB_GetBufferFromPool(size_t MaxMsgSize); */ void CFE_SB_ReturnBufferToPool(CFE_SB_BufferD_t *bd); -/*---------------------------------------------------------------------------------------*/ -/** - * \brief Broadcast a SB buffer descriptor to all destinations in route - * - * Internal routine that implements the logic of transmitting a message buffer - * to all destinations subscribed in the SB route. - * - * As this function will broadcast the message to any number of destinations (0-many), - * and some may be successful and some may fail, the status cannot be expressed - * in any single error code, so this does not return any status. - * - * Instead, this routine handles all potential outcomes on its own, and does - * not expect the caller to handle any delivery issues. Also note that the general - * design pattern of the software bus is a "send and forget" model where the sender does - * not know (or care) what entities are subscribed to the data being generated. - * - * - For any undeliverable destination (limit, OSAL error, etc), a proper event is generated. - * - For any successful queueing, the buffer use count is incremented - * - * The caller is expected to hold a reference (use count) of the buffer prior to invoking - * this routine, representing itself, which is then consumed by this routine. - * - * \note _This call will "consume" the buffer by decrementing the buffer use count_ after - * broadcasting the message to all subscribed pipes. - * - * The caller should not access the buffer again after calling this function, as it may - * be deallocated at any time. If the caller wishes to continue accessing the buffer, - * it should explicitly increment the use count before calling this, which will prevent - * deallocation. - * - * \param[in] BufDscPtr Pointer to the buffer descriptor to broadcast - * \param[in] RouteId Route to send to - */ -void CFE_SB_BroadcastBufferToRoute(CFE_SB_BufferD_t *BufDscPtr, CFE_SBR_RouteId_t RouteId); - /*---------------------------------------------------------------------------------------*/ /** * \brief Perform basic sanity check on the Zero Copy handle @@ -745,6 +750,439 @@ CFE_SB_DestinationD_t *CFE_SB_GetDestPtr(CFE_SBR_RouteId_t RouteId, CFE_SB_PipeI **/ size_t CFE_SB_MsgHdrSize(const CFE_MSG_Message_t *MsgPtr); +/* + * Message Transmit/Receive Transaction implementation functions + */ + +/*---------------------------------------------------------------------------------------*/ +/** + * \brief Set up transaction initial state + * + * Helper function to initialize the common parts of a transmit/receive transaction + * + * \param[out] TxnPtr Transaction object to initialize + * \param[inout] PipeSet Pointer to pipe entry buffer + * \param[in] MaxPipes Number of entries in PipeSet + * \param[in] RefMemPtr User-supplied Opaque object pointer for event logging + */ +void CFE_SB_MessageTxn_Init(CFE_SB_MessageTxn_State_t *TxnPtr, CFE_SB_PipeSetEntry_t *PipeSet, uint16 MaxPipes, + const void *RefMemPtr); + +/*---------------------------------------------------------------------------------------*/ +/** + * \brief Check transaction current state + * + * Checks if the transaction is in a good state. + * + * \param[in] TxnPtr Transaction object to check + * \returns Boolean indicating transaction condition + * \retval true if the transaction is OK + * \retval false if the transaction has an error + */ +static inline bool CFE_SB_MessageTxn_IsOK(const CFE_SB_MessageTxn_State_t *TxnPtr) +{ + return (TxnPtr->Status == CFE_SUCCESS && TxnPtr->TransactionEventId == 0); +} + +/*---------------------------------------------------------------------------------------*/ +/** + * \brief Get transaction content size + * + * Obtains the size of the object/message being passed in this transaction + * + * \param[in] TxnPtr Transaction object + * \returns Size of message/object being passed + */ +static inline size_t CFE_SB_MessageTxn_GetContentSize(const CFE_SB_MessageTxn_State_t *TxnPtr) +{ + return TxnPtr->ContentSize; +} + +/*---------------------------------------------------------------------------------------*/ +/** + * \brief Get transaction MsgId used for routing + * + * Obtains the MsgId used for routing of the object/message being passed in this transaction + * + * \note This MsgId may be different than the one embedded within the message + * + * \param[in] TxnPtr Transaction object + * \returns MsgId used for routing of message/object being passed + */ +static inline CFE_SB_MsgId_t CFE_SB_MessageTxn_GetRoutingMsgId(CFE_SB_MessageTxn_State_t *TxnPtr) +{ + return TxnPtr->RoutingMsgId; +} + +/*---------------------------------------------------------------------------------------*/ +/** + * \brief Get transaction status code + * + * Obtains the CFE status code associated with the transaction + * + * \param[in] TxnPtr Transaction object + * \returns CFE Status code + */ +static inline CFE_Status_t CFE_SB_MessageTxn_GetStatus(CFE_SB_MessageTxn_State_t *TxnPtr) +{ + return TxnPtr->Status; +} + +/*---------------------------------------------------------------------------------------*/ +/** + * \brief Set transaction status code and event + * + * If an off-nominal condition occurs, this routine sets the specified status and/or event code + * that should be returned to the caller to indicate that condition. + * + * A value of 0 (which is an alias to #CFE_SUCCESS for status codes) can be passed for either + * parameter if there is no defined code for the particular condition. + * + * The transaction object stores the first non-zero value for event ID or status code. + * + * \param[inout] TxnPtr Transaction object + * \param[in] EventId The event ID to set + * \param[in] Status The status code to set + */ +void CFE_SB_MessageTxn_SetEventAndStatus(CFE_SB_MessageTxn_State_t *TxnPtr, uint16 EventId, CFE_Status_t Status); + +/*---------------------------------------------------------------------------------------*/ +/** + * \brief Set transaction MsgId used for routing + * + * Configures the MsgId used for routing of the object/message being passed in this transaction + * + * \note This MsgId may be different than the one embedded within the message + * + * \param[inout] TxnPtr Transaction object + * \param[in] RoutingMsgId MsgId used for routing of message/object being passed + */ +void CFE_SB_MessageTxn_SetRoutingMsgId(CFE_SB_MessageTxn_State_t *TxnPtr, CFE_SB_MsgId_t RoutingMsgId); + +/*---------------------------------------------------------------------------------------*/ +/** + * \brief Set transaction content size + * + * Configures the size of the object/message being passed in this transaction + * + * \param[inout] TxnPtr Transaction object + * \param[in] ContentSize Size of message/object being passed + */ +void CFE_SB_MessageTxn_SetContentSize(CFE_SB_MessageTxn_State_t *TxnPtr, size_t ContentSize); + +/*---------------------------------------------------------------------------------------*/ +/** + * \brief Configure transaction time out + * + * Configures the relative timeout (in milliseconds) for this transaction. This is based + * on sampling the PSP clock at the time this function is invoked, and adding the relative + * time to it. + * + * This should be called early in the transaction configuration process. + * + * \param[inout] TxnPtr Transaction object + * \param[in] Timeout Timeout for message/object transaction + */ +void CFE_SB_MessageTxn_SetTimeout(CFE_SB_MessageTxn_State_t *TxnPtr, int32 Timeout); + +/*---------------------------------------------------------------------------------------*/ +/** + * \brief Configure message endpoint (origination/termination) processing + * + * For a transmit transaction this enables origination processing. If configured as + * true, then the CFE_MSG_OriginationAction() function is invoked prior to sending the message. + * The specific action(s) depend on the MSG module implementation, and may include: + * - Updating the sequence number + * - Updating the message timestamp + * - Calculating/Appending any applicable CRC, checksum, or other error control field + * - Any other system-specific message header updates + * + * For a receive transaction, this enables message verification. If configured as + * true, then the CFE_MSG_VerificationAction() function will be invoked before the message buffer + * is returned to the caller. The verification criteria depends on the MSG implementation, but + * is typically expected to be the inverse of the origination processing. That is, items that + * were calculated or updated as part of the origination process can be verified during this step. + * If verification fails, then an event will be logged, the message will be dropped, and the + * implementation will get the next message in the queue (if any). + * + * \note The receive verification function in the default MSG implementation always returns + * success, thus should be backward compatible with previous CFE versions that did not perform + * any verification at the SB level, leaving it up to the individual app to check. To make use + * of this feature, the implementer must also provide an alternate implemenation of + * CFE_MSG_VerificationAction() that performs the desired checks for their particular use-case. + * + * \sa CFE_MSG_OriginationAction() + * \sa CFE_MSG_VerificationAction() + * + * \param[inout] TxnPtr Transaction object + * \param[in] IsEndpoint Pass as "true" to enable endpoint (origination/termination) message processing + */ +void CFE_SB_MessageTxn_SetEndpoint(CFE_SB_MessageTxn_State_t *TxnPtr, bool IsEndpoint); + +/*---------------------------------------------------------------------------------------*/ +/** + * \brief Helper function to get the OSAL timeout to use + * + * Returns the relative timeout (in milliseconds) for any pending queue operation(s). + * This reflects the amount of time left from the initial call to CFE_SB_MessageTxn_SetTimeout(). + * + * If the original timeout was to PEND, this always returns -1 (OS_PEND). + * If the original timeout was to POLL, this always returns 0 (OS_CHECK). + * If the original timeout was some nonzero value, this returns the time left, in milliseconds, + * based on the current time as obtained from the PSP. + * + * \param[in] TxnPtr Transaction object + * \returns Timeout to use for OSAL routines that may block + */ +int32 CFE_SB_MessageTxn_GetOsTimeout(const CFE_SB_MessageTxn_State_t *TxnPtr); + +/*---------------------------------------------------------------------------------------*/ +/** + * \brief Facilitates reporting of a single event related to a transmit transaction + * + * Internal routine that assembles the following information about how an event should + * be reported: + * + * - Complete message text (human-readable) + * - The type of event (information, error, etc) + * - The loop-detection bit to use (request to send/clear to send) + * + * \param[inout] TxnPtr Transaction object + * \param[in] TskId Calling task identifier + * \param[in] EventId Event to report + * \param[out] EvtMsg Message buffer + * \param[in] EvtMsgSize Size of EvtMsg buffer + * \param[in] ContextPtr Context information (may be NULL for general transaction events) + * \param[out] EventType Buffer to store event type + * \param[out] ReqBit Buffer to store request/loop detect bit + */ +void CFE_SB_MessageTxn_GetEventDetails(const CFE_SB_MessageTxn_State_t *TxnPtr, const CFE_SB_PipeSetEntry_t *ContextPtr, + uint16 EventId, CFE_ES_TaskId_t TskId, char *EvtMsg, size_t EvtMsgSize, + CFE_EVS_EventType_Enum_t *EventType, int32 *ReqBit); + +/*---------------------------------------------------------------------------------------*/ +/** + * \brief Reports a single event related to a transmit transaction + * + * Internal routine that performs the basic flow of sending a single event ID related + * to a transmit transaction. This uses CFE_SB_TransmitTxn_GetEventDetails() to determine + * how the event should be reported, then checks/sets the Request bit (loop detect), sends the + * event, then clears the request bit. + * + * \param[in] TxnPtr Transaction object + * \param[in] ContextPtr Context information (may be NULL for general transaction events) + * \param[in] EventId Event to report + * + * \returns Boolean indicating if the event constitutes a transaction failure + * \retval true if the transmit transaction failed as a result (event is an error) + * \retval false if this was informational (event is benign, e.g. no subscribers) + */ +bool CFE_SB_MessageTxn_ReportSingleEvent(const CFE_SB_MessageTxn_State_t *TxnPtr, + const CFE_SB_PipeSetEntry_t *ContextPtr, uint16 EventId); + +/*---------------------------------------------------------------------------------------*/ +/** + * \brief Implements all reporting and accouting associated with a transmit transaction + * + * Internal routine that sends all events and increments any telemetry counters associated + * with the transaction. This should be called as the last step of a transmit operation. + * + * \param[in] TxnPtr Transaction object + */ +void CFE_SB_MessageTxn_ReportEvents(const CFE_SB_MessageTxn_State_t *TxnPtr); + +/*---------------------------------------------------------------------------------------*/ +/** + * \brief Process all pipes identified in the transaction object + * + * The provided HandlerFunc will be invoked for every item in the PipeSet within the transaction + * object. The handler function can stop the loop by returning "false". + * + * \param[in] HandlerFunc Handler function to call + * \param[inout] TxnPtr Transaction object, passed through to handler + * \param[inout] Arg Opaque argument to pass to handler + */ +void CFE_SB_MessageTxn_ProcessPipes(CFE_SB_MessageTxn_PipeHandler_t HandlerFunc, CFE_SB_MessageTxn_State_t *TxnPtr, + void *Arg); + +/* + * Receive Transaction implementation/helper functions + * These functions are specific to the receive-side operation + */ + +/*---------------------------------------------------------------------------------------*/ +/** + * \brief Initialize a receive transaction + * + * This should be the first function called to initialize a transaction state object + * that has been newly allocated. The object will be put into a safe initial state. + * + * The RefMemPtr should refer to the object/buffer that the user intends to receive from the + * software bus. This is kept as part of the transaction mainly for logging/event purposes, + * the address may be reported in events if the transaction is unsuccessful. + * + * \param[out] TxnPtr Transaction object to initialize + * \param[in] RefMemPtr Pointer to user object/buffer being received (opaque) + */ +CFE_SB_MessageTxn_State_t *CFE_SB_ReceiveTxn_Init(CFE_SB_ReceiveTxn_State_t *TxnPtr, const void *RefMemPtr); + +/*---------------------------------------------------------------------------------------*/ +/** + * \brief Sets the Pipe ID to read for a receive transaction + * + * Currently, receive transactions only deal with a single pipe. This sets the pipe ID to + * read to receive the object. + * + * \param[inout] TxnPtr Transaction object + * \param[in] PipeId Pipe ID to read from + */ +void CFE_SB_ReceiveTxn_SetPipeId(CFE_SB_MessageTxn_State_t *TxnPtr, CFE_SB_PipeId_t PipeId); + +/*---------------------------------------------------------------------------------------*/ +/** + * \brief Pipe handler function for receive transactions + * + * Helper function to implement reading of a pipe during a receive transaction. This + * is only used via CFE_SB_MessageTxn_ProcessPipes(), but declared here so it can be unit + * tested. + * + * This implements the logic of transmitting a message buffer to all destinations that were + * identified via CFE_SB_TransmitTxn_FindDestinations(). + * + * As this function will broadcast the message to any number of destinations (0-many), + * and some may be successful and some may fail, this function always returns true + * to continue the loop inside CFE_SB_MessageTxn_ProcessPipes(). + * + * The status/result of every queue write operation is kept as part of the transaction + * status object. Event reporting related those operations is deferred to the + * CFE_SB_TransmitTxn_ReportEvents() function, which should be invoked at the end + * of the transaction to report any delivery issues. + * + * The caller is expected to hold a reference (use count) of the buffer prior to invoking + * this routine, representing itself, plus the number of active destinations. + * + * \note If any queue write operation is _not_ successful, the use count will be decremented. + * \sa CFE_SB_MessageTxn_ProcessPipes + * + * \param[inout] TxnPtr Transaction object + * \param[in] ContextPtr Pointer to pipe entry within transaction + * \param[inout] Arg Opaque argument for API, should be a CFE_SB_BufferD_t** + * \returns always false to stop the parent loop (receive transactions only read a single pipe) + */ +bool CFE_SB_ReceiveTxn_PipeHandler(CFE_SB_MessageTxn_State_t *TxnPtr, CFE_SB_PipeSetEntry_t *ContextPtr, void *Arg); + +/*---------------------------------------------------------------------------------------*/ +/** + * \brief Executes a receive transaction + * + * Implements reading of the pipe(s) and exporting information such as the content pointer, content size, + * and message ID. + * + * \param[inout] TxnPtr Transaction object + * \returns Pointer to buffer that was read + * \retval NULL if no message was read (e.g. if a timeout occurred or polling an empty queue) + */ +const CFE_SB_Buffer_t *CFE_SB_ReceiveTxn_Execute(CFE_SB_MessageTxn_State_t *TxnPtr); + +/* + * Transmit Transaction implementation/helper functions + * These functions are specific to the transmit-side operation + */ + +/*---------------------------------------------------------------------------------------*/ +/** + * \brief Initialize a transmit transaction + * + * This should be the first function called to initialize a transaction state object + * that has been newly allocated. The object will be put into a safe initial state. + * + * The RefMemPtr should refer to the object/buffer that the user intends to send on the + * software bus. This is kept as part of the transaction mainly for logging/event purposes, + * the address may be reported in events if the transaction is unsuccessful. + * + * \param[out] TxnPtr Transaction object to initialize + * \param[in] RefMemPtr Pointer to user object/buffer being transmitted (opaque) + */ +CFE_SB_MessageTxn_State_t *CFE_SB_TransmitTxn_Init(CFE_SB_TransmitTxn_State_t *TxnPtr, const void *RefMemPtr); + +/*---------------------------------------------------------------------------------------*/ +/** + * \brief Set up a transmit transaction from a CFE MSG object + * + * Extracts the routing information - specifically MsgId and Size - from the message content. + * + * Software Bus transmit operations typically operate based on the MsgId and Size information + * that the application stores the message header prior to transmission. This function implements + * that traditional behavior by pulling this information out of the message and caching it in + * the transaction state object for use during routing and delivery of the object. + * + * The information is extracted from the message using the CFE MSG API calls. + * + * \param[inout] TxnPtr Transaction object + * \param[in] MsgPtr Pointer to message being transmitted + */ +void CFE_SB_TransmitTxn_SetupFromMsg(CFE_SB_MessageTxn_State_t *TxnPtr, const CFE_MSG_Message_t *MsgPtr); + +/*---------------------------------------------------------------------------------------*/ +/** + * \brief Find the complete set of destination pipes for the given transaction + * + * Looks up the routing information (via the SBR subsystem/module) and collects the set of + * active destinations (Pipe IDs) that the message will need to be broadcast to. + * + * If no destinations are found, then this sets the transaction status to generate a + * NO SUBSCRIBERS event, but it does not actually send the event from here. + * + * \sa CFE_SB_TransmitTxn_ReportEvents() + * + * \note This also increments the buffer use count for every destination found, in anticipation + * of writing the buffer address into the underlying queue. If the subsequent write is not + * actually successful, then the count must be decremented accordingly, to keep the reference + * counts correct. + * + * \param[inout] TxnPtr Transaction object + * \param[inout] BufDscPtr Buffer descriptor that is pending broadcast + */ +void CFE_SB_TransmitTxn_FindDestinations(CFE_SB_MessageTxn_State_t *TxnPtr, CFE_SB_BufferD_t *BufDscPtr); + +/*---------------------------------------------------------------------------------------*/ +/** + * \brief Pipe handler function for transmit transactions + * + * Helper function to implement reading of a pipe during a transmit transaction. This + * is only used via CFE_SB_MessageTxn_ProcessPipes(), but declared here so it can be unit + * tested. + * + * \sa CFE_SB_MessageTxn_ProcessPipes + * + * \param[inout] TxnPtr Transaction object + * \param[in] ContextPtr Pointer to pipe entry within transaction + * \param[inout] Arg Opaque argument for API, should be a CFE_SB_BufferD_t* + * \returns always true to continue the parent loop (transmit transactions process all pipes) + */ +bool CFE_SB_TransmitTxn_PipeHandler(CFE_SB_MessageTxn_State_t *TxnPtr, CFE_SB_PipeSetEntry_t *ContextPtr, void *Arg); + +/*---------------------------------------------------------------------------------------*/ +/** + * \brief Executes the transmit transaction + * + * Internal routine that finds all active destinations for the route and broadcasts the + * buffer to those destinations. Any errors or off-nominal events that occur will be stored + * in the transaction object for deferred reporting via CFE_SB_TransmitTxn_ReportEvents(). + * + * \note Upon successful operation, this function decrements the use count of the buffer. + * The calling routine is expected to hold one reference to the buffer being transmitted, which + * is then consumed by this call. If the caller intends to retain a reference to the buffer, + * the use count must be incremented prior to invoking this function. + * + * However, if this returns a non-successful status code then the use count will _not_ be + * decremented - but this can generally only fail if the passed-in buffer does not validate. + * + * \param[inout] TxnPtr Transaction object + * \param[inout] BufPtr Buffer object that is pending to be broadcast + */ +void CFE_SB_TransmitTxn_Execute(CFE_SB_MessageTxn_State_t *TxnPtr, CFE_SB_Buffer_t *BufPtr); + /* * Software Bus Message Handler Function prototypes */ diff --git a/modules/sb/fsw/src/cfe_sb_task.c b/modules/sb/fsw/src/cfe_sb_task.c index e3168d8a7..72c0ed7e7 100644 --- a/modules/sb/fsw/src/cfe_sb_task.c +++ b/modules/sb/fsw/src/cfe_sb_task.c @@ -44,7 +44,7 @@ typedef struct { const char *Filename; /* File name for error reporting */ osal_id_t Fd; /* File id for writing */ - uint32 FileSize; /* File size for reporting */ + size_t FileSize; /* File size for reporting */ uint32 EntryCount; /* Entry count for reporting */ int32 Status; /* File write status */ } CFE_SB_FileWriteCallback_t; diff --git a/modules/sb/ut-coverage/sb_UT.c b/modules/sb/ut-coverage/sb_UT.c index b6b7cb141..770b6963b 100644 --- a/modules/sb/ut-coverage/sb_UT.c +++ b/modules/sb/ut-coverage/sb_UT.c @@ -390,7 +390,7 @@ void Test_SB_Main_RcvErr(void) UT_SetDeferredRetcode(UT_KEY(OS_QueueGet), 1, -1); CFE_SB_TaskMain(); - CFE_UtAssert_EVENTCOUNT(6); + CFE_UtAssert_EVENTCOUNT(7); CFE_UtAssert_EVENTSENT(CFE_SB_INIT_EID); @@ -2883,6 +2883,591 @@ void Test_Unsubscribe_GetDestPtr(void) CFE_UtAssert_TEARDOWN(CFE_SB_DeletePipe(TestPipe2)); } +void Test_TransmitTxn_Init(void) +{ + /* Test case for: + * void CFE_SB_TransmitTxn_Init(CFE_SB_TransmitTxn_State_t *TxnPtr, const void *RefMemPtr); + */ + CFE_SB_TransmitTxn_State_t TxnBuf; + CFE_SB_MessageTxn_State_t *Txn; + uint32 MyData; + + /* Call to ensure coverage */ + memset(&Txn, 0xEE, sizeof(Txn)); + MyData = 123; + UtAssert_ADDRESS_EQ(Txn = CFE_SB_TransmitTxn_Init(&TxnBuf, &MyData), &TxnBuf); + + /* This should have cleared everything */ + UtAssert_ADDRESS_EQ(Txn->RefMemPtr, &MyData); + UtAssert_ZERO(Txn->NumPipes); + UtAssert_ZERO(Txn->NumPipeErrs); + UtAssert_ZERO(Txn->TransactionEventId); + UtAssert_ZERO(Txn->TimeoutMode); + UtAssert_ZERO(Txn->ContentSize); + UtAssert_BOOL_FALSE(Txn->IsEndpoint); +} + +void Test_MessageTxn_SetEventAndStatus(void) +{ + /* Test function for: + * void CFE_SB_MessageTxn_SetEventAndStatus(CFE_SB_MessageTxn_State_t *TxnPtr, + * uint16 EventId, CFE_Status_t Status) + */ + CFE_SB_MessageTxn_State_t Txn; + + /* + * although this function is used throughout the other tests, this is needed to target + * certain branches/paths that don't get executed. Namely - this should only store + * the first error/event that occurs. + */ + + /* Set only an event ID first, then attempt to set both */ + memset(&Txn, 0, sizeof(Txn)); + + UtAssert_BOOL_TRUE(CFE_SB_MessageTxn_IsOK(&Txn)); + + CFE_SB_MessageTxn_SetEventAndStatus(&Txn, CFE_SB_MSG_TOO_BIG_EID, CFE_SUCCESS); + UtAssert_UINT16_EQ(Txn.TransactionEventId, CFE_SB_MSG_TOO_BIG_EID); + UtAssert_INT32_EQ(Txn.Status, CFE_SUCCESS); + UtAssert_BOOL_FALSE(CFE_SB_MessageTxn_IsOK(&Txn)); + + CFE_SB_MessageTxn_SetEventAndStatus(&Txn, CFE_SB_SEND_INV_MSGID_EID, CFE_SB_BAD_ARGUMENT); + UtAssert_UINT16_EQ(Txn.TransactionEventId, CFE_SB_MSG_TOO_BIG_EID); + UtAssert_INT32_EQ(Txn.Status, CFE_SB_BAD_ARGUMENT); + UtAssert_BOOL_FALSE(CFE_SB_MessageTxn_IsOK(&Txn)); + + /* Set only a status code first, then attempt to set both */ + memset(&Txn, 0, sizeof(Txn)); + + CFE_SB_MessageTxn_SetEventAndStatus(&Txn, 0, CFE_SB_BUF_ALOC_ERR); + UtAssert_UINT16_EQ(Txn.TransactionEventId, 0); + UtAssert_INT32_EQ(Txn.Status, CFE_SB_BUF_ALOC_ERR); + UtAssert_BOOL_FALSE(CFE_SB_MessageTxn_IsOK(&Txn)); + + CFE_SB_MessageTxn_SetEventAndStatus(&Txn, CFE_SB_SEND_INV_MSGID_EID, CFE_SB_BAD_ARGUMENT); + UtAssert_UINT16_EQ(Txn.TransactionEventId, CFE_SB_SEND_INV_MSGID_EID); + UtAssert_INT32_EQ(Txn.Status, CFE_SB_BUF_ALOC_ERR); + UtAssert_BOOL_FALSE(CFE_SB_MessageTxn_IsOK(&Txn)); +} + +void Test_MessageTxn_Timeout(void) +{ + /* Test case for: + * void CFE_SB_MessageTxn_SetTimeout(CFE_SB_MessageTxn_State_t *TxnPtr, int32 Timeout); + * int32 CFE_SB_MessageTxn_GetOsTimeout(const CFE_SB_MessageTxn_State_t *TxnPtr); + */ + CFE_SB_MessageTxn_State_t Txn; + OS_time_t TestTime; + + memset(&Txn, 0, sizeof(Txn)); + + UtAssert_VOIDCALL(CFE_SB_MessageTxn_SetTimeout(&Txn, CFE_SB_POLL)); + UtAssert_INT32_EQ(CFE_SB_MessageTxn_GetOsTimeout(&Txn), OS_CHECK); + + UtAssert_VOIDCALL(CFE_SB_MessageTxn_SetTimeout(&Txn, CFE_SB_PEND_FOREVER)); + UtAssert_INT32_EQ(CFE_SB_MessageTxn_GetOsTimeout(&Txn), OS_PEND); + + TestTime = OS_TimeFromTotalSeconds(1000000000); + UT_SetDataBuffer(UT_KEY(CFE_PSP_GetTime), &TestTime, sizeof(TestTime), false); + UtAssert_VOIDCALL(CFE_SB_MessageTxn_SetTimeout(&Txn, 100)); + + UT_SetDataBuffer(UT_KEY(CFE_PSP_GetTime), &TestTime, sizeof(TestTime), false); + UtAssert_INT32_EQ(CFE_SB_MessageTxn_GetOsTimeout(&Txn), 100); + + TestTime = OS_TimeAdd(TestTime, OS_TimeFromTotalMilliseconds(10)); + UT_SetDataBuffer(UT_KEY(CFE_PSP_GetTime), &TestTime, sizeof(TestTime), false); + UtAssert_INT32_EQ(CFE_SB_MessageTxn_GetOsTimeout(&Txn), 90); + + TestTime = OS_TimeAdd(TestTime, OS_TimeFromTotalSeconds(1)); + UT_SetDataBuffer(UT_KEY(CFE_PSP_GetTime), &TestTime, sizeof(TestTime), false); + UtAssert_INT32_EQ(CFE_SB_MessageTxn_GetOsTimeout(&Txn), OS_CHECK); + + UtAssert_VOIDCALL(CFE_SB_MessageTxn_SetTimeout(&Txn, -1000)); + UtAssert_INT32_EQ(Txn.Status, CFE_SB_BAD_ARGUMENT); +} + +void Test_MessageTxn_SetupFromMsg(void) +{ + /* Test case for: + * CFE_Status_t CFE_SB_TransmitTxn_SetupFromMsg(CFE_SB_MessageTxn_State_t *TxnPtr, const CFE_MSG_Message_t + * *MsgPtr); + */ + CFE_SB_MessageTxn_State_t Txn; + CFE_MSG_Message_t Msg; + CFE_SB_MsgId_t MsgId; + CFE_MSG_Size_t MsgSize; + + memset(&Msg, 0, sizeof(Msg)); + + /* Transaction already failed case (no-op) */ + memset(&Txn, 0, sizeof(Txn)); + Txn.Status = -20; + UtAssert_VOIDCALL(CFE_SB_TransmitTxn_SetupFromMsg(&Txn, &Msg)); + UtAssert_INT32_EQ(Txn.Status, -20); + + /* CFE_MSG_GetMsgId() fail case */ + memset(&Txn, 0, sizeof(Txn)); + UT_SetDeferredRetcode(UT_KEY(CFE_MSG_GetMsgId), 1, -10); + UtAssert_VOIDCALL(CFE_SB_TransmitTxn_SetupFromMsg(&Txn, &Msg)); + UtAssert_INT32_EQ(Txn.Status, -10); + UtAssert_UINT32_EQ(Txn.TransactionEventId, CFE_SB_SEND_BAD_ARG_EID); + + /* Invalid MsgId case */ + memset(&Txn, 0, sizeof(Txn)); + MsgId = CFE_SB_INVALID_MSG_ID; + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); + UtAssert_VOIDCALL(CFE_SB_TransmitTxn_SetupFromMsg(&Txn, &Msg)); + UtAssert_INT32_EQ(Txn.Status, CFE_SB_BAD_ARGUMENT); + UtAssert_UINT32_EQ(Txn.TransactionEventId, CFE_SB_SEND_INV_MSGID_EID); + + /* CFE_MSG_GetSize() fail case */ + memset(&Txn, 0, sizeof(Txn)); + MsgId = SB_UT_TLM_MID; + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); + UT_SetDeferredRetcode(UT_KEY(CFE_MSG_GetSize), 1, -11); + UtAssert_VOIDCALL(CFE_SB_TransmitTxn_SetupFromMsg(&Txn, &Msg)); + UtAssert_INT32_EQ(Txn.Status, -11); + UtAssert_UINT32_EQ(Txn.TransactionEventId, CFE_SB_SEND_BAD_ARG_EID); + + /* Message too big case */ + memset(&Txn, 0, sizeof(Txn)); + MsgId = SB_UT_TLM_MID; + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); + MsgSize = 1 + CFE_MISSION_SB_MAX_SB_MSG_SIZE; + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &MsgSize, sizeof(MsgSize), false); + UtAssert_VOIDCALL(CFE_SB_TransmitTxn_SetupFromMsg(&Txn, &Msg)); + UtAssert_INT32_EQ(Txn.Status, CFE_SB_MSG_TOO_BIG); + UtAssert_UINT32_EQ(Txn.TransactionEventId, CFE_SB_MSG_TOO_BIG_EID); + + /* Nominal case */ + memset(&Txn, 0, sizeof(Txn)); + MsgId = SB_UT_TLM_MID; + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); + MsgSize = sizeof(Msg); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &MsgSize, sizeof(MsgSize), false); + + UtAssert_VOIDCALL(CFE_SB_TransmitTxn_SetupFromMsg(&Txn, &Msg)); + UtAssert_INT32_EQ(Txn.Status, CFE_SUCCESS); + UtAssert_ZERO(Txn.TransactionEventId); + CFE_UtAssert_MSGID_EQ(Txn.RoutingMsgId, SB_UT_TLM_MID); + UtAssert_UINT32_EQ(Txn.ContentSize, sizeof(Msg)); +} + +void Test_TransmitTxn_FindDestinations(void) +{ + /* Test case for: + * void CFE_SB_TransmitTxn_FindDestinations(CFE_SB_MessageTxn_State_t *TxnPtr, CFE_SB_BufferD_t *BufDscPtr); + */ + + CFE_SB_TransmitTxn_State_t TxnBuf; + CFE_SB_MessageTxn_State_t *Txn; + CFE_SB_BufferD_t BufDsc; + CFE_SB_PipeD_t * PipeDscPtr; + CFE_SB_PipeId_t PipeId = CFE_SB_INVALID_PIPE; + CFE_SB_MsgId_t MsgId = SB_UT_TLM_MID; + CFE_SBR_RouteId_t RouteId; + CFE_SB_DestinationD_t * DestPtr; + + memset(&BufDsc, 0, sizeof(BufDsc)); + CFE_SB_TrackingListReset(&BufDsc.Link); /* so tracking list ops work */ + + CFE_UtAssert_SETUP(CFE_SB_CreatePipe(&PipeId, 2, "TestPipe")); + CFE_UtAssert_SETUP(CFE_SB_SubscribeFull(MsgId, PipeId, CFE_SB_DEFAULT_QOS, 2, CFE_SB_MSG_GLOBAL)); + PipeDscPtr = CFE_SB_LocatePipeDescByID(PipeId); + RouteId = CFE_SBR_GetRouteId(MsgId); + DestPtr = CFE_SB_GetDestPtr(RouteId, PipeId); + Txn = CFE_SB_TransmitTxn_Init(&TxnBuf, &BufDsc.Content); + PipeDscPtr->PeakQueueDepth = 1; + + CFE_SB_Global.HKTlmMsg.Payload.NoSubscribersCounter = 0; + + /* No subscriber case */ + Txn->RoutingMsgId = CFE_SB_INVALID_MSG_ID; + UtAssert_VOIDCALL(CFE_SB_TransmitTxn_FindDestinations(Txn, &BufDsc)); + UtAssert_UINT32_EQ(CFE_SB_Global.HKTlmMsg.Payload.NoSubscribersCounter, 1); + UtAssert_UINT32_EQ(Txn->TransactionEventId, CFE_SB_SEND_NO_SUBS_EID); + UtAssert_UINT32_EQ(BufDsc.UseCount, 0); + + /* Nominal Case 1 */ + memset(&BufDsc, 0, sizeof(BufDsc)); + Txn = CFE_SB_TransmitTxn_Init(&TxnBuf, &BufDsc.Content); + CFE_SB_TrackingListReset(&BufDsc.Link); /* so tracking list ops work */ + Txn->RoutingMsgId = MsgId; + UtAssert_VOIDCALL(CFE_SB_TransmitTxn_FindDestinations(Txn, &BufDsc)); + UtAssert_UINT32_EQ(Txn->NumPipes, 1); + CFE_UtAssert_RESOURCEID_EQ(Txn->PipeSet[0].PipeId, PipeId); + UtAssert_UINT32_EQ(Txn->PipeSet[0].PendingEventId, 0); + UtAssert_UINT32_EQ(BufDsc.UseCount, 1); + UtAssert_UINT32_EQ(DestPtr->BuffCount, 1); + UtAssert_UINT32_EQ(PipeDscPtr->CurrentQueueDepth, 1); + UtAssert_UINT32_EQ(PipeDscPtr->PeakQueueDepth, 1); + UtAssert_UINT32_EQ(PipeDscPtr->SendErrors, 0); + UtAssert_UINT32_EQ(Txn->NumPipeErrs, 0); + + /* Nominal Case 2 */ + memset(&BufDsc, 0, sizeof(BufDsc)); + Txn = CFE_SB_TransmitTxn_Init(&TxnBuf, &BufDsc.Content); + CFE_SB_TrackingListReset(&BufDsc.Link); /* so tracking list ops work */ + Txn->RoutingMsgId = MsgId; + UtAssert_VOIDCALL(CFE_SB_TransmitTxn_FindDestinations(Txn, &BufDsc)); + UtAssert_UINT32_EQ(Txn->NumPipes, 1); + CFE_UtAssert_RESOURCEID_EQ(Txn->PipeSet[0].PipeId, PipeId); + UtAssert_UINT32_EQ(Txn->PipeSet[0].PendingEventId, 0); + UtAssert_UINT32_EQ(BufDsc.UseCount, 1); + UtAssert_UINT32_EQ(DestPtr->BuffCount, 2); + UtAssert_UINT32_EQ(PipeDscPtr->CurrentQueueDepth, 2); + UtAssert_UINT32_EQ(PipeDscPtr->PeakQueueDepth, 2); + UtAssert_UINT32_EQ(PipeDscPtr->SendErrors, 0); + UtAssert_UINT32_EQ(Txn->NumPipeErrs, 0); + + /* MsgLim Error Case */ + memset(&BufDsc, 0, sizeof(BufDsc)); + Txn = CFE_SB_TransmitTxn_Init(&TxnBuf, &BufDsc.Content); + CFE_SB_TrackingListReset(&BufDsc.Link); /* so tracking list ops work */ + Txn->RoutingMsgId = MsgId; + UtAssert_VOIDCALL(CFE_SB_TransmitTxn_FindDestinations(Txn, &BufDsc)); + UtAssert_UINT32_EQ(Txn->NumPipes, 1); + CFE_UtAssert_RESOURCEID_EQ(Txn->PipeSet[0].PipeId, PipeId); + UtAssert_UINT32_EQ(Txn->PipeSet[0].PendingEventId, CFE_SB_MSGID_LIM_ERR_EID); + UtAssert_ZERO(BufDsc.UseCount); + UtAssert_UINT32_EQ(DestPtr->BuffCount, 2); + UtAssert_UINT32_EQ(PipeDscPtr->CurrentQueueDepth, 2); + UtAssert_UINT32_EQ(PipeDscPtr->PeakQueueDepth, 2); + UtAssert_UINT32_EQ(PipeDscPtr->SendErrors, 1); + UtAssert_UINT32_EQ(Txn->NumPipeErrs, 1); + DestPtr->BuffCount = 0; + + /* Destination Inactive Case */ + memset(&BufDsc, 0, sizeof(BufDsc)); + Txn = CFE_SB_TransmitTxn_Init(&TxnBuf, &BufDsc.Content); + CFE_SB_TrackingListReset(&BufDsc.Link); /* so tracking list ops work */ + Txn->RoutingMsgId = MsgId; + DestPtr->Active = CFE_SB_INACTIVE; + UtAssert_VOIDCALL(CFE_SB_TransmitTxn_FindDestinations(Txn, &BufDsc)); + UtAssert_ZERO(Txn->NumPipes); + UtAssert_UINT32_EQ(BufDsc.UseCount, 0); + UtAssert_UINT32_EQ(DestPtr->BuffCount, 0); + DestPtr->Active = CFE_SB_ACTIVE; + + /* Pipe "Ignore Mine" Option Case w/Matching AppID */ + Txn = CFE_SB_TransmitTxn_Init(&TxnBuf, &BufDsc.Content); + Txn->RoutingMsgId = MsgId; + PipeDscPtr->Opts |= CFE_SB_PIPEOPTS_IGNOREMINE; + UtAssert_VOIDCALL(CFE_SB_TransmitTxn_FindDestinations(Txn, &BufDsc)); + UtAssert_ZERO(Txn->NumPipes); + UtAssert_UINT32_EQ(BufDsc.UseCount, 0); + UtAssert_UINT32_EQ(DestPtr->BuffCount, 0); + + /* Pipe "Ignore Mine" Option Case w/Non-Matching AppID */ + Txn = CFE_SB_TransmitTxn_Init(&TxnBuf, &BufDsc.Content); + Txn->RoutingMsgId = MsgId; + PipeDscPtr->AppId = CFE_ES_APPID_UNDEFINED; + UtAssert_VOIDCALL(CFE_SB_TransmitTxn_FindDestinations(Txn, &BufDsc)); + UtAssert_UINT32_EQ(Txn->NumPipes, 1); + UtAssert_UINT32_EQ(BufDsc.UseCount, 1); + UtAssert_UINT32_EQ(DestPtr->BuffCount, 1); + CFE_ES_GetAppID(&PipeDscPtr->AppId); + PipeDscPtr->Opts &= ~CFE_SB_PIPEOPTS_IGNOREMINE; + + /* DestPtr List too long - this emulates a hypothetical bug in SBR allowing list to grow too long */ + /* Hack to make it infinite length */ + DestPtr->Next = DestPtr; + Txn = CFE_SB_TransmitTxn_Init(&TxnBuf, &BufDsc.Content); + Txn->RoutingMsgId = MsgId; + UtAssert_VOIDCALL(CFE_SB_TransmitTxn_FindDestinations(Txn, &BufDsc)); + UtAssert_UINT32_EQ(Txn->NumPipes, CFE_PLATFORM_SB_MAX_DEST_PER_PKT); + + CFE_UtAssert_TEARDOWN(CFE_SB_DeletePipe(PipeId)); +} + +void Test_TransmitTxn_PipeHandler(void) +{ + /* Test function for: + * bool CFE_SB_TransmitTxn_PipeHandler(CFE_SB_MessageTxn_State_t *TxnPtr, CFE_SB_PipeSetEntry_t *ContextPtr, void + * *Arg); + */ + + CFE_SB_TransmitTxn_State_t TxnBuf; + CFE_SB_MessageTxn_State_t *Txn; + CFE_SB_PipeId_t PipeId = CFE_SB_INVALID_PIPE; + CFE_SB_MsgId_t MsgId = SB_UT_TLM_MID; + CFE_SB_BufferD_t SBBufD; + + memset(&SBBufD, 0, sizeof(SBBufD)); + memset(&TxnBuf, 0, sizeof(TxnBuf)); + CFE_SB_TrackingListReset(&SBBufD.Link); /* so tracking list ops work */ + Txn = CFE_SB_TransmitTxn_Init(&TxnBuf, &SBBufD.Content); + + CFE_UtAssert_SETUP(CFE_SB_CreatePipe(&PipeId, 3, "TestPipe")); + CFE_UtAssert_SETUP(CFE_SB_Subscribe(MsgId, PipeId)); + + SBBufD.DestRouteId = CFE_SBR_GetRouteId(MsgId); + + CFE_SB_LocatePipeDescByID(PipeId)->CurrentQueueDepth = 1; + CFE_SB_GetDestPtr(SBBufD.DestRouteId, PipeId)->BuffCount = 1; + + Txn->NumPipes = 6; + Txn->NumPipeErrs = 1; + Txn->PipeSet[0].PipeId = PipeId; + Txn->PipeSet[1].PipeId = PipeId; + Txn->PipeSet[2].PipeId = PipeId; + Txn->PipeSet[2].PendingEventId = 1; + Txn->PipeSet[3].PipeId = PipeId; + Txn->PipeSet[4].PipeId = PipeId; + Txn->PipeSet[5].PipeId = SB_UT_ALTERNATE_INVALID_PIPEID; + + UT_SetDeferredRetcode(UT_KEY(OS_QueuePut), 2, OS_QUEUE_FULL); + UT_SetDeferredRetcode(UT_KEY(OS_QueuePut), 1, OS_ERROR); + UT_SetDeferredRetcode(UT_KEY(OS_QueuePut), 1, OS_ERROR); + UT_SetDeferredRetcode(UT_KEY(OS_QueuePut), 1, OS_ERROR); + + UtAssert_VOIDCALL(CFE_SB_MessageTxn_ProcessPipes(CFE_SB_TransmitTxn_PipeHandler, Txn, &SBBufD)); + UtAssert_STUB_COUNT(OS_QueuePut, 5); + UtAssert_UINT32_EQ(Txn->NumPipeErrs, 5); + UtAssert_UINT32_EQ(Txn->PipeSet[0].PendingEventId, 0); + UtAssert_UINT32_EQ(Txn->PipeSet[1].PendingEventId, CFE_SB_Q_FULL_ERR_EID); + UtAssert_UINT32_EQ(Txn->PipeSet[2].PendingEventId, 1); + UtAssert_UINT32_EQ(Txn->PipeSet[3].PendingEventId, CFE_SB_Q_WR_ERR_EID); + UtAssert_UINT32_EQ(Txn->PipeSet[4].PendingEventId, CFE_SB_Q_WR_ERR_EID); + UtAssert_UINT32_EQ(Txn->PipeSet[5].PendingEventId, CFE_SB_Q_WR_ERR_EID); + + CFE_UtAssert_TEARDOWN(CFE_SB_DeletePipe(PipeId)); +} + +void Test_TransmitTxn_Execute(void) +{ + /* Test case for: + * CFE_Status_t CFE_SB_TransmitTxn_Execute(CFE_SB_MessageTxn_State_t *TxnPtr, CFE_SB_Buffer_t *BufPtr); + */ + CFE_SB_BufferD_t SBBufD; + CFE_SB_TransmitTxn_State_t TxnBuf; + CFE_SB_MessageTxn_State_t *Txn; + CFE_ES_AppId_t MyAppId; + CFE_SB_PipeId_t PipeId = CFE_SB_INVALID_PIPE; + CFE_SB_MsgId_t MsgId = SB_UT_TLM_MID; + + memset(&SBBufD, 0, sizeof(SBBufD)); + memset(&TxnBuf, 0, sizeof(TxnBuf)); + CFE_SB_TrackingListReset(&SBBufD.Link); /* so tracking list ops work */ + Txn = CFE_SB_TransmitTxn_Init(&TxnBuf, &SBBufD.Content); + CFE_UtAssert_SETUP(CFE_SB_CreatePipe(&PipeId, 2, "TestPipe")); + CFE_UtAssert_SETUP(CFE_ES_GetAppID(&MyAppId)); + + /* no subs - this should still keep status as SUCCESS but trigger CFE_SB_SEND_NO_SUBS_EID event */ + SBBufD.AppId = MyAppId; + UtAssert_VOIDCALL(CFE_SB_TransmitTxn_Execute(Txn, &SBBufD.Content)); + UtAssert_STUB_COUNT(OS_QueuePut, 0); + UtAssert_UINT32_EQ(Txn->TransactionEventId, CFE_SB_SEND_NO_SUBS_EID); + UtAssert_INT32_EQ(Txn->Status, CFE_SUCCESS); + UtAssert_BOOL_FALSE(CFE_RESOURCEID_TEST_DEFINED(SBBufD.AppId)); + + /* add a subscriber - nominal case */ + CFE_UtAssert_SETUP(CFE_SB_SubscribeFull(MsgId, PipeId, CFE_SB_DEFAULT_QOS, 2, CFE_SB_MSG_GLOBAL)); + Txn = CFE_SB_TransmitTxn_Init(&TxnBuf, &SBBufD.Content); + Txn->RoutingMsgId = MsgId; + SBBufD.AppId = MyAppId; + UtAssert_VOIDCALL(CFE_SB_TransmitTxn_Execute(Txn, &SBBufD.Content)); + UtAssert_BOOL_TRUE(CFE_SB_MessageTxn_IsOK(Txn)); + UtAssert_STUB_COUNT(OS_QueuePut, 1); + UtAssert_BOOL_FALSE(CFE_RESOURCEID_TEST_DEFINED(SBBufD.AppId)); + + /* error writing to the pipe - this also still keeps status as SUCCESS but trigger CFE_SB_Q_WR_ERR_EID */ + Txn = CFE_SB_TransmitTxn_Init(&TxnBuf, &SBBufD.Content); + Txn->RoutingMsgId = MsgId; + SBBufD.AppId = MyAppId; + UT_SetDeferredRetcode(UT_KEY(OS_QueuePut), 1, OS_ERROR); + UtAssert_VOIDCALL(CFE_SB_TransmitTxn_Execute(Txn, &SBBufD.Content)); + UtAssert_BOOL_TRUE(CFE_SB_MessageTxn_IsOK(Txn)); + UtAssert_UINT32_EQ(Txn->PipeSet[0].PendingEventId, CFE_SB_Q_WR_ERR_EID); + UtAssert_STUB_COUNT(OS_QueuePut, 2); + UtAssert_BOOL_FALSE(CFE_RESOURCEID_TEST_DEFINED(SBBufD.AppId)); + + /* Validation fail */ + Txn = CFE_SB_TransmitTxn_Init(&TxnBuf, &SBBufD.Content); + UtAssert_VOIDCALL(CFE_SB_TransmitTxn_Execute(Txn, &SBBufD.Content)); + UtAssert_BOOL_FALSE(CFE_SB_MessageTxn_IsOK(Txn)); + UtAssert_INT32_EQ(Txn->Status, CFE_SB_BUFFER_INVALID); + UtAssert_STUB_COUNT(OS_QueuePut, 2); + + CFE_UtAssert_TEARDOWN(CFE_SB_DeletePipe(PipeId)); +} + +void Test_MessageTxn_GetEventDetails(void) +{ + /* Test case for: + * void CFE_SB_MessageTxn_GetEventDetails(const CFE_SB_MessageTxn_State_t *TxnPtr, CFE_ES_TaskId_t TskId, uint16 + * EventId,char *EvtMsg, size_t EvtMsgSize, const CFE_SB_PipeSetEntry_t *ContextPtr,CFE_EVS_EventType_Enum_t + * *EventType, int32 *ReqBit); + */ + + CFE_SB_MessageTxn_State_t Txn; + CFE_SB_PipeSetEntry_t Entry; + CFE_ES_TaskId_t MyTskId; + char EvtMsg[64]; + CFE_EVS_EventType_Enum_t EvType; + int32 EvReqBit; + CFE_SB_PipeId_t PipeId; + + CFE_UtAssert_SETUP(CFE_ES_GetTaskID(&MyTskId)); + CFE_UtAssert_SETUP(CFE_SB_CreatePipe(&PipeId, 3, "TestPipe")); + CFE_SB_MessageTxn_Init(&Txn, &Entry, 1, &PipeId); + EvReqBit = 0; + EvType = 0; + Entry.PipeId = PipeId; + + memset(EvtMsg, 0xAA, sizeof(EvtMsg)); + UtAssert_VOIDCALL( + CFE_SB_MessageTxn_GetEventDetails(&Txn, NULL, 0, MyTskId, EvtMsg, sizeof(EvtMsg), &EvType, &EvReqBit)); + UtAssert_ZERO(EvtMsg[0]); + UtAssert_ZERO(EvReqBit); + + memset(EvtMsg, 0xAA, sizeof(EvtMsg)); + UtAssert_VOIDCALL(CFE_SB_MessageTxn_GetEventDetails(&Txn, NULL, CFE_SB_SEND_BAD_ARG_EID, MyTskId, EvtMsg, + sizeof(EvtMsg), &EvType, &EvReqBit)); + UtAssert_NONZERO(EvtMsg[0]); + UtAssert_NOT_NULL(memchr(EvtMsg, 0, sizeof(EvtMsg))); + UtAssert_UINT32_EQ(EvReqBit, CFE_SB_SEND_BAD_ARG_EID_BIT); + + memset(EvtMsg, 0xAA, sizeof(EvtMsg)); + UtAssert_VOIDCALL(CFE_SB_MessageTxn_GetEventDetails(&Txn, NULL, CFE_SB_SEND_INV_MSGID_EID, MyTskId, EvtMsg, + sizeof(EvtMsg), &EvType, &EvReqBit)); + UtAssert_NONZERO(EvtMsg[0]); + UtAssert_UINT32_EQ(EvReqBit, CFE_SB_SEND_INV_MSGID_EID_BIT); + UtAssert_NOT_NULL(memchr(EvtMsg, 0, sizeof(EvtMsg))); + + memset(EvtMsg, 0xAA, sizeof(EvtMsg)); + UtAssert_VOIDCALL(CFE_SB_MessageTxn_GetEventDetails(&Txn, NULL, CFE_SB_MSG_TOO_BIG_EID, MyTskId, EvtMsg, + sizeof(EvtMsg), &EvType, &EvReqBit)); + UtAssert_NONZERO(EvtMsg[0]); + UtAssert_NOT_NULL(memchr(EvtMsg, 0, sizeof(EvtMsg))); + UtAssert_UINT32_EQ(EvReqBit, CFE_SB_MSG_TOO_BIG_EID_BIT); + + memset(EvtMsg, 0xAA, sizeof(EvtMsg)); + UtAssert_VOIDCALL(CFE_SB_MessageTxn_GetEventDetails(&Txn, NULL, CFE_SB_SEND_NO_SUBS_EID, MyTskId, EvtMsg, + sizeof(EvtMsg), &EvType, &EvReqBit)); + UtAssert_NONZERO(EvtMsg[0]); + UtAssert_NOT_NULL(memchr(EvtMsg, 0, sizeof(EvtMsg))); + UtAssert_UINT32_EQ(EvReqBit, CFE_SB_SEND_NO_SUBS_EID_BIT); + + memset(EvtMsg, 0xAA, sizeof(EvtMsg)); + UtAssert_VOIDCALL(CFE_SB_MessageTxn_GetEventDetails(&Txn, &Entry, CFE_SB_GET_BUF_ERR_EID, MyTskId, EvtMsg, + sizeof(EvtMsg), &EvType, &EvReqBit)); + UtAssert_NONZERO(EvtMsg[0]); + UtAssert_NOT_NULL(memchr(EvtMsg, 0, sizeof(EvtMsg))); + UtAssert_UINT32_EQ(EvReqBit, CFE_SB_GET_BUF_ERR_EID_BIT); + + memset(EvtMsg, 0xAA, sizeof(EvtMsg)); + UtAssert_VOIDCALL(CFE_SB_MessageTxn_GetEventDetails(&Txn, &Entry, CFE_SB_MSGID_LIM_ERR_EID, MyTskId, EvtMsg, + sizeof(EvtMsg), &EvType, &EvReqBit)); + UtAssert_NONZERO(EvtMsg[0]); + UtAssert_NOT_NULL(memchr(EvtMsg, 0, sizeof(EvtMsg))); + UtAssert_UINT32_EQ(EvReqBit, CFE_SB_MSGID_LIM_ERR_EID_BIT); + + memset(EvtMsg, 0xAA, sizeof(EvtMsg)); + UtAssert_VOIDCALL(CFE_SB_MessageTxn_GetEventDetails(&Txn, &Entry, CFE_SB_Q_FULL_ERR_EID, MyTskId, EvtMsg, + sizeof(EvtMsg), &EvType, &EvReqBit)); + UtAssert_NONZERO(EvtMsg[0]); + UtAssert_NOT_NULL(memchr(EvtMsg, 0, sizeof(EvtMsg))); + UtAssert_UINT32_EQ(EvReqBit, CFE_SB_Q_FULL_ERR_EID_BIT); + + memset(EvtMsg, 0xAA, sizeof(EvtMsg)); + UtAssert_VOIDCALL(CFE_SB_MessageTxn_GetEventDetails(&Txn, NULL, CFE_SB_Q_WR_ERR_EID, MyTskId, EvtMsg, + sizeof(EvtMsg), &EvType, &EvReqBit)); + UtAssert_NONZERO(EvtMsg[0]); + UtAssert_NOT_NULL(memchr(EvtMsg, 0, sizeof(EvtMsg))); + UtAssert_UINT32_EQ(EvReqBit, CFE_SB_Q_WR_ERR_EID_BIT); + + CFE_UtAssert_TEARDOWN(CFE_SB_DeletePipe(PipeId)); +} + +void Test_MessageTxn_ReportSingleEvent(void) +{ + /* Test case for: + * bool CFE_SB_MessageTxn_ReportSingleEvent(uint16 EventId, const CFE_SB_MessageTxn_State_t *TxnPtr, const + * CFE_SB_PipeSetEntry_t *ContextPtr); + */ + CFE_SB_PipeSetEntry_t Entry; + CFE_SB_MessageTxn_State_t Txn; + CFE_SB_PipeId_t PipeId; + CFE_ES_TaskId_t MyTskId; + + memset(&Txn, 0, sizeof(Txn)); + memset(&Entry, 0, sizeof(Entry)); + CFE_UtAssert_SETUP(CFE_SB_CreatePipe(&PipeId, 3, "TestPipe")); + CFE_UtAssert_SETUP(CFE_ES_GetTaskID(&MyTskId)); + Txn.NumPipes = 1; + Txn.PipeSet = &Entry; + Entry.PipeId = PipeId; + + /* Event ID == 0 is reserved for no event, nothing to report */ + UT_ClearEventHistory(); + UtAssert_BOOL_FALSE(CFE_SB_MessageTxn_ReportSingleEvent(&Txn, NULL, 0)); + CFE_UtAssert_EVENTCOUNT(0); + + /* No subscribers should be an information event (not an error) */ + UT_ClearEventHistory(); + UtAssert_BOOL_FALSE(CFE_SB_MessageTxn_ReportSingleEvent(&Txn, NULL, CFE_SB_SEND_NO_SUBS_EID)); + CFE_UtAssert_EVENTCOUNT(1); + CFE_UtAssert_EVENTSENT(CFE_SB_SEND_NO_SUBS_EID); + + /* Queue write failure should be an error */ + /* Note that with context != NULL, it looks up the pipe name, which generates a debug event */ + UT_ClearEventHistory(); + UtAssert_BOOL_TRUE(CFE_SB_MessageTxn_ReportSingleEvent(&Txn, &Entry, CFE_SB_Q_WR_ERR_EID)); + CFE_UtAssert_EVENTCOUNT(2); + CFE_UtAssert_EVENTSENT(CFE_SB_Q_WR_ERR_EID); + CFE_UtAssert_EVENTSENT(CFE_SB_GETPIPENAME_EID); + + /* Check that the loop-avoidance works */ + CFE_SB_RequestToSendEvent(MyTskId, CFE_SB_MSG_TOO_BIG_EID_BIT); + UT_ClearEventHistory(); + UtAssert_BOOL_TRUE(CFE_SB_MessageTxn_ReportSingleEvent(&Txn, NULL, CFE_SB_MSG_TOO_BIG_EID)); + CFE_UtAssert_EVENTCOUNT(0); + CFE_SB_FinishSendEvent(MyTskId, CFE_SB_MSG_TOO_BIG_EID_BIT); + + CFE_UtAssert_TEARDOWN(CFE_SB_DeletePipe(PipeId)); +} + +void Test_MessageTxn_ReportEvents(void) +{ + /* Test case for: + * void CFE_SB_MessageTxn_ReportEvents(const CFE_SB_MessageTxn_State_t *TxnPtr); + */ + CFE_SB_PipeSetEntry_t PipeSetEntry; + CFE_SB_MessageTxn_State_t Txn; + + memset(&Txn, 0, sizeof(Txn)); + Txn.PipeSet = &PipeSetEntry; + Txn.NumPipes = 1; + Txn.MaxPipes = 1; + + /* nominal */ + UtAssert_VOIDCALL(CFE_SB_MessageTxn_ReportEvents(&Txn)); + UtAssert_ZERO(CFE_SB_Global.HKTlmMsg.Payload.MsgSendErrorCounter); + + /* with an event at the transaction level, known to be an error */ + Txn.TransactionEventId = CFE_SB_MSG_TOO_BIG_EID; + Txn.IsTransmit = true; + UtAssert_VOIDCALL(CFE_SB_MessageTxn_ReportEvents(&Txn)); + UtAssert_UINT32_EQ(CFE_SB_Global.HKTlmMsg.Payload.MsgSendErrorCounter, 1); + + /* with some undefined/unknown event at the transaction level, not an error */ + Txn.TransactionEventId = 0xFFFF; + UtAssert_VOIDCALL(CFE_SB_MessageTxn_ReportEvents(&Txn)); + UtAssert_UINT32_EQ(CFE_SB_Global.HKTlmMsg.Payload.MsgSendErrorCounter, 1); + + /* with an event at the pipe level, known to be an error */ + Txn.TransactionEventId = 0; + Txn.PipeSet[0].PendingEventId = CFE_SB_Q_FULL_ERR_EID; + UtAssert_VOIDCALL(CFE_SB_MessageTxn_ReportEvents(&Txn)); + UtAssert_UINT32_EQ(CFE_SB_Global.HKTlmMsg.Payload.MsgSendErrorCounter, 2); + + /* with some undefined/unknown event at the pipe level, not an error */ + Txn.PipeSet[0].PendingEventId = 0xFFFF; + UtAssert_VOIDCALL(CFE_SB_MessageTxn_ReportEvents(&Txn)); + UtAssert_UINT32_EQ(CFE_SB_Global.HKTlmMsg.Payload.MsgSendErrorCounter, 2); +} + /* ** Function for calling SB send message API test functions */ @@ -2901,10 +3486,19 @@ void Test_TransmitMsg_API(void) SB_UT_ADD_SUBTEST(Test_TransmitBuffer_NoIncrement); SB_UT_ADD_SUBTEST(Test_TransmitMsg_ZeroCopyBufferValidate); SB_UT_ADD_SUBTEST(Test_TransmitMsg_DisabledDestination); - SB_UT_ADD_SUBTEST(Test_BroadcastBufferToRoute); - SB_UT_ADD_SUBTEST(Test_TransmitMsgValidate_MaxMsgSizePlusOne); - SB_UT_ADD_SUBTEST(Test_TransmitMsgValidate_NoSubscribers); - SB_UT_ADD_SUBTEST(Test_TransmitMsgValidate_InvalidMsgId); + + SB_UT_ADD_SUBTEST(Test_MessageTxn_SetEventAndStatus); + SB_UT_ADD_SUBTEST(Test_MessageTxn_SetupFromMsg); + SB_UT_ADD_SUBTEST(Test_MessageTxn_Timeout); + SB_UT_ADD_SUBTEST(Test_MessageTxn_GetEventDetails); + SB_UT_ADD_SUBTEST(Test_MessageTxn_ReportSingleEvent); + SB_UT_ADD_SUBTEST(Test_MessageTxn_ReportEvents); + + SB_UT_ADD_SUBTEST(Test_TransmitTxn_Init); + SB_UT_ADD_SUBTEST(Test_TransmitTxn_FindDestinations); + SB_UT_ADD_SUBTEST(Test_TransmitTxn_PipeHandler); + SB_UT_ADD_SUBTEST(Test_TransmitTxn_Execute); + SB_UT_ADD_SUBTEST(Test_AllocateMessageBuffer); SB_UT_ADD_SUBTEST(Test_ReleaseMessageBuffer); } @@ -3249,7 +3843,7 @@ void Test_TransmitMsg_GetPoolBufErr(void) */ void Test_AllocateMessageBuffer(void) { - uint16 MsgSize = 10; + size_t MsgSize = 10; uint32 MemUse; /* Attempt to allocate a message buffer greater than the max size */ @@ -3304,9 +3898,6 @@ void Test_TransmitMsg_ZeroCopyBufferValidate(void) * descriptor which is NOT from CFE_SB_AllocateMessageBuffer(). */ memset(&BadZeroCpyBuf, 0, sizeof(BadZeroCpyBuf)); - /* Null Buffer => BAD_ARGUMENT */ - UtAssert_INT32_EQ(CFE_SB_ZeroCopyBufferValidate(NULL, &BufDscPtr), CFE_SB_BAD_ARGUMENT); - /* Non-null buffer pointer but Non Zero-Copy => CFE_SB_BUFFER_INVALID */ UtAssert_INT32_EQ(CFE_SB_ZeroCopyBufferValidate(&BadZeroCpyBuf.Content, &BufDscPtr), CFE_SB_BUFFER_INVALID); @@ -3441,7 +4032,7 @@ void Test_ReleaseMessageBuffer(void) CFE_SB_Buffer_t *ZeroCpyMsgPtr2 = NULL; CFE_SB_Buffer_t *ZeroCpyMsgPtr3 = NULL; CFE_SB_BufferD_t BadBufferDesc; - uint16 MsgSize = 10; + size_t MsgSize = 10; ZeroCpyMsgPtr1 = CFE_SB_AllocateMessageBuffer(MsgSize); ZeroCpyMsgPtr2 = CFE_SB_AllocateMessageBuffer(MsgSize); @@ -3505,113 +4096,12 @@ void Test_TransmitMsg_DisabledDestination(void) CFE_UtAssert_TEARDOWN(CFE_SB_DeletePipe(PipeId)); } -/* -** Test successful CFE_SB_BroadcastBufferToRoute -*/ -void Test_BroadcastBufferToRoute(void) -{ - CFE_SB_PipeId_t PipeId = CFE_SB_INVALID_PIPE; - CFE_SB_MsgId_t MsgId = SB_UT_TLM_MID; - CFE_SB_BufferD_t SBBufD; - int32 PipeDepth; - CFE_SBR_RouteId_t RouteId; - - memset(&SBBufD, 0, sizeof(SBBufD)); - SBBufD.MsgId = MsgId; - CFE_SB_TrackingListReset(&SBBufD.Link); - - PipeDepth = 2; - CFE_UtAssert_SETUP(CFE_SB_CreatePipe(&PipeId, PipeDepth, "TestPipe")); - CFE_UtAssert_SETUP(CFE_SB_Subscribe(MsgId, PipeId)); - - RouteId = CFE_SBR_GetRouteId(MsgId); - - /* No return from this function - it handles all errors */ - CFE_SB_BroadcastBufferToRoute(&SBBufD, RouteId); - - CFE_UtAssert_EVENTCOUNT(2); - UT_ClearEventHistory(); - - /* Calling this with invalid route ID is essentially a no-op, called for coverage */ - CFE_SB_BroadcastBufferToRoute(&SBBufD, CFE_SBR_INVALID_ROUTE_ID); - - CFE_UtAssert_TEARDOWN(CFE_SB_DeletePipe(PipeId)); -} - -/* -** Test response to sending a message with the message size larger than allowed -*/ -void Test_TransmitMsgValidate_MaxMsgSizePlusOne(void) +void UT_CFE_MSG_Verify_CustomHandler(void *UserObj, UT_EntryKey_t FuncKey, const UT_StubContext_t *Context) { - CFE_SB_MsgId_t MsgId = SB_UT_TLM_MID; - CFE_SB_MsgId_t MsgIdRtn; - SB_UT_Test_Tlm_t TlmPkt; - CFE_MSG_Size_t Size = CFE_MISSION_SB_MAX_SB_MSG_SIZE + 1; - CFE_MSG_Size_t SizeRtn = 0; - CFE_SBR_RouteId_t RouteIdRtn; - - memset(&TlmPkt, 0, sizeof(TlmPkt)); - - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); - - UtAssert_INT32_EQ(CFE_SB_TransmitMsgValidate(CFE_MSG_PTR(TlmPkt.TelemetryHeader), &MsgIdRtn, &SizeRtn, &RouteIdRtn), - CFE_SB_MSG_TOO_BIG); - CFE_UtAssert_MSGID_EQ(MsgIdRtn, MsgId); - UtAssert_INT32_EQ(SizeRtn, Size); + bool *IsAcceptable = UT_Hook_GetArgValueByName(Context, "IsAcceptable", bool *); - CFE_UtAssert_EVENTCOUNT(1); - - CFE_UtAssert_EVENTSENT(CFE_SB_MSG_TOO_BIG_EID); -} - -/* -** Test response to sending a message which has no subscribers -*/ -void Test_TransmitMsgValidate_NoSubscribers(void) -{ - CFE_SB_MsgId_t MsgId = SB_UT_TLM_MID; - CFE_SB_MsgId_t MsgIdRtn; - SB_UT_Test_Tlm_t TlmPkt; - CFE_MSG_Size_t Size = sizeof(TlmPkt); - CFE_MSG_Size_t SizeRtn = 0; - CFE_SBR_RouteId_t RouteIdRtn = CFE_SBR_INVALID_ROUTE_ID; - - memset(&TlmPkt, 0, sizeof(TlmPkt)); - - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); - - CFE_UtAssert_SUCCESS( - CFE_SB_TransmitMsgValidate(CFE_MSG_PTR(TlmPkt.TelemetryHeader), &MsgIdRtn, &SizeRtn, &RouteIdRtn)); - CFE_UtAssert_MSGID_EQ(MsgIdRtn, MsgId); - UtAssert_INT32_EQ(SizeRtn, Size); - UtAssert_BOOL_FALSE(CFE_SBR_IsValidRouteId(RouteIdRtn)); - - CFE_UtAssert_EVENTCOUNT(1); - - CFE_UtAssert_EVENTSENT(CFE_SB_SEND_NO_SUBS_EID); -} - -/* -** Test response to sending a message which has an invalid Msg ID -*/ -void Test_TransmitMsgValidate_InvalidMsgId(void) -{ - CFE_SB_MsgId_t MsgId = CFE_SB_INVALID_MSG_ID; - CFE_SB_MsgId_t MsgIdRtn; - SB_UT_Test_Tlm_t TlmPkt; - CFE_MSG_Size_t SizeRtn; - CFE_SBR_RouteId_t RouteIdRtn; - - memset(&TlmPkt, 0, sizeof(TlmPkt)); - - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); - - UtAssert_INT32_EQ(CFE_SB_TransmitMsgValidate(CFE_MSG_PTR(TlmPkt.TelemetryHeader), &MsgIdRtn, &SizeRtn, &RouteIdRtn), - CFE_SB_BAD_ARGUMENT); - CFE_UtAssert_EVENTCOUNT(1); - CFE_UtAssert_EVENTSENT(CFE_SB_SEND_INV_MSGID_EID); + /* Return alternating false/true (this is needed to avoid an endless loop) */ + *IsAcceptable = (UT_GetStubCount(FuncKey) & 1) == 0; } /* @@ -3630,17 +4120,18 @@ void Test_ReceiveBuffer_API(void) static void SB_UT_PipeIdModifyHandler(void *UserObj, UT_EntryKey_t FuncKey, const UT_StubContext_t *Context) { - void * data = UT_Hook_GetArgValueByName(Context, "data", void *); + CFE_SB_BufferD_t ** OutData = UT_Hook_GetArgValueByName(Context, "data", void *); size_t * size_copied = UT_Hook_GetArgValueByName(Context, "size_copied", size_t *); int32 status; - static SB_UT_Test_Tlm_t FakeTlmPkt; - SB_UT_Test_Tlm_t ** OutData; + static CFE_SB_BufferD_t LocalBuf; CFE_SB_PipeD_t * PipeDscPtr = UserObj; - OutData = data; - *OutData = &FakeTlmPkt; - *size_copied = sizeof(*OutData); - status = OS_SUCCESS; + memset(&LocalBuf, 0, sizeof(LocalBuf)); + CFE_SB_TrackingListReset(&LocalBuf.Link); + LocalBuf.UseCount = 1; + *OutData = &LocalBuf; + *size_copied = sizeof(*OutData); + status = OS_SUCCESS; UT_Stub_SetReturnValue(FuncKey, status); /* Modify the PipeID so it fails to match */ @@ -3700,8 +4191,8 @@ void Test_ReceiveBuffer_InvalidPipeId(void) UT_SetHandlerFunction(UT_KEY(OS_QueueGet), SB_UT_PipeIdModifyHandler, PipeDscPtr); UtAssert_INT32_EQ(CFE_SB_ReceiveBuffer(&SBBufPtr, PipeId, CFE_SB_POLL), CFE_SB_PIPE_RD_ERR); CFE_UtAssert_EVENTSENT(CFE_SB_BAD_PIPEID_EID); - UtAssert_UINT8_EQ(CFE_SB_Global.HKTlmMsg.Payload.MsgReceiveErrorCounter, 2); - UtAssert_UINT8_EQ(CFE_SB_Global.HKTlmMsg.Payload.InternalErrorCounter, 0); + UtAssert_UINT8_EQ(CFE_SB_Global.HKTlmMsg.Payload.MsgReceiveErrorCounter, 1); + UtAssert_UINT8_EQ(CFE_SB_Global.HKTlmMsg.Payload.InternalErrorCounter, 1); UT_SetHandlerFunction(UT_KEY(OS_QueueGet), NULL, NULL); /* restore the PipeID so it can be deleted */ @@ -3793,7 +4284,7 @@ void Test_ReceiveBuffer_PipeReadError(void) UT_SetDeferredRetcode(UT_KEY(OS_QueueGet), 1, OS_ERROR); UtAssert_INT32_EQ(CFE_SB_ReceiveBuffer(&SBBufPtr, PipeId, CFE_SB_PEND_FOREVER), CFE_SB_PIPE_RD_ERR); - CFE_UtAssert_EVENTCOUNT(2); + CFE_UtAssert_EVENTCOUNT(3); CFE_UtAssert_EVENTSENT(CFE_SB_Q_RD_ERR_EID); @@ -4228,11 +4719,6 @@ void Test_SB_SpecialCases(void) SB_UT_ADD_SUBTEST(Test_PutDestBlk_ErrLogic); SB_UT_ADD_SUBTEST(Test_CFE_SB_Buffers); SB_UT_ADD_SUBTEST(Test_CFE_SB_BadPipeInfo); - SB_UT_ADD_SUBTEST(Test_SB_TransmitMsgPaths_Nominal); - SB_UT_ADD_SUBTEST(Test_SB_TransmitMsgPaths_LimitErr); - SB_UT_ADD_SUBTEST(Test_SB_TransmitMsgPaths_FullErr); - SB_UT_ADD_SUBTEST(Test_SB_TransmitMsgPaths_WriteErr); - SB_UT_ADD_SUBTEST(Test_SB_TransmitMsgPaths_IgnoreOpt); SB_UT_ADD_SUBTEST(Test_ReceiveBuffer_UnsubResubPath); SB_UT_ADD_SUBTEST(Test_MessageString); } @@ -4402,281 +4888,6 @@ void Test_CFE_SB_BadPipeInfo(void) CFE_UtAssert_TEARDOWN(CFE_SB_DeletePipe(PipeId)); } -/* -** Test send housekeeping information command -*/ -void Test_SB_TransmitMsgPaths_Nominal(void) -{ - union - { - CFE_SB_Buffer_t SBBuf; - CFE_SB_SendHkCmd_t SendHkCmd; - } Housekeeping; - CFE_SB_MsgId_t MsgId; - CFE_SB_PipeId_t PipeId = CFE_SB_INVALID_PIPE; - SB_UT_Test_Tlm_t TlmPkt; - int32 PipeDepth = 2; - CFE_MSG_Size_t Size; - CFE_MSG_Type_t Type; - - memset(&Housekeeping, 0, sizeof(Housekeeping)); - memset(&TlmPkt, 0, sizeof(TlmPkt)); - - /* Set up for dispatch FIRST */ - UT_SetupBasicMsgDispatch(&UT_TPID_CFE_SB_SEND_HK, sizeof(Housekeeping.SendHkCmd), false); - - /* For internal send message call */ - MsgId = CFE_SB_ValueToMsgId(CFE_SB_HK_TLM_MID); - Size = sizeof(CFE_SB_Global.HKTlmMsg); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); - - /* Repress sending the no subscriptions event and process request */ - CFE_SB_Global.HKTlmMsg.Payload.NoSubscribersCounter = 0; - CFE_SB_Global.StopRecurseFlags[1] |= CFE_BIT(CFE_SB_SEND_NO_SUBS_EID_BIT); - CFE_SB_ProcessCmdPipePkt(&Housekeeping.SBBuf); - - /* The no subs event should not be in history but count should increment */ - CFE_UtAssert_EVENTNOTSENT(CFE_SB_SEND_NO_SUBS_EID); - UtAssert_INT32_EQ(CFE_SB_Global.HKTlmMsg.Payload.NoSubscribersCounter, 1); - - /* Repress get buffer error */ - CFE_SB_Global.HKTlmMsg.Payload.MsgSendErrorCounter = 0; - CFE_SB_Global.StopRecurseFlags[1] |= CFE_BIT(CFE_SB_GET_BUF_ERR_EID_BIT); - - /* Set up for dispatch FIRST */ - UT_SetupBasicMsgDispatch(&UT_TPID_CFE_SB_SEND_HK, sizeof(Housekeeping.SendHkCmd), false); - - /* For internal send message call */ - MsgId = CFE_SB_ValueToMsgId(CFE_SB_HK_TLM_MID); - Size = sizeof(CFE_SB_Global.HKTlmMsg); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); - - UT_SetDeferredRetcode(UT_KEY(CFE_ES_GetPoolBuf), 1, CFE_ES_ERR_MEM_BLOCK_SIZE); - CFE_SB_ProcessCmdPipePkt(&Housekeeping.SBBuf); - UtAssert_INT32_EQ(CFE_SB_Global.HKTlmMsg.Payload.MsgSendErrorCounter, 0); - - CFE_UtAssert_EVENTNOTSENT(CFE_SB_GET_BUF_ERR_EID); - - CFE_UtAssert_EVENTCOUNT(0); - - CFE_SB_Global.StopRecurseFlags[1] = 0; - - /* Create a message ID with the command bit set and disable reporting */ - MsgId = SB_UT_CMD_MID; - Size = sizeof(TlmPkt); - Type = CFE_MSG_Type_Cmd; - CFE_UtAssert_SETUP(CFE_SB_CreatePipe(&PipeId, PipeDepth, "TestPipe")); - - /* Will fail because of deferred CFE_ES_GetPoolBuf failure return */ - UtAssert_INT32_EQ(CFE_SB_Subscribe(MsgId, PipeId), CFE_SB_BUF_ALOC_ERR); - - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetType), &Type, sizeof(Type), false); - - CFE_UtAssert_SUCCESS(CFE_SB_TransmitMsg(CFE_MSG_PTR(TlmPkt.TelemetryHeader), true)); - - CFE_UtAssert_EVENTCOUNT(3); - - /* - * Test Additional paths within CFE_SB_TransmitMsgValidate that skip sending events to avoid a loop - * For all of these they should skip sending the event but still increment the MsgSendErrorCounter - */ - - /* CFE_SB_MSG_TOO_BIG_EID loop filter */ - CFE_SB_Global.HKTlmMsg.Payload.MsgSendErrorCounter = 0; - Size = CFE_MISSION_SB_MAX_SB_MSG_SIZE + 1; - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); - CFE_SB_Global.StopRecurseFlags[1] |= CFE_BIT(CFE_SB_MSG_TOO_BIG_EID_BIT); - CFE_SB_TransmitMsg(CFE_MSG_PTR(Housekeeping.SBBuf), true); - CFE_UtAssert_EVENTNOTSENT(CFE_SB_MSG_TOO_BIG_EID); - UtAssert_UINT32_EQ(CFE_SB_Global.HKTlmMsg.Payload.MsgSendErrorCounter, 1); - - /* CFE_SB_SEND_INV_MSGID_EID loop filter */ - CFE_SB_Global.HKTlmMsg.Payload.MsgSendErrorCounter = 0; - MsgId = CFE_SB_INVALID_MSG_ID; - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); - CFE_SB_Global.StopRecurseFlags[1] |= CFE_BIT(CFE_SB_SEND_INV_MSGID_EID_BIT); - CFE_SB_TransmitMsg(CFE_MSG_PTR(Housekeeping.SBBuf), true); - CFE_UtAssert_EVENTNOTSENT(CFE_SB_SEND_INV_MSGID_EID); - UtAssert_UINT32_EQ(CFE_SB_Global.HKTlmMsg.Payload.MsgSendErrorCounter, 1); - - /* CFE_SB_SEND_BAD_ARG_EID loop filter */ - CFE_SB_Global.HKTlmMsg.Payload.MsgSendErrorCounter = 0; - CFE_SB_Global.StopRecurseFlags[1] |= CFE_BIT(CFE_SB_SEND_BAD_ARG_EID_BIT); - CFE_SB_TransmitMsg(NULL, true); - CFE_UtAssert_EVENTNOTSENT(CFE_SB_SEND_BAD_ARG_EID); - UtAssert_UINT32_EQ(CFE_SB_Global.HKTlmMsg.Payload.MsgSendErrorCounter, 1); - - CFE_UtAssert_TEARDOWN(CFE_SB_DeletePipe(PipeId)); -} - -void Test_SB_TransmitMsgPaths_LimitErr(void) -{ - CFE_SB_MsgId_t MsgId; - CFE_SB_PipeId_t PipeId = CFE_SB_INVALID_PIPE; - SB_UT_Test_Tlm_t TlmPkt; - int32 PipeDepth = 2; - CFE_MSG_Type_t Type = CFE_MSG_Type_Tlm; - CFE_MSG_Size_t Size = sizeof(TlmPkt); - - memset(&TlmPkt, 0, sizeof(TlmPkt)); - - /* Test inhibiting sending a "message ID limit error" message */ - MsgId = SB_UT_TLM_MID; - CFE_UtAssert_SETUP(CFE_SB_CreatePipe(&PipeId, PipeDepth, "MsgLimTestPipe")); - - /* Set maximum allowed messages on the pipe at one time to 1 */ - CFE_UtAssert_SETUP(CFE_SB_SubscribeEx(MsgId, PipeId, CFE_SB_DEFAULT_QOS, 1)); - - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetType), &Type, sizeof(Type), false); - - /* First send should pass */ - CFE_UtAssert_SUCCESS(CFE_SB_TransmitMsg(CFE_MSG_PTR(TlmPkt.TelemetryHeader), true)); - - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetType), &Type, sizeof(Type), false); - - CFE_SB_Global.StopRecurseFlags[1] |= CFE_BIT(CFE_SB_MSGID_LIM_ERR_EID_BIT); - CFE_UtAssert_SUCCESS(CFE_SB_TransmitMsg(CFE_MSG_PTR(TlmPkt.TelemetryHeader), true)); - CFE_SB_Global.StopRecurseFlags[1] = 0; - - CFE_UtAssert_EVENTNOTSENT(CFE_SB_MSGID_LIM_ERR_EID); - - CFE_UtAssert_TEARDOWN(CFE_SB_DeletePipe(PipeId)); -} - -void Test_SB_TransmitMsgPaths_FullErr(void) -{ - CFE_SB_MsgId_t MsgId; - CFE_SB_PipeId_t PipeId = CFE_SB_INVALID_PIPE; - SB_UT_Test_Tlm_t TlmPkt; - int32 PipeDepth = 2; - CFE_MSG_Type_t Type = CFE_MSG_Type_Tlm; - CFE_MSG_Size_t Size = sizeof(TlmPkt); - - memset(&TlmPkt, 0, sizeof(TlmPkt)); - - /* Test inhibiting sending a "pipe full" message */ - MsgId = SB_UT_TLM_MID; - CFE_UtAssert_SETUP(CFE_SB_CreatePipe(&PipeId, PipeDepth, "PipeFullTestPipe")); - CFE_UtAssert_SETUP(CFE_SB_Subscribe(MsgId, PipeId)); - - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetType), &Type, sizeof(Type), false); - - /* This send should pass */ - CFE_UtAssert_SUCCESS(CFE_SB_TransmitMsg(CFE_MSG_PTR(TlmPkt.TelemetryHeader), true)); - - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetType), &Type, sizeof(Type), false); - - /* Tell the QueuePut stub to return OS_QUEUE_FULL on its next call */ - UT_SetDeferredRetcode(UT_KEY(OS_QueuePut), 1, OS_QUEUE_FULL); - CFE_SB_Global.StopRecurseFlags[1] |= CFE_BIT(CFE_SB_Q_FULL_ERR_EID_BIT); - CFE_UtAssert_SUCCESS(CFE_SB_TransmitMsg(CFE_MSG_PTR(TlmPkt.TelemetryHeader), true)); - CFE_SB_Global.StopRecurseFlags[1] = 0; - - CFE_UtAssert_EVENTNOTSENT(CFE_SB_Q_FULL_ERR_EID_BIT); - - CFE_UtAssert_EVENTCOUNT(2); - - CFE_UtAssert_TEARDOWN(CFE_SB_DeletePipe(PipeId)); -} - -void Test_SB_TransmitMsgPaths_WriteErr(void) -{ - CFE_SB_MsgId_t MsgId; - CFE_SB_PipeId_t PipeId = CFE_SB_INVALID_PIPE; - SB_UT_Test_Tlm_t TlmPkt; - int32 PipeDepth = 2; - CFE_MSG_Type_t Type = CFE_MSG_Type_Tlm; - CFE_MSG_Size_t Size = sizeof(TlmPkt); - - memset(&TlmPkt, 0, sizeof(TlmPkt)); - - /* Test inhibiting sending a "pipe write error" message */ - MsgId = SB_UT_TLM_MID; - CFE_UtAssert_SETUP(CFE_SB_CreatePipe(&PipeId, PipeDepth, "TestPipe")); - CFE_UtAssert_SETUP(CFE_SB_Subscribe(MsgId, PipeId)); - UT_SetDeferredRetcode(UT_KEY(OS_QueuePut), 1, OS_ERROR); - - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetType), &Type, sizeof(Type), false); - - CFE_SB_Global.StopRecurseFlags[1] |= CFE_BIT(CFE_SB_Q_WR_ERR_EID_BIT); - CFE_UtAssert_SUCCESS(CFE_SB_TransmitMsg(CFE_MSG_PTR(TlmPkt.TelemetryHeader), true)); - CFE_SB_Global.StopRecurseFlags[1] = 0; - - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetType), &Type, sizeof(Type), false); - - CFE_UtAssert_SUCCESS(CFE_SB_TransmitMsg(CFE_MSG_PTR(TlmPkt.TelemetryHeader), true)); - - CFE_UtAssert_EVENTCOUNT(2); - - CFE_UtAssert_EVENTNOTSENT(CFE_SB_Q_WR_ERR_EID); - - CFE_UtAssert_TEARDOWN(CFE_SB_DeletePipe(PipeId)); -} - -void Test_SB_TransmitMsgPaths_IgnoreOpt(void) -{ - CFE_SB_MsgId_t MsgId; - CFE_SB_PipeId_t PipeId = CFE_SB_INVALID_PIPE; - SB_UT_Test_Tlm_t TlmPkt; - int32 PipeDepth = 2; - CFE_MSG_Type_t Type = CFE_MSG_Type_Tlm; - CFE_MSG_Size_t Size = sizeof(TlmPkt); - CFE_SB_PipeD_t * PipeDscPtr; - CFE_ES_AppId_t AppId; - - memset(&TlmPkt, 0, sizeof(TlmPkt)); - - /* Setup Test skipping sending to a pipe when the pipe option is set to ignore */ - MsgId = SB_UT_TLM_MID; - CFE_UtAssert_SETUP(CFE_SB_CreatePipe(&PipeId, PipeDepth, "SkipPipe")); - CFE_UtAssert_SETUP(CFE_SB_Subscribe(MsgId, PipeId)); - CFE_UtAssert_SETUP(CFE_SB_SetPipeOpts(PipeId, CFE_SB_PIPEOPTS_IGNOREMINE)); - - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetType), &Type, sizeof(Type), false); - - /* Test skipping this pipe and the send should pass */ - CFE_UtAssert_SUCCESS(CFE_SB_TransmitMsg(CFE_MSG_PTR(TlmPkt.TelemetryHeader), true)); - UtAssert_STUB_COUNT(OS_QueuePut, 0); - - /* Set up and send again without matching ApId and it should transmit */ - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); - UT_SetDataBuffer(UT_KEY(CFE_MSG_GetType), &Type, sizeof(Type), false); - PipeDscPtr = CFE_SB_LocatePipeDescByID(PipeId); - AppId = PipeDscPtr->AppId; - PipeDscPtr->AppId = CFE_ES_APPID_UNDEFINED; - - /* Also hit case where not the peak depth */ - PipeDscPtr->PeakQueueDepth += 2; - CFE_UtAssert_SUCCESS(CFE_SB_TransmitMsg(CFE_MSG_PTR(TlmPkt.TelemetryHeader), true)); - UtAssert_STUB_COUNT(OS_QueuePut, 1); - - /* Set AppId back so it can be deleted */ - PipeDscPtr->AppId = AppId; - - CFE_UtAssert_TEARDOWN(CFE_SB_SetPipeOpts(PipeId, 0)); - CFE_UtAssert_TEARDOWN(CFE_SB_DeletePipe(PipeId)); -} - /* ** Test receiving a message response to an unsubscribing to message, then ** resubscribing to it while it's in the pipe diff --git a/modules/sb/ut-coverage/sb_UT.h b/modules/sb/ut-coverage/sb_UT.h index 2fbbc9adc..bb5d30a60 100644 --- a/modules/sb/ut-coverage/sb_UT.h +++ b/modules/sb/ut-coverage/sb_UT.h @@ -2047,7 +2047,7 @@ void Test_TransmitMsg_DisabledDestination(void); /*****************************************************************************/ /** -** \brief Test CFE_SB_BroadcastBufferToRoute +** \brief Test CFE_SB_TransmitTxn_BroadcastToRoute ** ** \par Description ** This function tests broadcasting a message buffer with the metadata. @@ -2058,23 +2058,7 @@ void Test_TransmitMsg_DisabledDestination(void); ** \returns ** This function does not return a value. ******************************************************************************/ -void Test_BroadcastBufferToRoute(void); - -/*****************************************************************************/ -/** -** \brief Test response to sending a message which has no subscribers -** -** \par Description -** This function tests the response to sending a message which has no -** subscribers. -** -** \par Assumptions, External Events, and Notes: -** None -** -** \returns -** This function does not return a value. -******************************************************************************/ -void Test_TransmitMsgValidate_NoSubscribers(void); +void Test_TransmitTxn_PipeHandler(void); /*****************************************************************************/ /** @@ -2090,7 +2074,7 @@ void Test_TransmitMsgValidate_NoSubscribers(void); ** \returns ** This function does not return a value. ******************************************************************************/ -void Test_TransmitMsgValidate_InvalidMsgId(void); +void Test_TransmitTxn_SetupFromMsg_InvalidMsgId(void); /*****************************************************************************/ /** @@ -2107,7 +2091,7 @@ void Test_TransmitMsgValidate_InvalidMsgId(void); ** \returns ** This function does not return a value. ******************************************************************************/ -void Test_TransmitMsgValidate_MaxMsgSizePlusOne(void); +void Test_TransmitTxn_SetupFromMsg_MaxMsgSizePlusOne(void); /*****************************************************************************/ /** @@ -2457,25 +2441,6 @@ void Test_CFE_SB_Buffers(void); ******************************************************************************/ void Test_CFE_SB_BadPipeInfo(void); -/*****************************************************************************/ -/** -** \brief Test TransmitMsgFull function paths -** -** \par Description -** This function tests branch paths in the TransmitMsgFull function. -** -** \par Assumptions, External Events, and Notes: -** None -** -** \returns -** This function does not return a value. -******************************************************************************/ -void Test_SB_TransmitMsgPaths_Nominal(void); -void Test_SB_TransmitMsgPaths_LimitErr(void); -void Test_SB_TransmitMsgPaths_FullErr(void); -void Test_SB_TransmitMsgPaths_WriteErr(void); -void Test_SB_TransmitMsgPaths_IgnoreOpt(void); - /*****************************************************************************/ /** ** \brief Test ReceiveBuffer function unsubscribe/resubscribe path diff --git a/modules/tbl/config/default_cfe_tbl_interface_cfg.h b/modules/tbl/config/default_cfe_tbl_interface_cfg.h index 214e65418..5dddf48db 100644 --- a/modules/tbl/config/default_cfe_tbl_interface_cfg.h +++ b/modules/tbl/config/default_cfe_tbl_interface_cfg.h @@ -25,7 +25,7 @@ * interface, tables definitions, and any other data products that * serve to exchange information with other entities. * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ diff --git a/modules/tbl/config/default_cfe_tbl_internal_cfg.h b/modules/tbl/config/default_cfe_tbl_internal_cfg.h index 412553139..bd5790bd7 100644 --- a/modules/tbl/config/default_cfe_tbl_internal_cfg.h +++ b/modules/tbl/config/default_cfe_tbl_internal_cfg.h @@ -25,7 +25,7 @@ * to items in this file only affect the local module and will be transparent * to external entities that are using the public interface(s). * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ @@ -125,7 +125,7 @@ ** This number must be less than 32767. It should be recognized that this parameter ** determines the size of the Critical Table Registry which is maintained in the Critical ** Data Store. An excessively high number will waste Critical Data Store memory. Therefore, -** this number must not exceed the value defined in CFE_ES_CDS_MAX_CRITICAL_TABLES. +** this number must not exceed the value defined in CFE_PLATFORM_ES_CDS_MAX_NUM_ENTRIES. */ #define CFE_PLATFORM_TBL_MAX_CRITICAL_TABLES 32 diff --git a/modules/tbl/config/default_cfe_tbl_mission_cfg.h b/modules/tbl/config/default_cfe_tbl_mission_cfg.h index 9e3c57d21..ec0278ea9 100644 --- a/modules/tbl/config/default_cfe_tbl_mission_cfg.h +++ b/modules/tbl/config/default_cfe_tbl_mission_cfg.h @@ -24,7 +24,7 @@ * This is a compatibility header for the "mission_cfg.h" file that has * traditionally provided public config definitions for each CFS app. * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ diff --git a/modules/tbl/config/default_cfe_tbl_msg.h b/modules/tbl/config/default_cfe_tbl_msg.h index adaf442e0..b498c50a9 100644 --- a/modules/tbl/config/default_cfe_tbl_msg.h +++ b/modules/tbl/config/default_cfe_tbl_msg.h @@ -24,7 +24,7 @@ * This is a compatibility header for the "cfe_tbl_msg.h" file that has * traditionally provided the message definitions for cFS apps. * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ diff --git a/modules/tbl/config/default_cfe_tbl_platform_cfg.h b/modules/tbl/config/default_cfe_tbl_platform_cfg.h index 5bcff58d7..f8770cd1e 100644 --- a/modules/tbl/config/default_cfe_tbl_platform_cfg.h +++ b/modules/tbl/config/default_cfe_tbl_platform_cfg.h @@ -28,7 +28,7 @@ * These definitions are now provided in two separate files, one for * the public/mission scope and one for internal scope. * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ diff --git a/modules/tbl/fsw/src/cfe_tbl_api.c b/modules/tbl/fsw/src/cfe_tbl_api.c index 36e08f068..92dc8933c 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) { - /* Identify whether the Inactive Buffer is a shared buffer or a dedicated one */ - if (RegRecPtr->DoubleBuffered) + LogTagStr = "inactive"; + BuffPtr = CFE_TBL_GetInactiveBuffer(RegRecPtr); + } + else + { + 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) + if (ResultPtr != NULL) + { + if (BuffPtr == NULL) { - 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); + /* No buffer, it cannot be valid */ + ResultPtr->Result = -1; } - else + else if (RegRecPtr->ValidationFuncPtr == 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); - } - } - - /* 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) - { - /* 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; @@ -1134,7 +1096,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_ES_AppId_t ThisAppId; + CFE_TBL_LoadBuff_t * ActiveBufPtr; Status = CFE_TBL_TxnStartFromHandle(&Txn, TblHandle, CFE_TBL_TxnContext_ACCESSOR_APP); @@ -1142,36 +1104,34 @@ CFE_Status_t CFE_TBL_DumpToBuffer(CFE_TBL_Handle_t TblHandle) { Status = CFE_TBL_TxnGetTableStatus(&Txn); - RegRecPtr = CFE_TBL_TxnRegRec(&Txn); - - CFE_TBL_TxnFinish(&Txn); - } - else - { - ThisAppId = CFE_TBL_TxnAppId(&Txn); - - CFE_ES_WriteToSysLog("%s: App(%lu) does not have access to Tbl Handle=%d\n", __func__, - CFE_RESOURCEID_TO_ULONG(ThisAppId), (int)TblHandle); - } + /* Make sure the table has been requested to be dumped */ + if (Status == CFE_TBL_INFO_DUMP_PENDING) + { + RegRecPtr = CFE_TBL_TxnRegRec(&Txn); + DumpCtrlPtr = CFE_TBL_LocateDumpCtrlByID(RegRecPtr->DumpControlId); + ActiveBufPtr = CFE_TBL_GetActiveBuffer(RegRecPtr); - /* Make sure the table has been requested to be dumped */ - if (Status == CFE_TBL_INFO_DUMP_PENDING) - { - DumpCtrlPtr = &CFE_TBL_Global.DumpControlBlocks[RegRecPtr->DumpControlIndex]; + /* Copy the contents of the active buffer to the assigned dump buffer */ + memcpy(DumpCtrlPtr->DumpBufferPtr->BufferPtr, ActiveBufPtr->BufferPtr, DumpCtrlPtr->Size); - /* Copy the contents of the active buffer to the assigned dump buffer */ - memcpy(DumpCtrlPtr->DumpBufferPtr->BufferPtr, RegRecPtr->Buffers[0].BufferPtr, DumpCtrlPtr->Size); + /* Save the current time so that the header in the dump file can have the correct time */ + DumpCtrlPtr->DumpBufferPtr->FileTime = CFE_TIME_GetTime(); - /* Save the current time so that the header in the dump file can have the correct time */ - DumpCtrlPtr->DumpBufferPtr->FileTime = CFE_TIME_GetTime(); + /* Disassociate the dump request from the table */ + RegRecPtr->DumpControlId = CFE_TBL_NO_DUMP_PENDING; - /* Disassociate the dump request from the table */ - RegRecPtr->DumpControlIndex = CFE_TBL_NO_DUMP_PENDING; + /* Notify the Table Services Application that the dump buffer is ready to be written to a file */ + DumpCtrlPtr->State = CFE_TBL_DUMP_PERFORMED; - /* Notify the Table Services Application that the dump buffer is ready to be written to a file */ - DumpCtrlPtr->State = CFE_TBL_DUMP_PERFORMED; + Status = CFE_SUCCESS; + } - Status = CFE_SUCCESS; + CFE_TBL_TxnFinish(&Txn); + } + else + { + 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..3a407ee45 100644 --- a/modules/tbl/fsw/src/cfe_tbl_internal.c +++ b/modules/tbl/fsw/src/cfe_tbl_internal.c @@ -89,17 +89,9 @@ 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++) { - CFE_TBL_Global.DumpControlBlocks[i].State = CFE_TBL_DUMP_FREE; - /* Prevent Shared Buffers from being used until successfully allocated */ CFE_TBL_Global.LoadBuffs[i].Taken = true; } @@ -223,13 +215,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->DumpControlId = CFE_TBL_NO_DUMP_PENDING; CFE_TBL_HandleLinkInit(&RegRecPtr->AccessList); } @@ -322,6 +314,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 @@ -904,6 +1005,7 @@ void CFE_TBL_ByteSwapUint32(uint32 *Uint32ToSwapPtr) char *InPtr = (char *)&Temp; char *OutPtr = (char *)Uint32ToSwapPtr; + /* SAD: Safe access to InPtr[0-3] and OutPtr[0-3] as both manipulate bytes within 4-byte integers. */ OutPtr[0] = InPtr[3]; OutPtr[1] = InPtr[2]; OutPtr[2] = InPtr[1]; @@ -918,19 +1020,22 @@ void CFE_TBL_ByteSwapUint32(uint32 *Uint32ToSwapPtr) *-----------------------------------------------------------------*/ int32 CFE_TBL_CleanUpApp(CFE_ES_AppId_t AppId) { - uint32 i; - CFE_TBL_TxnState_t Txn; + uint32 i; + CFE_TBL_TxnState_t Txn; + CFE_TBL_DumpControl_t *DumpCtrlPtr; /* Scan Dump Requests to determine if any of the tables that */ /* were to be dumped will be deleted */ for (i = 0; i < CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS; i++) { + DumpCtrlPtr = &CFE_TBL_Global.DumpControlBlocks[i]; + /* Check to see if the table to be dumped is owned by the App to be deleted */ - if ((CFE_TBL_Global.DumpControlBlocks[i].State != CFE_TBL_DUMP_FREE) && - CFE_RESOURCEID_TEST_EQUAL(CFE_TBL_Global.DumpControlBlocks[i].RegRecPtr->OwnerAppId, AppId)) + if (CFE_TBL_DumpCtrlBlockIsUsed(DumpCtrlPtr) && + CFE_RESOURCEID_TEST_EQUAL(DumpCtrlPtr->RegRecPtr->OwnerAppId, AppId)) { /* If so, then remove the dump request */ - CFE_TBL_Global.DumpControlBlocks[i].State = CFE_TBL_DUMP_FREE; + CFE_TBL_DumpCtrlBlockSetFree(DumpCtrlPtr); } } @@ -1546,3 +1651,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..23c7654c0 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,104 @@ 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); +/*---------------------------------------------------------------------------------------*/ +/** +** \brief Gets the ID of the next buffer to use on a double-buffered table +** +** \par Description +** This returns the identifier for the local table buffer that should be +** loaded next. +** +** \par Assumptions, External Events, and Notes: +** This is not applicable to single-buffered tables. +** +** \param RegRecPtr The table registry record +** \returns Identifier of next buffer to use +*/ +int32 CFE_TBL_GetNextLocalBufferId(CFE_TBL_RegistryRec_t *RegRecPtr); + +/*---------------------------------------------------------------------------------------*/ +/** +** \brief Gets the currently-active buffer pointer for a table +** +** \par Description +** This returns a pointer to the currently active table buffer. On a single-buffered +** table, this is always the first/only buffer. This function never returns NULL, as +** all tables have at least one buffer. +** +** \par Assumptions, External Events, and Notes: +** None +** +** \param RegRecPtr The table registry record +** \returns Pointer to the active table buffer +*/ +CFE_TBL_LoadBuff_t *CFE_TBL_GetActiveBuffer(CFE_TBL_RegistryRec_t *RegRecPtr); + +/*---------------------------------------------------------------------------------------*/ +/** +** \brief Gets the inactive buffer pointer for a table +** +** \par Description +** This returns a pointer to inactive table buffer. On a double-buffered table +** this refers to whichever buffer is _not_ currently active (that is, the opposite +** buffer from what is returned by CFE_TBL_GetActiveBuffer()). +** +** On a single-buffered, if there is a load in progress that is utilizing one of the +** global/shared load buffers, then this returns a pointer to that buffer. If there +** is no load in progress, this returns NULL to indicate there is no inactive buffer. +** +** \par Assumptions, External Events, and Notes: +** This funtion may return NULL if there is no inactive buffer associated with the table +** +** \param RegRecPtr The table registry record +** \returns Pointer to the inactive table buffer +*/ +CFE_TBL_LoadBuff_t *CFE_TBL_GetInactiveBuffer(CFE_TBL_RegistryRec_t *RegRecPtr); + +/*---------------------------------------------------------------------------------------*/ +/** +** \brief Gets the buffer pointer for a table based on the selection enum +** +** \par Description +** Gets either the active buffer (see CFE_TBL_GetActiveBuffer()) or the inactive +** buffer (see CFE_TBL_GetInactiveBuffer()) based on the BufferSelect parameter. +** +** \par Assumptions, External Events, and Notes: +** This funtion may return NULL if there is no buffer associated with the table +** This will send an event if the BufferSelect parameter is not valid +** +** \param RegRecPtr The table registry record +** \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_BufferSelect_Enum_t BufferSelect); + +/*---------------------------------------------------------------------------------------*/ +/** +** \brief Checks if a validation request is pending and clears the request +** +** \par Description +** This checks the given flag (which is a request ID) to determine if a table validation +** request is pending. +** +** If no validation request is pending, this returns NULL and nothing else is done. +** +** If a validation request is pending, then this clears the request (by writing +** #CFE_TBL_VALRESULTID_UNDEFINED to the request flag) and returns a pointer to the +** corresponding Validation Result buffer that refers to that request. The request +** should be in the PENDING state. +** +** \par Assumptions, External Events, and Notes: +** This will clear the flag if there was a pending request, as it is expected that the +** caller will be performing the validation at this time. +** +** \param ValIdPtr Pointer to the table validation request flag (from the table registry entry) +** \returns Pointer to the request, if a request was pending +** \retval NULL if no request was pending +*/ +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..23275fa8e 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,30 @@ 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_DumpCtrlId_ToIndex(CFE_TBL_DumpCtrlId_t DumpCtrlId, uint32 *Idx) +{ + return CFE_ResourceId_ToIndex(CFE_RESOURCEID_UNWRAP(DumpCtrlId), CFE_TBL_DUMPCTRLID_BASE, + CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS, Idx); +} + +/*---------------------------------------------------------------- + * + * 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 +163,111 @@ 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_DumpControl_t *CFE_TBL_LocateDumpCtrlByID(CFE_TBL_DumpCtrlId_t BlockId) +{ + CFE_TBL_DumpControl_t *BlockPtr; + uint32 Idx; + + if (CFE_TBL_DumpCtrlId_ToIndex(BlockId, &Idx) == CFE_SUCCESS) + { + BlockPtr = &CFE_TBL_Global.DumpControlBlocks[Idx]; + } + else + { + BlockPtr = NULL; + } + + return BlockPtr; +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +bool CFE_TBL_CheckDumpCtrlSlotUsed(CFE_ResourceId_t CheckId) +{ + CFE_TBL_DumpControl_t *BlockPtr; + + /* + * 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. + */ + BlockPtr = CFE_TBL_LocateDumpCtrlByID(CFE_TBL_DUMPCTRLID_C(CheckId)); + return (BlockPtr == NULL || CFE_TBL_DumpCtrlBlockIsUsed(BlockPtr)); +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +CFE_ResourceId_t CFE_TBL_GetNextDumpCtrlBlock(void) +{ + return CFE_ResourceId_FindNext(CFE_TBL_Global.LastDumpCtrlBlockId, CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS, + CFE_TBL_CheckDumpCtrlSlotUsed); +} + +/*---------------------------------------------------------------- + * + * 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..7217b1684 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,386 @@ #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] ValResultId the ID of the validation result entry 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); + +/* + * --------------------------------------------------------------------------------------- + * + * ~~~ DUMP CONTROL BLOCK ACCESSORS ~~~ + * + * These operate on CFE_TBL_DumpControl_t* and CFE_TBL_DumpCtrlId_t types + * + * --------------------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Get the array index correlating with a Dump Control Block ID + * + * Calculates the array position/index of the global array entry for + * the given block ID. + * + * @param[in] DumpCtrlId the ID/handle of the control 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_DumpCtrlId_ToIndex(CFE_TBL_DumpCtrlId_t DumpCtrlId, uint32 *Idx); + +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Locate the registry 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_DumpCtrlBlockIsMatch() function can be used to check/confirm + * if the returned table entry is a positive match for the given ID. + * + * @sa CFE_TBL_DumpCtrlBlockIsMatch() + * + * @param[in] BlockId the block ID to locate + * @return pointer to dump control block for the given ID, or NULL if out of range + */ +CFE_TBL_DumpControl_t *CFE_TBL_LocateDumpCtrlByID(CFE_TBL_DumpCtrlId_t BlockId); + +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Check if a dump control block is a match for the given ID + * + * This routine confirms that the previously-located block pointer is valid + * and matches the expected block 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_LocateDumpCtrlByID() + * 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_LocateDumpCtrlByID + * + * @param[in] BlockPtr pointer to validation result table entry, or NULL + * @param[in] BlockId expected validation result ID + * @returns true if the entry matches the given ID + */ +static inline bool CFE_TBL_DumpCtrlBlockIsMatch(const CFE_TBL_DumpControl_t *BlockPtr, CFE_TBL_DumpCtrlId_t BlockId) +{ + return (BlockPtr != NULL && CFE_RESOURCEID_TEST_EQUAL(BlockPtr->BlockId, BlockId)); +} + +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Check if a dump control block is in use or free/empty + * + * This routine checks if the block 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] BlockPtr pointer to dump control block + * @returns true if the entry is in use/configured, or false if it is free/empty + */ +static inline bool CFE_TBL_DumpCtrlBlockIsUsed(const CFE_TBL_DumpControl_t *BlockPtr) +{ + return (CFE_RESOURCEID_TEST_DEFINED(BlockPtr->BlockId)); +} + +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Marks a dump control block as in use (not avaliable) + * + * This sets the internal field(s) within this entry, and marks + * it as being associated with the given block 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] BlockPtr pointer to dump control block + * @param[in] PendingId the ID of this entry that will be set + */ +static inline void CFE_TBL_DumpCtrlBlockSetUsed(CFE_TBL_DumpControl_t *BlockPtr, CFE_ResourceId_t PendingId) +{ + BlockPtr->BlockId = CFE_TBL_DUMPCTRLID_C(PendingId); +} + +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Marks a dump control block as available (not in use) + * + * This clears the internal field(s) within this entry, and marks + * it as not being associated with any block 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] BlockPtr pointer to dump control block + */ +static inline void CFE_TBL_DumpCtrlBlockSetFree(CFE_TBL_DumpControl_t *BlockPtr) +{ + BlockPtr->State = CFE_TBL_DUMP_FREE; + BlockPtr->BlockId = CFE_TBL_DUMPCTRLID_UNDEFINED; +} + +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Get the ID value from a dump control block + * + * This routine converts the block 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] BlockPtr pointer to block + * @returns ID of entry + */ +static inline CFE_TBL_DumpCtrlId_t CFE_TBL_DumpCtrlBlockGetId(const CFE_TBL_DumpControl_t *BlockPtr) +{ + return BlockPtr->BlockId; +} + +/* + * Internal functions to perform name based resource lookups + * + * These functions do not lock, they must only be used internally by ES when + * the lock is already held. + */ + +/** + * @brief Determine the next ID to use for a dump control block + * + * Obtains an ID value that is usable for a new dump control block. If no blocks + * are available, then UNDEFINED is returned. + * + * @returns ID to use for next control block, or UNDEFINED if no slots available + */ +CFE_ResourceId_t CFE_TBL_GetNextDumpCtrlBlock(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_CheckDumpCtrlSlotUsed(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 +536,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 +567,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..c510cd46b 100644 --- a/modules/tbl/fsw/src/cfe_tbl_task.h +++ b/modules/tbl/fsw/src/cfe_tbl_task.h @@ -64,19 +64,39 @@ /** \brief Value indicating when no Validation is Pending */ /** ** 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 +** #CFE_TBL_RegistryRec_t::ValidateActiveId or #CFE_TBL_RegistryRec_t::ValidateInactiveId */ -#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 */ /** ** This macro is used to indicate no Dump is Pending by assigning it to -** #CFE_TBL_RegistryRec_t::DumpControlIndex +** #CFE_TBL_RegistryRec_t::DumpControlId */ -#define CFE_TBL_NO_DUMP_PENDING (-1) +#define CFE_TBL_NO_DUMP_PENDING CFE_TBL_DUMPCTRLID_UNDEFINED /************************ 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 A type for Dump Control Block IDs + * + * This is the type that is used for any API accepting or returning a dump control block + */ +typedef CFE_RESOURCEID_BASE_TYPE CFE_TBL_DumpCtrlId_t; + +#define CFE_TBL_DUMPCTRLID_C(val) ((CFE_TBL_DumpCtrlId_t)CFE_RESOURCEID_WRAP(val)) +#define CFE_TBL_DUMPCTRLID_UNDEFINED CFE_TBL_DUMPCTRLID_C(CFE_RESOURCEID_UNDEFINED) + /*******************************************************************************/ /** \brief Identifies the current state of a validation sequence. */ @@ -105,6 +125,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 +211,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 */ + CFE_TBL_DumpCtrlId_t DumpControlId; /**< \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; @@ -231,6 +255,8 @@ typedef struct */ typedef struct { + CFE_TBL_DumpCtrlId_t BlockId; + CFE_TBL_DumpState_t State; /**< \brief Current state of this block of data */ size_t Size; /**< \brief Number of bytes to be dumped */ CFE_TBL_LoadBuff_t * DumpBufferPtr; /**< \brief Address where dumped data is to be stored temporarily */ @@ -349,6 +375,10 @@ typedef struct * Registry dump state info (background job) */ CFE_TBL_RegDumpStateInfo_t RegDumpState; + + CFE_ResourceId_t LastValidationResultId; + CFE_ResourceId_t LastDumpCtrlBlockId; + } 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..1033464d4 100644 --- a/modules/tbl/fsw/src/cfe_tbl_task_cmds.c +++ b/modules/tbl/fsw/src/cfe_tbl_task_cmds.c @@ -86,10 +86,11 @@ int32 CFE_TBL_SendHkCmd(const CFE_TBL_SendHkCmd_t *data) /* Check to see if there are any dump-only table dumps pending */ for (i = 0; i < CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS; i++) { - if (CFE_TBL_Global.DumpControlBlocks[i].State == CFE_TBL_DUMP_PERFORMED) + DumpCtrlPtr = &CFE_TBL_Global.DumpControlBlocks[i]; + + if (CFE_TBL_DumpCtrlBlockIsUsed(DumpCtrlPtr) && DumpCtrlPtr->State == CFE_TBL_DUMP_PERFORMED) { - DumpCtrlPtr = &CFE_TBL_Global.DumpControlBlocks[i]; - Status = CFE_TBL_DumpToFile(DumpCtrlPtr->DumpBufferPtr->DataSource, DumpCtrlPtr->TableName, + Status = CFE_TBL_DumpToFile(DumpCtrlPtr->DumpBufferPtr->DataSource, DumpCtrlPtr->TableName, DumpCtrlPtr->DumpBufferPtr->BufferPtr, DumpCtrlPtr->Size); /* If dump file was successfully written, update the file header so that the timestamp */ @@ -125,7 +126,7 @@ int32 CFE_TBL_SendHkCmd(const CFE_TBL_SendHkCmd_t *data) DumpCtrlPtr->RegRecPtr->LoadInProgress = CFE_TBL_NO_LOAD_IN_PROGRESS; /* Free the Dump Control Block for later use */ - DumpCtrlPtr->State = CFE_TBL_DUMP_FREE; + CFE_TBL_DumpCtrlBlockSetFree(DumpCtrlPtr); } } @@ -179,16 +180,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 +222,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; @@ -530,17 +537,20 @@ int32 CFE_TBL_LoadCmd(const CFE_TBL_LoadCmd_t *data) int32 CFE_TBL_DumpCmd(const CFE_TBL_DumpCmd_t *data) { CFE_TBL_CmdProcRet_t ReturnCode = CFE_TBL_INC_ERR_CTR; /* Assume failure */ - int16 RegIndex; + CFE_TBL_TxnState_t Txn; const CFE_TBL_DumpCmd_Payload_t *CmdPtr = &data->Payload; char DumpFilename[OS_MAX_PATH_LEN]; char TableName[CFE_TBL_MAX_FULL_NAME_LEN]; CFE_TBL_RegistryRec_t * RegRecPtr; - void * DumpDataAddr = NULL; CFE_TBL_LoadBuff_t * WorkingBufferPtr; - int32 DumpIndex; - int32 Status; + CFE_TBL_LoadBuff_t * SelectedBufferPtr; + CFE_ResourceId_t PendingDumpId; + CFE_Status_t Status; CFE_TBL_DumpControl_t * DumpCtrlPtr; + SelectedBufferPtr = NULL; + WorkingBufferPtr = NULL; + /* Make sure all strings are null terminated before attempting to process them */ CFE_SB_MessageStringGet(DumpFilename, (char *)CmdPtr->DumpFilename, NULL, sizeof(DumpFilename), sizeof(CmdPtr->DumpFilename)); @@ -548,76 +558,47 @@ int32 CFE_TBL_DumpCmd(const CFE_TBL_DumpCmd_t *data) 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); + Status = CFE_TBL_TxnStartFromName(&Txn, TableName, CFE_TBL_TxnContext_UNDEFINED); - if (RegIndex != CFE_TBL_NOT_FOUND) + if (Status == CFE_SUCCESS) { /* Obtain a pointer to registry information about specified table */ - RegRecPtr = &CFE_TBL_Global.Registry[RegIndex]; + RegRecPtr = CFE_TBL_TxnRegRec(&Txn); /* Determine what data is to be dumped */ - if (CmdPtr->ActiveTableFlag == CFE_TBL_BufferSelect_ACTIVE) - { - DumpDataAddr = RegRecPtr->Buffers[RegRecPtr->ActiveBufferIndex].BufferPtr; - } - else if (CmdPtr->ActiveTableFlag == CFE_TBL_BufferSelect_INACTIVE) /* Dumping Inactive Buffer */ - { - /* If this is a double buffered table, locating the inactive buffer is trivial */ - if (RegRecPtr->DoubleBuffered) - { - DumpDataAddr = RegRecPtr->Buffers[(1U - RegRecPtr->ActiveBufferIndex)].BufferPtr; - } - else - { - /* For single buffered tables, the index to the inactive buffer is kept in 'LoadInProgress' */ - /* Unless this is a table whose address was defined by the owning Application. */ - if ((RegRecPtr->LoadInProgress != CFE_TBL_NO_LOAD_IN_PROGRESS) && (!RegRecPtr->UserDefAddr)) - { - DumpDataAddr = 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); - } - } - } - else + SelectedBufferPtr = CFE_TBL_GetSelectedBuffer(RegRecPtr, CmdPtr->ActiveTableFlag); + + CFE_TBL_TxnFinish(&Txn); + + if (SelectedBufferPtr == NULL) { 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 dumped, then proceed with creating the file and dumping the data */ - if (DumpDataAddr != NULL) + else { + /* If we have located the data to be dumped, then proceed with creating the file and dumping the data */ /* If this is not a dump only table, then we can perform the dump immediately */ if (!RegRecPtr->DumpOnly) { - ReturnCode = CFE_TBL_DumpToFile(DumpFilename, TableName, DumpDataAddr, RegRecPtr->Size); + ReturnCode = CFE_TBL_DumpToFile(DumpFilename, TableName, SelectedBufferPtr->BufferPtr, RegRecPtr->Size); } else /* Dump Only tables need to synchronize their dumps with the owner's execution */ { /* Make sure a dump is not already in progress */ - if (RegRecPtr->DumpControlIndex == CFE_TBL_NO_DUMP_PENDING) + if (!CFE_RESOURCEID_TEST_DEFINED(RegRecPtr->DumpControlId)) { /* Find a free Dump Control Block */ - DumpIndex = 0; - while ((DumpIndex < CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS) && - (CFE_TBL_Global.DumpControlBlocks[DumpIndex].State != CFE_TBL_DUMP_FREE)) - { - DumpIndex++; - } - - if (DumpIndex < CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS) + PendingDumpId = CFE_TBL_GetNextDumpCtrlBlock(); + DumpCtrlPtr = CFE_TBL_LocateDumpCtrlByID(CFE_TBL_DUMPCTRLID_C(PendingDumpId)); + if (DumpCtrlPtr != NULL) { /* Allocate a shared memory buffer for storing the data to be dumped */ Status = CFE_TBL_GetWorkingBuffer(&WorkingBufferPtr, RegRecPtr, false); if (Status == CFE_SUCCESS) { - DumpCtrlPtr = &CFE_TBL_Global.DumpControlBlocks[DumpIndex]; DumpCtrlPtr->State = CFE_TBL_DUMP_PENDING; DumpCtrlPtr->RegRecPtr = RegRecPtr; @@ -628,7 +609,8 @@ int32 CFE_TBL_DumpCmd(const CFE_TBL_DumpCmd_t *data) DumpCtrlPtr->Size = RegRecPtr->Size; /* Notify the owning application that a dump is pending */ - RegRecPtr->DumpControlIndex = DumpIndex; + CFE_TBL_DumpCtrlBlockSetUsed(DumpCtrlPtr, PendingDumpId); + RegRecPtr->DumpControlId = CFE_TBL_DumpCtrlBlockGetId(DumpCtrlPtr); /* If application requested notification by message, then do so */ CFE_TBL_SendNotificationMsg(RegRecPtr); @@ -798,82 +780,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 +841,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 +864,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..63beb11a3 100644 --- a/modules/tbl/fsw/src/cfe_tbl_transaction.c +++ b/modules/tbl/fsw/src/cfe_tbl_transaction.c @@ -284,12 +284,12 @@ 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; } - else if (RegRecPtr->DumpControlIndex != CFE_TBL_NO_DUMP_PENDING) + else if (CFE_RESOURCEID_TEST_DEFINED(RegRecPtr->DumpControlId)) { Status = CFE_TBL_INFO_DUMP_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..64c08e044 100644 --- a/modules/tbl/ut-coverage/tbl_UT.c +++ b/modules/tbl/ut-coverage/tbl_UT.c @@ -113,6 +113,92 @@ 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)); +} + +void UT_TBL_SetupPendingDump(uint32 ArrayIndex, CFE_TBL_LoadBuff_t *DumpBufferPtr, CFE_TBL_RegistryRec_t *RegRecPtr, + CFE_TBL_DumpControl_t **DumpCtrlOut) +{ + CFE_TBL_DumpControl_t *DumpCtrlPtr; + CFE_ResourceId_t PendingId; + + DumpCtrlPtr = &CFE_TBL_Global.DumpControlBlocks[ArrayIndex]; + + PendingId = CFE_ResourceId_FromInteger(CFE_TBL_DUMPCTRLID_BASE + ArrayIndex); + + memset(DumpCtrlPtr, 0, sizeof(*DumpCtrlPtr)); + + DumpCtrlPtr->State = CFE_TBL_DUMP_PENDING; + DumpCtrlPtr->BlockId = CFE_TBL_DUMPCTRLID_C(PendingId); + DumpCtrlPtr->RegRecPtr = RegRecPtr; + DumpCtrlPtr->DumpBufferPtr = DumpBufferPtr; + DumpCtrlPtr->Size = 1; + + snprintf(DumpCtrlPtr->TableName, sizeof(DumpCtrlPtr->TableName), "ut_cfe_tbl.UT_Table%u", + (unsigned int)ArrayIndex + 1); + + if (RegRecPtr != NULL) + { + RegRecPtr->DumpControlId = DumpCtrlPtr->BlockId; + } + + if (DumpCtrlOut != NULL) + { + *DumpCtrlOut = DumpCtrlPtr; + } +} + +/* Resets the indicated dump control block to the free/unused state */ +void UT_TBL_ResetDumpCtrlState(uint32 ArrayIndex) +{ + CFE_TBL_DumpControl_t *DumpCtrlPtr; + DumpCtrlPtr = &CFE_TBL_Global.DumpControlBlocks[ArrayIndex]; + memset(DumpCtrlPtr, 0, sizeof(*DumpCtrlPtr)); +} + /* ** Functions */ @@ -128,6 +214,15 @@ 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); + UT_ADD_TEST(Test_CFE_TBL_ResourceID_DumpControl); + /* cfe_tbl_task_cmds.c functions */ /* This should be done first (it initializes working data structures) */ UT_ADD_TEST(Test_CFE_TBL_DeleteCDSCmd); @@ -209,20 +304,13 @@ 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 */ for (i = 0; i < CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS; i++) { - CFE_TBL_Global.DumpControlBlocks[i].State = CFE_TBL_DUMP_FREE; - CFE_TBL_Global.DumpControlBlocks[i].DumpBufferPtr = NULL; - CFE_TBL_Global.DumpControlBlocks[i].Size = 0; - CFE_TBL_Global.DumpControlBlocks[i].TableName[0] = '\0'; + UT_TBL_ResetDumpCtrlState(i); /* Free all shared buffers */ CFE_TBL_Global.LoadBuffs[i].Taken = false; @@ -617,7 +705,7 @@ void Test_CFE_TBL_ActivateCmd(void) */ void Test_CFE_TBL_DumpToFile(void) { - uint32 TblSizeInBytes = 9; + size_t TblSizeInBytes = 9; UtPrintf("Begin Test Dump to File"); @@ -673,7 +761,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 +783,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 +798,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 +807,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 +819,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 +832,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 +901,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 +933,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); @@ -1024,7 +1109,7 @@ void Test_CFE_TBL_DumpRegCmd(void) */ void Test_CFE_TBL_DumpCmd(void) { - int i, k, u; + int i, u; uint8 Buff; uint8 * BuffPtr = &Buff; CFE_TBL_LoadBuff_t Load = {0}; @@ -1060,9 +1145,9 @@ void Test_CFE_TBL_DumpCmd(void) CFE_TBL_Global.Registry[i].DumpOnly = true; } - CFE_TBL_Global.DumpControlBlocks[2].State = CFE_TBL_DUMP_PENDING; - CFE_TBL_Global.DumpControlBlocks[3].State = CFE_TBL_DUMP_FREE; - CFE_TBL_Global.Registry[2].DumpControlIndex = CFE_TBL_NO_DUMP_PENDING; + UT_TBL_SetupPendingDump(2, NULL, NULL, NULL); + UT_TBL_ResetDumpCtrlState(3); + CFE_TBL_Global.Registry[2].DumpControlId = CFE_TBL_NO_DUMP_PENDING; CFE_TBL_Global.Registry[2].LoadInProgress = CFE_TBL_NO_LOAD_IN_PROGRESS + 1; CFE_TBL_Global.Registry[2].DoubleBuffered = false; CFE_TBL_Global.LoadBuffs[CFE_TBL_Global.Registry[2].LoadInProgress] = Load; @@ -1076,11 +1161,11 @@ void Test_CFE_TBL_DumpCmd(void) * available */ UT_InitData(); - CFE_TBL_Global.DumpControlBlocks[2].State = CFE_TBL_DUMP_FREE; - CFE_TBL_Global.Registry[2].DumpControlIndex = CFE_TBL_NO_DUMP_PENDING; - CFE_TBL_Global.Registry[2].LoadInProgress = CFE_TBL_NO_LOAD_IN_PROGRESS; - CFE_TBL_Global.Registry[2].TableLoadedOnce = true; - CFE_TBL_Global.Registry[2].DoubleBuffered = false; + UT_TBL_ResetDumpCtrlState(2); + CFE_TBL_Global.Registry[2].DumpControlId = CFE_TBL_NO_DUMP_PENDING; + CFE_TBL_Global.Registry[2].LoadInProgress = CFE_TBL_NO_LOAD_IN_PROGRESS; + CFE_TBL_Global.Registry[2].TableLoadedOnce = true; + CFE_TBL_Global.Registry[2].DoubleBuffered = false; for (u = 0; u < CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS; u++) { @@ -1095,14 +1180,9 @@ void Test_CFE_TBL_DumpCmd(void) * dump only table dumps have been requested */ UT_InitData(); - CFE_TBL_Global.Registry[2].DumpControlIndex = CFE_TBL_NO_DUMP_PENDING; - - for (k = 0; k < CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS; k++) - { - CFE_TBL_Global.DumpControlBlocks[k].State = CFE_TBL_DUMP_PENDING; - } - - CFE_TBL_Global.Registry[2].NotifyByMsg = true; + CFE_TBL_Global.Registry[2].DumpControlId = CFE_TBL_NO_DUMP_PENDING; + CFE_TBL_Global.Registry[2].NotifyByMsg = true; + UT_SetDeferredRetcode(UT_KEY(CFE_ResourceId_FindNext), 1, 0); UtAssert_INT32_EQ(CFE_TBL_DumpCmd(&DumpCmd), CFE_TBL_INC_ERR_CTR); /* Test with an inactive buffer, double-buffered, dump already in progress; @@ -1112,7 +1192,7 @@ void Test_CFE_TBL_DumpCmd(void) DumpCmd.Payload.ActiveTableFlag = CFE_TBL_BufferSelect_INACTIVE; CFE_TBL_Global.Registry[2].DoubleBuffered = true; CFE_TBL_Global.Registry[2].Buffers[(1 - CFE_TBL_Global.Registry[2].ActiveBufferIndex)].BufferPtr = BuffPtr; - CFE_TBL_Global.Registry[2].DumpControlIndex = CFE_TBL_NO_DUMP_PENDING + 1; + CFE_TBL_Global.Registry[2].DumpControlId = CFE_TBL_DUMPCTRLID_C(CFE_ResourceId_FromInteger(1)); UtAssert_INT32_EQ(CFE_TBL_DumpCmd(&DumpCmd), CFE_TBL_INC_ERR_CTR); /* Test with an inactive buffer, single-buffered, pointer created, is a @@ -1321,13 +1401,14 @@ void Test_CFE_TBL_LoadCmd(void) */ void Test_CFE_TBL_SendHkCmd(void) { - int i; - CFE_TBL_LoadBuff_t DumpBuff; - CFE_TBL_LoadBuff_t * DumpBuffPtr = &DumpBuff; - CFE_TBL_RegistryRec_t RegRecPtr; - uint8 Buff; - void * BuffPtr = &Buff; - int32 LoadInProg = 0; + int i; + CFE_TBL_LoadBuff_t DumpBuff; + CFE_TBL_LoadBuff_t * DumpBuffPtr = &DumpBuff; + CFE_TBL_RegistryRec_t *RegRecPtr; + uint8 Buff; + void * BuffPtr = &Buff; + int32 LoadInProg = 0; + CFE_TBL_DumpControl_t *DumpCtrlPtr; UtPrintf("Begin Test Housekeeping Command"); @@ -1335,25 +1416,21 @@ void Test_CFE_TBL_SendHkCmd(void) * to send Hk packet */ UT_InitData(); - strncpy(CFE_TBL_Global.DumpControlBlocks[0].TableName, "housekeepingtest", - sizeof(CFE_TBL_Global.DumpControlBlocks[0].TableName) - 1); - CFE_TBL_Global.DumpControlBlocks[0].TableName[sizeof(CFE_TBL_Global.DumpControlBlocks[0].TableName) - 1] = '\0'; - CFE_TBL_Global.DumpControlBlocks[0].Size = 10; - LoadInProg = CFE_TBL_NO_LOAD_IN_PROGRESS + 1; - RegRecPtr.LoadInProgress = LoadInProg; - CFE_TBL_Global.DumpControlBlocks[0].RegRecPtr = &RegRecPtr; - DumpBuffPtr->Taken = true; - DumpBuffPtr->Validated = true; - DumpBuffPtr->BufferPtr = BuffPtr; - DumpBuffPtr->FileTime = CFE_TIME_ZERO_VALUE; + RegRecPtr = &CFE_TBL_Global.Registry[0]; + UT_TBL_SetupPendingDump(0, DumpBuffPtr, RegRecPtr, &DumpCtrlPtr); + LoadInProg = CFE_TBL_NO_LOAD_IN_PROGRESS + 1; + RegRecPtr->LoadInProgress = LoadInProg; + DumpBuffPtr->Taken = true; + DumpBuffPtr->Validated = true; + DumpBuffPtr->BufferPtr = BuffPtr; + DumpBuffPtr->FileTime = CFE_TIME_ZERO_VALUE; strncpy(DumpBuffPtr->DataSource, "hkSource", sizeof(DumpBuffPtr->DataSource) - 1); DumpBuffPtr->DataSource[sizeof(DumpBuffPtr->DataSource) - 1] = '\0'; - CFE_TBL_Global.DumpControlBlocks[0].DumpBufferPtr = DumpBuffPtr; - CFE_TBL_Global.DumpControlBlocks[0].State = CFE_TBL_DUMP_PERFORMED; + DumpCtrlPtr->State = CFE_TBL_DUMP_PERFORMED; for (i = 1; i < CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS; i++) { - CFE_TBL_Global.DumpControlBlocks[i].State = CFE_TBL_DUMP_PENDING; + UT_TBL_SetupPendingDump(i, NULL, NULL, NULL); } UT_SetDeferredRetcode(UT_KEY(CFE_SB_TransmitMsg), 1, CFE_SUCCESS - 1); @@ -1362,35 +1439,38 @@ void Test_CFE_TBL_SendHkCmd(void) for (i = 1; i < CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS; i++) { - CFE_TBL_Global.DumpControlBlocks[i].State = CFE_TBL_DUMP_PENDING; + UT_TBL_SetupPendingDump(i, NULL, NULL, NULL); } - RegRecPtr.LoadInProgress = LoadInProg; - CFE_TBL_Global.DumpControlBlocks[0].RegRecPtr = &RegRecPtr; + RegRecPtr->LoadInProgress = LoadInProg; /* Test response to inability to open dump file */ UT_InitData(); - CFE_TBL_Global.DumpControlBlocks[0].State = CFE_TBL_DUMP_PERFORMED; - CFE_TBL_Global.HkTlmTblRegIndex = CFE_TBL_NOT_FOUND + 1; + UT_TBL_SetupPendingDump(0, DumpBuffPtr, RegRecPtr, &DumpCtrlPtr); + DumpCtrlPtr->State = CFE_TBL_DUMP_PERFORMED; + CFE_TBL_Global.HkTlmTblRegIndex = CFE_TBL_NOT_FOUND + 1; UT_SetDefaultReturnValue(UT_KEY(OS_OpenCreate), OS_ERROR); UtAssert_INT32_EQ(CFE_TBL_SendHkCmd(NULL), CFE_TBL_DONT_INC_CTR); /* Test response to an invalid table and a dump file create failure */ UT_InitData(); - CFE_TBL_Global.HkTlmTblRegIndex = CFE_TBL_NOT_FOUND; - CFE_TBL_Global.DumpControlBlocks[0].State = CFE_TBL_DUMP_PERFORMED; + UT_TBL_SetupPendingDump(0, DumpBuffPtr, RegRecPtr, &DumpCtrlPtr); + CFE_TBL_Global.HkTlmTblRegIndex = CFE_TBL_NOT_FOUND; + DumpCtrlPtr->State = CFE_TBL_DUMP_PERFORMED; UT_SetDefaultReturnValue(UT_KEY(OS_OpenCreate), OS_ERROR); UtAssert_INT32_EQ(CFE_TBL_SendHkCmd(NULL), CFE_TBL_DONT_INC_CTR); /* Test response to a file time stamp failure */ UT_InitData(); - CFE_TBL_Global.DumpControlBlocks[0].State = CFE_TBL_DUMP_PERFORMED; + UT_TBL_SetupPendingDump(0, DumpBuffPtr, RegRecPtr, &DumpCtrlPtr); + DumpCtrlPtr->State = CFE_TBL_DUMP_PERFORMED; UT_SetDeferredRetcode(UT_KEY(CFE_FS_SetTimestamp), 1, OS_SUCCESS - 1); UtAssert_INT32_EQ(CFE_TBL_SendHkCmd(NULL), CFE_TBL_DONT_INC_CTR); /* Test response to OS_OpenCreate failure */ UT_InitData(); - CFE_TBL_Global.DumpControlBlocks[0].State = CFE_TBL_DUMP_PERFORMED; + UT_TBL_SetupPendingDump(0, DumpBuffPtr, RegRecPtr, &DumpCtrlPtr); + DumpCtrlPtr->State = CFE_TBL_DUMP_PERFORMED; UT_SetDeferredRetcode(UT_KEY(OS_OpenCreate), 3, -1); UtAssert_INT32_EQ(CFE_TBL_SendHkCmd(NULL), CFE_TBL_DONT_INC_CTR); } @@ -2469,14 +2549,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 +2582,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 +2652,8 @@ void Test_CFE_TBL_Manage(void) void * App2TblPtr; CFE_TBL_AccessDescriptor_t *AccessDescPtr; CFE_TBL_Handle_t AccessIterator; + CFE_TBL_ValidationResult_t *ValResultPtr; + CFE_TBL_DumpControl_t * DumpCtrlPtr; memset(&TestTable1, 0, sizeof(TestTable1)); @@ -2561,6 +2670,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 +2686,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 +2701,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 +2716,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 +2730,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 +2746,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 +2761,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 +2776,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 +2858,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 +2873,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 +2888,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,41 +2903,26 @@ 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(); CFE_UtAssert_SUCCESS(CFE_TBL_GetWorkingBuffer(&WorkingBufferPtr, RegRecPtr, false)); - CFE_TBL_Global.DumpControlBlocks[0].State = CFE_TBL_DUMP_PENDING; - CFE_TBL_Global.DumpControlBlocks[0].RegRecPtr = RegRecPtr; + UT_TBL_SetupPendingDump(0, WorkingBufferPtr, RegRecPtr, &DumpCtrlPtr); /* Save the name of the desired dump filename, table name, and size for * later */ - CFE_TBL_Global.DumpControlBlocks[0].DumpBufferPtr = WorkingBufferPtr; - strncpy(CFE_TBL_Global.DumpControlBlocks[0].DumpBufferPtr->DataSource, "MyDumpFilename", - sizeof(CFE_TBL_Global.DumpControlBlocks[0].DumpBufferPtr->DataSource) - 1); - CFE_TBL_Global.DumpControlBlocks[0] - .DumpBufferPtr->DataSource[sizeof(CFE_TBL_Global.DumpControlBlocks[0].DumpBufferPtr->DataSource) - 1] = 0; - strncpy(CFE_TBL_Global.DumpControlBlocks[0].TableName, "ut_cfe_tbl.UT_Table2", - sizeof(CFE_TBL_Global.DumpControlBlocks[0].TableName) - 1); - CFE_TBL_Global.DumpControlBlocks[0].TableName[sizeof(CFE_TBL_Global.DumpControlBlocks[0].TableName) - 1] = 0; - CFE_TBL_Global.DumpControlBlocks[0].Size = RegRecPtr->Size; - RegRecPtr->DumpControlIndex = 0; + strncpy(WorkingBufferPtr->DataSource, "MyDumpFilename", sizeof(WorkingBufferPtr->DataSource) - 1); + WorkingBufferPtr->DataSource[sizeof(WorkingBufferPtr->DataSource) - 1] = 0; CFE_UtAssert_SUCCESS(CFE_TBL_Manage(App1TblHandle2)); CFE_UtAssert_EVENTCOUNT(0); } @@ -3220,6 +3250,7 @@ void Test_CFE_TBL_Internal(void) CFE_TBL_LoadBuff_t * WorkingBufferPtr; CFE_TBL_RegistryRec_t * RegRecPtr; CFE_TBL_AccessDescriptor_t *AccessDescPtr; + CFE_TBL_DumpControl_t * DumpCtrlPtr; char FilenameLong[OS_MAX_PATH_LEN + 10]; char Filename[OS_MAX_PATH_LEN]; int32 i; @@ -3757,16 +3788,18 @@ void Test_CFE_TBL_Internal(void) UT_InitData(); UT_SetAppID(UT_TBL_APPID_1); UT_SetDefaultReturnValue(UT_KEY(CFE_ES_PutPoolBuf), -1); - AccessDescPtr = &CFE_TBL_Global.Handles[App1TblHandle1]; - RegRecPtr = &CFE_TBL_Global.Registry[AccessDescPtr->RegIndex]; - CFE_TBL_Global.DumpControlBlocks[3].State = CFE_TBL_DUMP_PENDING; - CFE_TBL_Global.DumpControlBlocks[3].RegRecPtr = RegRecPtr; - RegRecPtr->LoadInProgress = 1; - CFE_TBL_Global.LoadBuffs[1].Taken = true; + AccessDescPtr = &CFE_TBL_Global.Handles[App1TblHandle1]; + RegRecPtr = &CFE_TBL_Global.Registry[AccessDescPtr->RegIndex]; + WorkingBufferPtr = &CFE_TBL_Global.LoadBuffs[1]; + + UT_TBL_SetupPendingDump(3, WorkingBufferPtr, RegRecPtr, &DumpCtrlPtr); + + RegRecPtr->LoadInProgress = 1; + WorkingBufferPtr->Taken = true; CFE_UtAssert_SUCCESS(CFE_TBL_CleanUpApp(UT_TBL_APPID_1)); - UtAssert_INT32_EQ(CFE_TBL_Global.DumpControlBlocks[3].State, CFE_TBL_DUMP_FREE); + UtAssert_INT32_EQ(DumpCtrlPtr->State, CFE_TBL_DUMP_FREE); CFE_UtAssert_RESOURCEID_EQ(RegRecPtr->OwnerAppId, CFE_TBL_NOT_OWNED); - UtAssert_BOOL_FALSE(CFE_TBL_Global.LoadBuffs[RegRecPtr->LoadInProgress].Taken); + UtAssert_BOOL_FALSE(WorkingBufferPtr->Taken); UtAssert_INT32_EQ(RegRecPtr->LoadInProgress, CFE_TBL_NO_LOAD_IN_PROGRESS); /* Test response to an attempt to use an invalid table handle */ @@ -3895,16 +3928,18 @@ void Test_CFE_TBL_Internal(void) UT_InitData(); UT_SetAppID(UT_TBL_APPID_1); UT_SetDefaultReturnValue(UT_KEY(CFE_ES_PutPoolBuf), -1); - CFE_TBL_Global.Handles[0].AppId = UT_TBL_APPID_1; - CFE_TBL_Global.Handles[0].UsedFlag = true; - CFE_TBL_Global.Handles[0].RegIndex = 0; - CFE_TBL_Global.Registry[0].OwnerAppId = UT_TBL_APPID_2; - CFE_TBL_Global.DumpControlBlocks[3].State = CFE_TBL_DUMP_PENDING; - CFE_TBL_Global.DumpControlBlocks[3].RegRecPtr = &CFE_TBL_Global.Registry[0]; - CFE_TBL_Global.Handles[1].AppId = UT_TBL_APPID_1; - CFE_TBL_Global.Handles[1].UsedFlag = false; + RegRecPtr = &CFE_TBL_Global.Registry[0]; + UT_TBL_SetupPendingDump(3, NULL, RegRecPtr, &DumpCtrlPtr); + + CFE_TBL_Global.Handles[0].AppId = UT_TBL_APPID_1; + CFE_TBL_Global.Handles[0].UsedFlag = true; + CFE_TBL_Global.Handles[0].RegIndex = 0; + RegRecPtr->OwnerAppId = UT_TBL_APPID_2; + CFE_TBL_Global.Handles[1].AppId = UT_TBL_APPID_1; + CFE_TBL_Global.Handles[1].UsedFlag = false; + CFE_UtAssert_SUCCESS(CFE_TBL_CleanUpApp(UT_TBL_APPID_1)); - UtAssert_INT32_EQ(CFE_TBL_Global.DumpControlBlocks[3].State, CFE_TBL_DUMP_PENDING); + UtAssert_INT32_EQ(DumpCtrlPtr->State, CFE_TBL_DUMP_PENDING); CFE_UtAssert_RESOURCEID_EQ(RegRecPtr->OwnerAppId, UT_TBL_APPID_2); #if (CFE_PLATFORM_TBL_VALID_SCID_COUNT > 0) @@ -3999,6 +4034,148 @@ 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); +} + +/* + * Tests the resource accessors for Dump Control Blocks + */ +void Test_CFE_TBL_ResourceID_DumpControl(void) +{ + uint32 Idx; + CFE_TBL_DumpCtrlId_t InvalidBlockId; + CFE_TBL_DumpCtrlId_t ValidBlockId; + CFE_ResourceId_t PendingId; + + UT_InitData(); + + InvalidBlockId = CFE_TBL_DUMPCTRLID_UNDEFINED; + UT_SetDefaultReturnValue(UT_KEY(CFE_ResourceId_ToIndex), CFE_ES_ERR_RESOURCEID_NOT_VALID); + UtAssert_INT32_EQ(CFE_TBL_DumpCtrlId_ToIndex(InvalidBlockId, &Idx), CFE_ES_ERR_RESOURCEID_NOT_VALID); + + /* by definition, looking up the undefined value should always be NULL */ + UtAssert_NULL(CFE_TBL_LocateDumpCtrlByID(InvalidBlockId)); + UT_ResetState(UT_KEY(CFE_ResourceId_ToIndex)); + + ValidBlockId = CFE_TBL_DUMPCTRLID_C(CFE_ResourceId_FromInteger(CFE_TBL_DUMPCTRLID_BASE + 1)); + UtAssert_INT32_EQ(CFE_TBL_DumpCtrlId_ToIndex(ValidBlockId, &Idx), CFE_SUCCESS); + + UtAssert_VOIDCALL(PendingId = CFE_TBL_GetNextDumpCtrlBlock()); + UtAssert_BOOL_TRUE(CFE_ResourceId_IsDefined(PendingId)); + + /* The slot should be available right now */ + UtAssert_BOOL_FALSE(CFE_TBL_CheckDumpCtrlSlotUsed(PendingId)); + + /* Make it used and confirm it is reported as not available */ + CFE_TBL_DumpCtrlBlockSetUsed(CFE_TBL_LocateDumpCtrlByID(CFE_TBL_DUMPCTRLID_C(PendingId)), PendingId); + UtAssert_BOOL_TRUE(CFE_TBL_CheckDumpCtrlSlotUsed(PendingId)); + + /* Test case where no ID is available */ + UT_SetDefaultReturnValue(UT_KEY(CFE_ResourceId_FindNext), 0); + UtAssert_VOIDCALL(PendingId = CFE_TBL_GetNextDumpCtrlBlock()); + UtAssert_BOOL_FALSE(CFE_ResourceId_IsDefined(PendingId)); + + /* A nonexistent slot is always "unavailable" */ + UtAssert_BOOL_TRUE(CFE_TBL_CheckDumpCtrlSlotUsed(PendingId)); + UT_ResetState(UT_KEY(CFE_ResourceId_FindNext)); +} + /* ** 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..b4b5fd8db 100644 --- a/modules/tbl/ut-coverage/tbl_UT.h +++ b/modules/tbl/ut-coverage/tbl_UT.h @@ -680,4 +680,10 @@ 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); +void Test_CFE_TBL_ResourceID_DumpControl(void); + #endif /* TBL_UT_H */ diff --git a/modules/time/config/default_cfe_time_interface_cfg.h b/modules/time/config/default_cfe_time_interface_cfg.h index 3e614f154..332a85111 100644 --- a/modules/time/config/default_cfe_time_interface_cfg.h +++ b/modules/time/config/default_cfe_time_interface_cfg.h @@ -25,7 +25,7 @@ * interface, tables definitions, and any other data products that * serve to exchange information with other entities. * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ diff --git a/modules/time/config/default_cfe_time_internal_cfg.h b/modules/time/config/default_cfe_time_internal_cfg.h index f00c25e7c..33d72da52 100644 --- a/modules/time/config/default_cfe_time_internal_cfg.h +++ b/modules/time/config/default_cfe_time_internal_cfg.h @@ -25,7 +25,7 @@ * to items in this file only affect the local module and will be transparent * to external entities that are using the public interface(s). * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ diff --git a/modules/time/config/default_cfe_time_mission_cfg.h b/modules/time/config/default_cfe_time_mission_cfg.h index 5e8e973c1..720aee1e9 100644 --- a/modules/time/config/default_cfe_time_mission_cfg.h +++ b/modules/time/config/default_cfe_time_mission_cfg.h @@ -24,7 +24,7 @@ * This is a compatibility header for the "mission_cfg.h" file that has * traditionally provided public config definitions for each CFS app. * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ diff --git a/modules/time/config/default_cfe_time_msg.h b/modules/time/config/default_cfe_time_msg.h index 4156bdbd2..30d25f0a2 100644 --- a/modules/time/config/default_cfe_time_msg.h +++ b/modules/time/config/default_cfe_time_msg.h @@ -24,7 +24,7 @@ * This is a compatibility header for the "cfe_time_msg.h" file that has * traditionally provided the message definitions for cFS apps. * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */ diff --git a/modules/time/config/default_cfe_time_platform_cfg.h b/modules/time/config/default_cfe_time_platform_cfg.h index 414213026..f094f4400 100644 --- a/modules/time/config/default_cfe_time_platform_cfg.h +++ b/modules/time/config/default_cfe_time_platform_cfg.h @@ -28,7 +28,7 @@ * These definitions are now provided in two separate files, one for * the public/mission scope and one for internal scope. * - * @note This file may be overridden/superceded by mission-provided defintions + * @note This file may be overridden/superceded by mission-provided definitions * either by overriding this header or by generating definitions from a command/data * dictionary tool. */