diff --git a/cmake/mission_defaults.cmake b/cmake/mission_defaults.cmake
index 33e8c292b..444a1138e 100644
--- a/cmake/mission_defaults.cmake
+++ b/cmake/mission_defaults.cmake
@@ -15,6 +15,7 @@ set(MISSION_CORE_MODULES
"osal"
"psp"
"msg"
+ "sbr"
)
# The "MISSION_GLOBAL_APPLIST" is a set of apps/libs that will be built
diff --git a/cmake/sample_defs/cpu1_platform_cfg.h b/cmake/sample_defs/cpu1_platform_cfg.h
index e82e24abb..fa5f9ced7 100644
--- a/cmake/sample_defs/cpu1_platform_cfg.h
+++ b/cmake/sample_defs/cpu1_platform_cfg.h
@@ -47,7 +47,11 @@
** regarding this parameter, send an SB command to 'Send Statistics Pkt'.
**
** \par Limits
-** This parameter has a lower limit of 1 and an upper limit of 1024.
+** This must be a power of two if software bus message routing hash implementation
+** is being used. Lower than 64 will cause unit test failures, and
+** telemetry reporting is impacted below 32. There is no hard
+** upper limit, but impacts memory footprint. For software bus message routing
+** search implementation the number of msg ids subscribed to impacts performance.
**
*/
#define CFE_PLATFORM_SB_MAX_MSG_IDS 256
diff --git a/fsw/cfe-core/src/inc/cfe_sb_events.h b/fsw/cfe-core/src/inc/cfe_sb_events.h
index 9144d852e..c99e55eed 100644
--- a/fsw/cfe-core/src/inc/cfe_sb_events.h
+++ b/fsw/cfe-core/src/inc/cfe_sb_events.h
@@ -497,6 +497,21 @@
**/
#define CFE_SB_SUBSCRIPTION_RPT_EID 22
+/** \brief 'Msg hash collision: MsgId = 0x\%x, collisions = \%u'
+** \event 'Msg hash collision: MsgId = 0x\%x, collisions = \%u'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This event message is generated when a message id hash collision occurs when subscribing
+** to a message. Collisions indicate how many slots were incremented to find an opening.
+**
+** Number of collisions will directly impact software bus performance. These can be resolved
+** by adjusting MsgId values or increasing CFE_PLATFORM_SB_MAX_MSG_IDS.
+**/
+#define CFE_SB_HASHCOLLISION_EID 23
+
/** \brief 'Pipe Overflow,MsgId 0x\%x,pipe \%s,stat 0x\%x,app \%s'
** \event 'Pipe Overflow,MsgId 0x\%x,pipe \%s,stat 0x\%x,app \%s'
**
diff --git a/fsw/cfe-core/src/inc/cfe_sb_extern_typedefs.h b/fsw/cfe-core/src/inc/cfe_sb_extern_typedefs.h
index 810355005..8eaea63e7 100644
--- a/fsw/cfe-core/src/inc/cfe_sb_extern_typedefs.h
+++ b/fsw/cfe-core/src/inc/cfe_sb_extern_typedefs.h
@@ -88,7 +88,7 @@ typedef uint8 CFE_SB_QosReliability_E
/**
* @brief An integer type that should be used for indexing into the Routing Table
*/
-typedef uint16 CFE_SB_MsgRouteIdx_Atom_t;
+typedef uint16 CFE_SB_RouteId_Atom_t;
/**
* @brief CFE_SB_MsgId_Atom_t primitive type definition
diff --git a/fsw/cfe-core/src/inc/cfe_sb_msg.h b/fsw/cfe-core/src/inc/cfe_sb_msg.h
index f8ad212bc..03407b0c9 100644
--- a/fsw/cfe-core/src/inc/cfe_sb_msg.h
+++ b/fsw/cfe-core/src/inc/cfe_sb_msg.h
@@ -683,8 +683,8 @@ typedef struct CFE_SB_RoutingFileEntry {
** Structure of one element of the map information in response to #CFE_SB_SEND_MAP_INFO_CC
*/
typedef struct CFE_SB_MsgMapFileEntry {
- CFE_SB_MsgId_t MsgId;/**< \brief Message Id which has been subscribed to */
- CFE_SB_MsgRouteIdx_Atom_t Index;/**< \brief Routing table index where pipe destinations are found */
+ CFE_SB_MsgId_t MsgId;/**< \brief Message Id which has been subscribed to */
+ CFE_SB_RouteId_Atom_t Index;/**< \brief Routing raw index value (0 based, not Route ID) */
}CFE_SB_MsgMapFileEntry_t;
diff --git a/fsw/cfe-core/src/inc/private/cfe_sb_destination_typedef.h b/fsw/cfe-core/src/inc/private/cfe_sb_destination_typedef.h
new file mode 100644
index 000000000..8627b8476
--- /dev/null
+++ b/fsw/cfe-core/src/inc/private/cfe_sb_destination_typedef.h
@@ -0,0 +1,52 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** 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.
+*/
+
+/**
+ * Definition of the CFE_SB_DestinationD_t type.
+ * This was moved into its own header file since it is referenced by multiple CFE modules.
+ */
+
+#ifndef CFE_SB_DESTINATION_TYPEDEF_H_
+#define CFE_SB_DESTINATION_TYPEDEF_H_
+
+#include "common_types.h"
+#include "cfe_sb.h" /* Required for CFE_SB_PipeId_t definition */
+
+/******************************************************************************
+ * This structure defines a DESTINATION DESCRIPTOR used to specify
+ * each destination pipe for a message.
+ *
+ * Note: Changing the size of this structure may require the memory pool
+ * block sizes to change.
+ */
+typedef struct
+{
+ CFE_SB_PipeId_t PipeId;
+ uint8 Active;
+ uint16 MsgId2PipeLim;
+ uint16 BuffCount;
+ uint16 DestCnt;
+ uint8 Scope;
+ uint8 Spare[3];
+ void *Prev;
+ void *Next;
+} CFE_SB_DestinationD_t;
+
+#endif /* CFE_SB_DESTINATION_TYPEDEF_H_ */
diff --git a/fsw/cfe-core/src/inc/private/cfe_sbr.h b/fsw/cfe-core/src/inc/private/cfe_sbr.h
new file mode 100644
index 000000000..de0123bd7
--- /dev/null
+++ b/fsw/cfe-core/src/inc/private/cfe_sbr.h
@@ -0,0 +1,205 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** 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.
+*/
+
+/******************************************************************************
+ * File: cfe_sbr.h
+ *
+ * Purpose:
+ * Prototypes for private functions and type definitions for SB
+ * routing internal use.
+ *****************************************************************************/
+
+#ifndef CFE_SBR_H_
+#define CFE_SBR_H_
+
+/*
+ * Includes
+ */
+#include "common_types.h"
+#include "private/cfe_sb_destination_typedef.h"
+#include "cfe_sb.h"
+#include "cfe_msg_typedefs.h"
+#include "cfe_platform_cfg.h"
+
+/******************************************************************************
+ * Type Definitions
+ */
+
+/**
+ * \brief Routing table id
+ *
+ * This is intended as a form of "strong typedef" where direct assignments should
+ * be restricted. Software bus uses numeric indexes into multiple tables to perform
+ * its duties, and it is important that these index values are distinct and separate
+ * and not mixed together.
+ *
+ * Using this holding structure prevents assignment directly into a different index
+ * or direct usage as numeric value.
+ */
+typedef struct
+{
+ CFE_SB_RouteId_Atom_t RouteId; /**< \brief Holding value, do not use directly in code */
+} CFE_SBR_RouteId_t;
+
+/** \brief Callback throttling structure */
+typedef struct
+{
+ uint32 StartIndex; /**< /brief 0 based index to start at */
+ uint32 MaxLoop; /**< /brief Max number to process */
+ uint32 NextIndex; /**< /brief Next start index (output), 0 if completed */
+} CFE_SBR_Throttle_t;
+
+/** \brief For each id callback function prototype */
+typedef void (*CFE_SBR_CallbackPtr_t)(CFE_SBR_RouteId_t RouteId, void *ArgPtr);
+
+/******************************************************************************
+ * Function prototypes
+ */
+
+/**
+ * \brief Initialize software bus routing module
+ */
+void CFE_SBR_Init(void);
+
+/**
+ * \brief Add a route for the given a message id
+ *
+ * Called for the first subscription to a message ID, uses up one
+ * element in the routing table. Assumes check for existing
+ * route was already performed or routes could leak
+ *
+ * \param[in] MsgId Message ID of the route to add
+ * \param[out] CollisionsPtr Number of collisions (if not null)
+ *
+ * \returns Route ID, will be invalid if route can not be added
+ */
+CFE_SBR_RouteId_t CFE_SBR_AddRoute(CFE_SB_MsgId_t MsgId, uint32 *CollisionsPtr);
+
+/**
+ * \brief Obtain the route id given a message id
+ *
+ * \param[in] MsgId Message ID of the route to get
+ *
+ * \returns Route ID, will be invalid if can't be returned
+ */
+CFE_SBR_RouteId_t CFE_SBR_GetRouteId(CFE_SB_MsgId_t MsgId);
+
+/**
+ * \brief Obtain the message id given a route id
+ *
+ * \param[in] RouteId Route ID of the message id to get
+ *
+ * \returns Message ID, will be invalid if cant be returned
+ */
+CFE_SB_MsgId_t CFE_SBR_GetMsgId(CFE_SBR_RouteId_t RouteId);
+
+/**
+ * \brief Obtain the destination list head pointer given a route id
+ *
+ * \param[in] RouteId Route ID
+ *
+ * \returns Destination list head pointer for the given route id.
+ * Will be null if route doesn't exist or no subscribers.
+ */
+CFE_SB_DestinationD_t *CFE_SBR_GetDestListHeadPtr(CFE_SBR_RouteId_t RouteId);
+
+/**
+ * \brief Set the destination list head pointer for given route id
+ *
+ * \param[in] RouteId Route Id
+ * \param[in] DestPtr Destination list head pointer
+ */
+void CFE_SBR_SetDestListHeadPtr(CFE_SBR_RouteId_t RouteId, CFE_SB_DestinationD_t *DestPtr);
+
+/**
+ * \brief Increment the sequence counter associated with the supplied route ID
+ *
+ * \param[in] RouteId Route ID
+ */
+void CFE_SBR_IncrementSequenceCounter(CFE_SBR_RouteId_t RouteId);
+
+/**
+ * \brief Get the sequence counter associated with the supplied route ID
+ *
+ * \param[in] RouteId Route ID
+ *
+ * \returns the sequence counter
+ */
+CFE_MSG_SequenceCount_t CFE_SBR_GetSequenceCounter(CFE_SBR_RouteId_t RouteId);
+
+/**
+ * \brief Call the supplied callback function for all routes
+ *
+ * Invokes callback for each route in the table. Message ID order
+ * depends on the routing table implementation. Possiblities include
+ * in subscription order and in order if incrementing message ids.
+ *
+ * \param[in] CallbackPtr Function to invoke for each matching ID
+ * \param[in] ArgPtr Opaque argument to pass to callback function
+ * \param[in,out] ThrottlePtr Throttling structure, NULL for no throttle
+ */
+void CFE_SBR_ForEachRouteId(CFE_SBR_CallbackPtr_t CallbackPtr, void *ArgPtr, CFE_SBR_Throttle_t *ThrottlePtr);
+
+/******************************************************************************
+** Inline functions
+*/
+
+/**
+ * \brief Identifies whether a given CFE_SBR_RouteId_t is valid
+ *
+ * Implements a basic sanity check on the value provided
+ *
+ * \returns true if sanity checks passed, false otherwise.
+ */
+static inline bool CFE_SBR_IsValidRouteId(CFE_SBR_RouteId_t RouteId)
+{
+ return (RouteId.RouteId != 0 && RouteId.RouteId <= CFE_PLATFORM_SB_MAX_MSG_IDS);
+}
+
+/**
+ * \brief Converts from raw value to CFE_SBR_RouteId_t
+ *
+ * Converts the supplied "bare number" into a type-safe CFE_SBR_RouteId_t value
+ *
+ * \returns A CFE_SBR_RouteId_t
+ */
+static inline CFE_SBR_RouteId_t CFE_SBR_ValueToRouteId(CFE_SB_RouteId_Atom_t Value)
+{
+ return ((CFE_SBR_RouteId_t) {.RouteId = 1 + Value});
+}
+
+/**
+ * \brief Converts from CFE_SBR_RouteId_t to raw value
+ *
+ * Converts the supplied route id into a "bare number" suitable for performing
+ * array lookups or other tasks for which the holding structure cannot be used directly.
+ *
+ * Use with caution, as this removes the type safety information from the value.
+ *
+ * \note It is assumed the value has already been validated using CFE_SB_IsValidRouteId()
+ *
+ * \returns The underlying value
+ */
+static inline CFE_SB_RouteId_Atom_t CFE_SBR_RouteIdToValue(CFE_SBR_RouteId_t RouteId)
+{
+ return (RouteId.RouteId - 1);
+}
+
+#endif /* CFE_SBR_H_ */
diff --git a/fsw/cfe-core/src/sb/cfe_sb_api.c b/fsw/cfe-core/src/sb/cfe_sb_api.c
index 44a7019a6..57dddd61d 100644
--- a/fsw/cfe-core/src/sb/cfe_sb_api.c
+++ b/fsw/cfe-core/src/sb/cfe_sb_api.c
@@ -75,6 +75,13 @@
*/
#define CFE_SB_TLM_PIPEDEPTHSTATS_SIZE (sizeof(CFE_SB.StatTlmMsg.Payload.PipeDepthStats) / sizeof(CFE_SB.StatTlmMsg.Payload.PipeDepthStats[0]))
+/* Local structure for remove pipe callbacks */
+typedef struct
+{
+ const char *FullName; /* Full name (app.task) for error reporting */
+ CFE_SB_PipeId_t PipeId; /* Pipe id to remove */
+} CFE_SB_RemovePipeCallback_t;
+
/*
* Function: CFE_SB_CreatePipe - See API and header file for details
*/
@@ -246,7 +253,23 @@ int32 CFE_SB_DeletePipeWithAppId(CFE_SB_PipeId_t PipeId, CFE_ES_ResourceID_t App
}/* end CFE_SB_DeletePipeWithAppId */
+/******************************************************************************
+ * Local callback helper for deleting a pipe from a route
+ */
+void CFE_SB_RemovePipeFromRoute(CFE_SBR_RouteId_t RouteId, void *ArgPtr)
+{
+ CFE_SB_DestinationD_t *destptr;
+ CFE_SB_RemovePipeCallback_t *args;
+
+ args = (CFE_SB_RemovePipeCallback_t *)ArgPtr;
+ destptr = CFE_SB_GetDestPtr(RouteId, args->PipeId);
+
+ if (destptr != NULL)
+ {
+ CFE_SB_RemoveDest(RouteId, destptr);
+ }
+}
/******************************************************************************
** Function: CFE_SB_DeletePipeFull()
@@ -265,17 +288,18 @@ int32 CFE_SB_DeletePipeWithAppId(CFE_SB_PipeId_t PipeId, CFE_ES_ResourceID_t App
*/
int32 CFE_SB_DeletePipeFull(CFE_SB_PipeId_t PipeId,CFE_ES_ResourceID_t AppId)
{
- uint8 PipeTblIdx;
- int32 RtnFromVal,Stat;
- CFE_ES_ResourceID_t Owner;
- uint32 i;
- CFE_ES_ResourceID_t TskId;
- CFE_SB_Msg_t *PipeMsgPtr;
- CFE_SB_DestinationD_t *DestPtr = NULL;
- char FullName[(OS_MAX_API_NAME * 2)];
-
- /* get TaskId of caller for events */
+ uint8 PipeTblIdx;
+ int32 RtnFromVal;
+ int32 Stat;
+ CFE_ES_ResourceID_t Owner;
+ CFE_ES_ResourceID_t TskId;
+ CFE_SB_Msg_t *PipeMsgPtr;
+ char FullName[(OS_MAX_API_NAME * 2)];
+ CFE_SB_RemovePipeCallback_t Args;
+
+ /* get TaskId and name of caller for events */
CFE_ES_GetTaskID(&TskId);
+ CFE_SB_GetAppTskName(TskId, FullName);
/* take semaphore to prevent a task switch during this call */
CFE_SB_LockSharedData(__func__,__LINE__);
@@ -289,7 +313,7 @@ int32 CFE_SB_DeletePipeFull(CFE_SB_PipeId_t PipeId,CFE_ES_ResourceID_t AppId)
CFE_SB_UnlockSharedData(__func__,__LINE__);
CFE_EVS_SendEventWithAppID(CFE_SB_DEL_PIPE_ERR1_EID,CFE_EVS_EventType_ERROR,CFE_SB.AppId,
"Pipe Delete Error:Bad Argument,PipedId %d,Requestor %s,Idx %d,Stat %d",
- (int)PipeId,CFE_SB_GetAppTskName(TskId,FullName),(int)PipeTblIdx,(int)RtnFromVal);
+ (int)PipeId,FullName,(int)PipeTblIdx,(int)RtnFromVal);
return CFE_SB_BAD_ARGUMENT;
}/* end if */
@@ -301,35 +325,14 @@ int32 CFE_SB_DeletePipeFull(CFE_SB_PipeId_t PipeId,CFE_ES_ResourceID_t AppId)
CFE_SB.HKTlmMsg.Payload.CreatePipeErrorCounter++;
CFE_SB_UnlockSharedData(__func__,__LINE__);
CFE_EVS_SendEventWithAppID(CFE_SB_DEL_PIPE_ERR2_EID,CFE_EVS_EventType_ERROR,CFE_SB.AppId,
- "Pipe Delete Error:Caller(%s) is not the owner of pipe %d",
- CFE_SB_GetAppTskName(TskId,FullName),(int)PipeId);
+ "Pipe Delete Error:Caller(%s) is not the owner of pipe %d", FullName, (int)PipeId);
return CFE_SB_BAD_ARGUMENT;
}/* end if */
- /* check destination list of every in-use MsgId, for the given pipeid. */
- /* when found, remove the pipe ID from the destination list via 'unsubscribe' */
- for(i=0;i PipeId == PipeId){
- /* release the semaphore, unsubscribe will need to take it */
- CFE_SB_UnlockSharedData(__func__,__LINE__);
- CFE_SB_UnsubscribeWithAppId(CFE_SB.RoutingTbl[i].MsgId,
- PipeId,AppId);
- CFE_SB_LockSharedData(__func__,__LINE__);
- }/* end if */
-
- DestPtr = DestPtr -> Next;
-
- }/* end while */
-
- }/* end if */
- }/* end for */
+ /* Remove the pipe from all routes */
+ Args.PipeId = PipeId;
+ Args.FullName = FullName;
+ CFE_SBR_ForEachRouteId(CFE_SB_RemovePipeFromRoute, &Args, NULL);
if (CFE_SB.PipeTbl[PipeTblIdx].ToTrashBuff != NULL) {
@@ -339,7 +342,6 @@ int32 CFE_SB_DeletePipeFull(CFE_SB_PipeId_t PipeId,CFE_ES_ResourceID_t AppId)
}/* end if */
-
/* remove any messages that might be on the pipe */
/* this step will free the memory used to store the message */
do{
@@ -728,16 +730,16 @@ int32 CFE_SB_SubscribeFull(CFE_SB_MsgId_t MsgId,
uint16 MsgLim,
uint8 Scope)
{
- CFE_SB_MsgRouteIdx_t RouteIdx;
- CFE_SB_RouteEntry_t* RoutePtr;
+ CFE_SBR_RouteId_t RouteId;
int32 Stat;
- CFE_SB_MsgKey_t MsgKey;
CFE_ES_ResourceID_t TskId;
CFE_ES_ResourceID_t AppId;
uint8 PipeIdx;
- CFE_SB_DestinationD_t *DestBlkPtr = NULL;
+ CFE_SB_DestinationD_t *DestPtr = NULL;
+ uint32 DestCount = 0;
char FullName[(OS_MAX_API_NAME * 2)];
char PipeName[OS_MAX_API_NAME] = {'\0'};
+ uint32 Collisions = 0;
CFE_SB_GetPipeName(PipeName, sizeof(PipeName), PipeId);
@@ -783,48 +785,44 @@ int32 CFE_SB_SubscribeFull(CFE_SB_MsgId_t MsgId,
return CFE_SB_BAD_ARGUMENT;
}/* end if */
- /* Convert the API MsgId into the SB internal representation MsgKey */
- MsgKey = CFE_SB_ConvertMsgIdtoMsgKey(MsgId);
-
- /* check for duplicate subscription */
- if(CFE_SB_DuplicateSubscribeCheck(MsgKey,PipeId)==CFE_SB_DUPLICATE){
- CFE_SB.HKTlmMsg.Payload.DuplicateSubscriptionsCounter++;
- CFE_SB_UnlockSharedData(__func__,__LINE__);
- CFE_EVS_SendEventWithAppID(CFE_SB_DUP_SUBSCRIP_EID,CFE_EVS_EventType_INFORMATION,CFE_SB.AppId,
- "Duplicate Subscription,MsgId 0x%x on %s pipe,app %s",
- (unsigned int)CFE_SB_MsgIdToValue(MsgId),
- PipeName,CFE_SB_GetAppTskName(TskId,FullName));
- return CFE_SUCCESS;
- }/* end if */
-
- /*
- ** If there has been a subscription for this message id earlier,
- ** get the element number in the routing table.
- */
- RouteIdx = CFE_SB_GetRoutingTblIdx(MsgKey);
-
- /* if not first subscription for this message KEY ... */
- if(CFE_SB_IsValidRouteIdx(RouteIdx))
+ RouteId = CFE_SBR_GetRouteId(MsgId);
+ if (CFE_SBR_IsValidRouteId(RouteId))
{
- RoutePtr = CFE_SB_GetRoutePtrFromIdx(RouteIdx);
+ /* check for duplicate subscription */
+ if(CFE_SB_GetDestPtr(RouteId, PipeId) != NULL)
+ {
+ CFE_SB.HKTlmMsg.Payload.DuplicateSubscriptionsCounter++;
+ CFE_SB_UnlockSharedData(__func__,__LINE__);
+ CFE_EVS_SendEventWithAppID(CFE_SB_DUP_SUBSCRIP_EID,CFE_EVS_EventType_INFORMATION,CFE_SB.AppId,
+ "Duplicate Subscription,MsgId 0x%x on %s pipe,app %s",
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId),
+ PipeName,CFE_SB_GetAppTskName(TskId,FullName));
+ return CFE_SUCCESS;
+ }
- /*
- * FIXME: If a hash or other conversion is used between MsgId and MsgKey,
- * then it is possible that this existing route is for a different MsgId.
- *
- * The MsgId should be checked against the "MsgId" in the route here.
- *
- * However it is not possible to have a mismatch in the default case where
- * MsgKey == MsgId
- */
+ /* Check for destination limit */
+ for (DestPtr = CFE_SBR_GetDestListHeadPtr(RouteId); DestPtr != NULL; DestPtr = DestPtr->Next)
+ {
+ DestCount++;
+ }
+ if(DestCount >= CFE_PLATFORM_SB_MAX_DEST_PER_PKT){
+ CFE_SB_UnlockSharedData(__func__,__LINE__);
+ CFE_EVS_SendEventWithAppID(CFE_SB_MAX_DESTS_MET_EID,CFE_EVS_EventType_ERROR,CFE_SB.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));
+
+ return CFE_SB_MAX_DESTS_MET;
+ }
}
else
{
- /* Get the index to the first available element in the routing table */
- RouteIdx = CFE_SB_RouteIdxPop_Unsync();
+ /* Add the route */
+ RouteId = CFE_SBR_AddRoute(MsgId, &Collisions);
/* if all routing table elements are used, send event */
- if(!CFE_SB_IsValidRouteIdx(RouteIdx)){
+ if(!CFE_SBR_IsValidRouteId(RouteId)){
CFE_SB_UnlockSharedData(__func__,__LINE__);
CFE_EVS_SendEventWithAppID(CFE_SB_MAX_MSGS_MET_EID,CFE_EVS_EventType_ERROR,CFE_SB.AppId,
"Subscribe Err:Max Msgs(%d)In Use,MsgId 0x%x,pipe %s,app %s",
@@ -841,28 +839,10 @@ int32 CFE_SB_SubscribeFull(CFE_SB_MsgId_t MsgId,
CFE_SB.StatTlmMsg.Payload.PeakMsgIdsInUse = CFE_SB.StatTlmMsg.Payload.MsgIdsInUse;
}/* end if */
- /* populate the look up table with the routing table index */
- CFE_SB_SetRoutingTblIdx(MsgKey,RouteIdx);
-
- /* label the new routing block with the message identifier */
- RoutePtr = CFE_SB_GetRoutePtrFromIdx(RouteIdx);
- RoutePtr->MsgId = MsgId;
-
}/* end if */
- if(RoutePtr->Destinations >= CFE_PLATFORM_SB_MAX_DEST_PER_PKT){
- CFE_SB_UnlockSharedData(__func__,__LINE__);
- CFE_EVS_SendEventWithAppID(CFE_SB_MAX_DESTS_MET_EID,CFE_EVS_EventType_ERROR,CFE_SB.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));
-
- return CFE_SB_MAX_DESTS_MET;
- }/* end if */
-
- DestBlkPtr = CFE_SB_GetDestinationBlk();
- if(DestBlkPtr == NULL){
+ DestPtr = CFE_SB_GetDestinationBlk();
+ if(DestPtr == NULL){
CFE_SB_UnlockSharedData(__func__,__LINE__);
CFE_EVS_SendEventWithAppID(CFE_SB_DEST_BLK_ERR_EID,CFE_EVS_EventType_ERROR,CFE_SB.AppId,
"Subscribe Err:Request for Destination Blk failed for Msg 0x%x",
@@ -871,19 +851,17 @@ int32 CFE_SB_SubscribeFull(CFE_SB_MsgId_t MsgId,
}/* end if */
/* initialize destination block */
- DestBlkPtr -> PipeId = PipeId;
- DestBlkPtr -> MsgId2PipeLim = (uint16)MsgLim;
- DestBlkPtr -> Active = CFE_SB_ACTIVE;
- DestBlkPtr -> BuffCount = 0;
- DestBlkPtr -> DestCnt = 0;
- DestBlkPtr -> Scope = Scope;
- DestBlkPtr -> Prev = NULL;
- DestBlkPtr -> Next = NULL;
-
- /* add destination block to head of list */
- CFE_SB_AddDest(RoutePtr, DestBlkPtr);
-
- RoutePtr->Destinations++;
+ DestPtr->PipeId = PipeId;
+ DestPtr->MsgId2PipeLim = (uint16)MsgLim;
+ DestPtr->Active = CFE_SB_ACTIVE;
+ DestPtr->BuffCount = 0;
+ DestPtr->DestCnt = 0;
+ DestPtr->Scope = Scope;
+ DestPtr->Prev = NULL;
+ DestPtr->Next = NULL;
+
+ /* add destination node */
+ CFE_SB_AddDestNode(RouteId, DestPtr);
CFE_SB.StatTlmMsg.Payload.SubscriptionsInUse++;
if(CFE_SB.StatTlmMsg.Payload.SubscriptionsInUse > CFE_SB.StatTlmMsg.Payload.PeakSubscriptionsInUse)
@@ -914,6 +892,13 @@ int32 CFE_SB_SubscribeFull(CFE_SB_MsgId_t MsgId,
(unsigned int)CFE_SB_MsgIdToValue(MsgId),
PipeName,(int)PipeId,CFE_SB_GetAppTskName(TskId,FullName));
+ if (Collisions != 0)
+ {
+ CFE_EVS_SendEventWithAppID(CFE_SB_HASHCOLLISION_EID, CFE_EVS_EventType_DEBUG, CFE_SB.AppId,
+ "Msg hash collision: MsgId = 0x%x, collisions = %u",
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId), Collisions);
+ }
+
return CFE_SUCCESS;
}/* end CFE_SB_SubscribeFull */
@@ -1021,13 +1006,12 @@ int32 CFE_SB_UnsubscribeWithAppId(CFE_SB_MsgId_t MsgId,
int32 CFE_SB_UnsubscribeFull(CFE_SB_MsgId_t MsgId,CFE_SB_PipeId_t PipeId,
uint8 Scope,CFE_ES_ResourceID_t AppId)
{
- CFE_SB_MsgKey_t MsgKey;
- CFE_SB_MsgRouteIdx_t RouteIdx;
- CFE_SB_RouteEntry_t* RoutePtr;
+ CFE_SBR_RouteId_t RouteId;
uint32 PipeIdx;
CFE_ES_ResourceID_t TskId;
CFE_SB_DestinationD_t *DestPtr = NULL;
char FullName[(OS_MAX_API_NAME * 2)];
+ char PipeName[OS_MAX_API_NAME] = {'\0'};
/* get TaskId of caller for events */
CFE_ES_GetTaskID(&TskId);
@@ -1070,15 +1054,12 @@ int32 CFE_SB_UnsubscribeFull(CFE_SB_MsgId_t MsgId,CFE_SB_PipeId_t PipeId,
return CFE_SB_BAD_ARGUMENT;
}/* end if */
- /* get index into routing table */
- MsgKey = CFE_SB_ConvertMsgIdtoMsgKey(MsgId);
- RouteIdx = CFE_SB_GetRoutingTblIdx(MsgKey);
+ /* get routing id */
+ RouteId = CFE_SBR_GetRouteId(MsgId);
/* if there have never been subscriptions for this message id... */
- if(!CFE_SB_IsValidRouteIdx(RouteIdx))
+ if(!CFE_SBR_IsValidRouteId(RouteId))
{
- char PipeName[OS_MAX_API_NAME] = {'\0'};
-
CFE_SB_UnlockSharedData(__func__,__LINE__);
CFE_SB_GetPipeName(PipeName, sizeof(PipeName), PipeId);
@@ -1090,22 +1071,13 @@ int32 CFE_SB_UnsubscribeFull(CFE_SB_MsgId_t MsgId,CFE_SB_PipeId_t PipeId,
return CFE_SUCCESS;
}/* end if */
- RoutePtr = CFE_SB_GetRoutePtrFromIdx(RouteIdx);
+ /* Get the destination pointer */
+ DestPtr = CFE_SB_GetDestPtr(RouteId, PipeId);
- /* search the list for a matching pipe id */
- for (DestPtr = RoutePtr->ListHeadPtr; DestPtr != NULL && DestPtr->PipeId != PipeId; DestPtr = DestPtr->Next)
- ;
-
- if(DestPtr)
+ if(DestPtr != NULL)
{
- /* match found, remove node from list */
- CFE_SB_RemoveDest(RoutePtr,DestPtr);
-
- /* return node to memory pool */
- CFE_SB_PutDestinationBlk(DestPtr);
-
- RoutePtr->Destinations--;
- CFE_SB.StatTlmMsg.Payload.SubscriptionsInUse--;
+ /* match found, remove destination */
+ CFE_SB_RemoveDest(RouteId,DestPtr);
CFE_EVS_SendEventWithAppID(CFE_SB_SUBSCRIPTION_REMOVED_EID,CFE_EVS_EventType_DEBUG,CFE_SB.AppId,
"Subscription Removed:Msg 0x%x on pipe %d,app %s",
@@ -1114,8 +1086,6 @@ int32 CFE_SB_UnsubscribeFull(CFE_SB_MsgId_t MsgId,CFE_SB_PipeId_t PipeId,
}
else
{
- char PipeName[OS_MAX_API_NAME] = {'\0'};
-
CFE_SB_GetPipeName(PipeName, sizeof(PipeName), PipeId);
CFE_EVS_SendEventWithAppID(CFE_SB_UNSUB_NO_SUBS_EID,CFE_EVS_EventType_INFORMATION,CFE_SB.AppId,
@@ -1188,21 +1158,20 @@ int32 CFE_SB_SendMsgFull(CFE_SB_Msg_t *MsgPtr,
uint32 TlmCntIncrements,
uint32 CopyMode)
{
- CFE_SB_MsgKey_t MsgKey;
CFE_SB_MsgId_t MsgId;
int32 Status;
CFE_SB_DestinationD_t *DestPtr = NULL;
CFE_SB_PipeD_t *PipeDscPtr;
- CFE_SB_RouteEntry_t *RtgTblPtr;
+ CFE_SBR_RouteId_t RouteId;
CFE_SB_BufferD_t *BufDscPtr;
uint16 TotalMsgSize;
- CFE_SB_MsgRouteIdx_t RtgTblIdx;
CFE_ES_ResourceID_t AppId;
CFE_ES_ResourceID_t TskId;
uint32 i;
char FullName[(OS_MAX_API_NAME * 2)];
CFE_SB_EventBuf_t SBSndErr;
char PipeName[OS_MAX_API_NAME] = {'\0'};
+ CFE_SB_PipeDepthStats_t *StatObj;
SBSndErr.EvtsToSnd = 0;
@@ -1262,16 +1231,15 @@ int32 CFE_SB_SendMsgFull(CFE_SB_Msg_t *MsgPtr,
return CFE_SB_MSG_TOO_BIG;
}/* end if */
- MsgKey = CFE_SB_ConvertMsgIdtoMsgKey(MsgId);
-
/* take semaphore to prevent a task switch during this call */
CFE_SB_LockSharedData(__func__,__LINE__);
- RtgTblIdx = CFE_SB_GetRoutingTblIdx(MsgKey);
+ /* Get the routing pointer */
+ RouteId = CFE_SBR_GetRouteId(MsgId);
/* if there have been no subscriptions for this pkt, */
/* increment the dropped pkt cnt, send event and return success */
- if(!CFE_SB_IsValidRouteIdx(RtgTblIdx)){
+ if(!CFE_SBR_IsValidRouteId(RouteId)){
CFE_SB.HKTlmMsg.Payload.NoSubscribersCounter++;
@@ -1329,30 +1297,16 @@ int32 CFE_SB_SendMsgFull(CFE_SB_Msg_t *MsgPtr,
memcpy( BufDscPtr->Buffer, MsgPtr, (uint16)TotalMsgSize );
}
- /* Obtain the actual routing table entry from the selected index */
- RtgTblPtr = CFE_SB_GetRoutePtrFromIdx(RtgTblIdx);
-
/* For Tlm packets, increment the seq count if requested */
if((CFE_SB_GetPktType(MsgId)==CFE_SB_PKTTYPE_TLM) &&
(TlmCntIncrements==CFE_SB_INCREMENT_TLM)){
- RtgTblPtr->SeqCnt++;
- CFE_SB_SetMsgSeqCnt((CFE_SB_Msg_t *)BufDscPtr->Buffer,
- RtgTblPtr->SeqCnt);
+ CFE_SBR_IncrementSequenceCounter(RouteId);
+ CFE_SB_SetMsgSeqCnt((CFE_SB_Msg_t *)BufDscPtr->Buffer, CFE_SBR_GetSequenceCounter(RouteId));
}/* end if */
- /* At this point there must be at least one destination for pkt */
-
/* Send the packet to all destinations */
- for (i=0, DestPtr = RtgTblPtr -> ListHeadPtr;
- i < RtgTblPtr -> Destinations; i++, DestPtr = DestPtr -> Next)
+ for(DestPtr = CFE_SBR_GetDestListHeadPtr(RouteId); DestPtr != NULL; DestPtr = DestPtr->Next)
{
- /* The DestPtr should never be NULL in this loop, this is just extra
- protection in case of the unforseen */
- if(DestPtr == NULL)
- {
- break;
- }
-
if (DestPtr->Active == CFE_SB_INACTIVE) /* destination is active */
{
continue;
@@ -1383,42 +1337,41 @@ int32 CFE_SB_SendMsgFull(CFE_SB_Msg_t *MsgPtr,
** Write the buffer descriptor to the queue of the pipe. If the write
** failed, log info and increment the pipe's error counter.
*/
- Status = OS_QueuePut(PipeDscPtr->SysQueueId,(void *)&BufDscPtr,
- sizeof(CFE_SB_BufferD_t *),0);
+ Status = OS_QueuePut(PipeDscPtr->SysQueueId, (void *)&BufDscPtr, sizeof(CFE_SB_BufferD_t *), 0);
- if (Status == OS_SUCCESS) {
+ if (Status == OS_SUCCESS)
+ {
BufDscPtr->UseCount++; /* used for releasing buffer */
DestPtr->BuffCount++; /* used for checking MsgId2PipeLimit */
DestPtr->DestCnt++; /* used for statistics */
if (DestPtr->PipeId < CFE_SB_TLM_PIPEDEPTHSTATS_SIZE)
{
- CFE_SB_PipeDepthStats_t *StatObj =
- &CFE_SB.StatTlmMsg.Payload.PipeDepthStats[DestPtr->PipeId];
+ StatObj = &CFE_SB.StatTlmMsg.Payload.PipeDepthStats[DestPtr->PipeId];
StatObj->InUse++;
- if(StatObj->InUse > StatObj->PeakInUse){
+ if(StatObj->InUse > StatObj->PeakInUse)
+ {
StatObj->PeakInUse = StatObj->InUse;
}/* end if */
}
-
- }else if(Status == OS_QUEUE_FULL) {
-
+ }
+ else if(Status == OS_QUEUE_FULL)
+ {
SBSndErr.EvtBuf[SBSndErr.EvtsToSnd].PipeId = DestPtr->PipeId;
SBSndErr.EvtBuf[SBSndErr.EvtsToSnd].EventId = CFE_SB_Q_FULL_ERR_EID;
SBSndErr.EvtsToSnd++;
CFE_SB.HKTlmMsg.Payload.PipeOverflowErrorCounter++;
PipeDscPtr->SendErrors++;
-
-
- }else{ /* Unexpected error while writing to queue. */
-
+ }
+ else
+ {
+ /* Unexpected error while writing to queue. */
SBSndErr.EvtBuf[SBSndErr.EvtsToSnd].PipeId = DestPtr->PipeId;
SBSndErr.EvtBuf[SBSndErr.EvtsToSnd].EventId = CFE_SB_Q_WR_ERR_EID;
SBSndErr.EvtBuf[SBSndErr.EvtsToSnd].ErrStat = Status;
SBSndErr.EvtsToSnd++;
CFE_SB.HKTlmMsg.Payload.InternalErrorCounter++;
PipeDscPtr->SendErrors++;
-
- }/*end if */
+ }/*end if */
} /* end loop over destinations */
@@ -1434,7 +1387,6 @@ int32 CFE_SB_SendMsgFull(CFE_SB_Msg_t *MsgPtr,
/* 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++)
{
@@ -1451,7 +1403,7 @@ int32 CFE_SB_SendMsgFull(CFE_SB_Msg_t *MsgPtr,
CFE_EVS_SendEventWithAppID(CFE_SB_MSGID_LIM_ERR_EID,CFE_EVS_EventType_ERROR,CFE_SB.AppId,
"Msg Limit Err,MsgId 0x%x,pipe %s,sender %s",
- (unsigned int)CFE_SB_MsgIdToValue(RtgTblPtr->MsgId),
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId),
PipeName, CFE_SB_GetAppTskName(TskId,FullName));
/* clear the bit so the task may send this event again */
@@ -1470,7 +1422,7 @@ int32 CFE_SB_SendMsgFull(CFE_SB_Msg_t *MsgPtr,
CFE_EVS_SendEventWithAppID(CFE_SB_Q_FULL_ERR_EID,CFE_EVS_EventType_ERROR,CFE_SB.AppId,
"Pipe Overflow,MsgId 0x%x,pipe %s,sender %s",
- (unsigned int)CFE_SB_MsgIdToValue(RtgTblPtr->MsgId),
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId),
PipeName, CFE_SB_GetAppTskName(TskId,FullName));
/* clear the bit so the task may send this event again */
@@ -1486,7 +1438,7 @@ int32 CFE_SB_SendMsgFull(CFE_SB_Msg_t *MsgPtr,
CFE_EVS_SendEventWithAppID(CFE_SB_Q_WR_ERR_EID,CFE_EVS_EventType_ERROR,CFE_SB.AppId,
"Pipe Write Err,MsgId 0x%x,pipe %s,sender %s,stat 0x%x",
- (unsigned int)CFE_SB_MsgIdToValue(RtgTblPtr->MsgId),
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId),
PipeName, CFE_SB_GetAppTskName(TskId,FullName),
(unsigned int)SBSndErr.EvtBuf[i].ErrStat);
@@ -1497,7 +1449,6 @@ int32 CFE_SB_SendMsgFull(CFE_SB_Msg_t *MsgPtr,
}/* end if */
}
-
return CFE_SUCCESS;
}/* end CFE_SB_SendMsgFull */
@@ -1515,6 +1466,7 @@ int32 CFE_SB_RcvMsg(CFE_SB_MsgPtr_t *BufPtr,
CFE_SB_BufferD_t *Message;
CFE_SB_PipeD_t *PipeDscPtr;
CFE_SB_DestinationD_t *DestPtr = NULL;
+ CFE_SBR_RouteId_t RouteId;
CFE_ES_ResourceID_t TskId;
char FullName[(OS_MAX_API_NAME * 2)];
@@ -1586,7 +1538,8 @@ int32 CFE_SB_RcvMsg(CFE_SB_MsgPtr_t *BufPtr,
*BufPtr = (CFE_SB_MsgPtr_t) Message->Buffer;
/* get pointer to destination to be used in decrementing msg limit cnt*/
- DestPtr = CFE_SB_GetDestPtr(CFE_SB_ConvertMsgIdtoMsgKey(PipeDscPtr->CurrentBuff->MsgId), PipeDscPtr->PipeId);
+ RouteId = CFE_SBR_GetRouteId(PipeDscPtr->CurrentBuff->MsgId);
+ DestPtr = CFE_SB_GetDestPtr(RouteId, PipeDscPtr->PipeId);
/*
** DestPtr would be NULL if the msg is unsubscribed to while it is on
@@ -1604,7 +1557,7 @@ int32 CFE_SB_RcvMsg(CFE_SB_MsgPtr_t *BufPtr,
if (PipeDscPtr->PipeId < CFE_SB_TLM_PIPEDEPTHSTATS_SIZE)
{
- CFE_SB.StatTlmMsg.Payload.PipeDepthStats[PipeDscPtr->PipeId].InUse--;
+ CFE_SB.StatTlmMsg.Payload.PipeDepthStats[PipeDscPtr->PipeId].InUse--;
}
}else{
diff --git a/fsw/cfe-core/src/sb/cfe_sb_init.c b/fsw/cfe-core/src/sb/cfe_sb_init.c
index 3a831269a..5095e1f95 100644
--- a/fsw/cfe-core/src/sb/cfe_sb_init.c
+++ b/fsw/cfe-core/src/sb/cfe_sb_init.c
@@ -112,15 +112,9 @@ int32 CFE_SB_EarlyInit (void) {
/* Initialize the pipe table. */
CFE_SB_InitPipeTbl();
- /* Initialize the routing index look up table */
- CFE_SB_InitMsgMap();
+ /* Initialize the routing module */
+ CFE_SBR_Init();
- /* Initialize the routing table. */
- CFE_SB_InitRoutingTbl();
-
- /* Initialize the APID to routing index map table */
- CFE_SB_InitIdxStack();
-
/* Initialize the SB Statistics Pkt */
CFE_SB_InitMsg(&CFE_SB.StatTlmMsg,
CFE_SB_ValueToMsgId(CFE_SB_STATS_TLM_MID),
@@ -198,63 +192,4 @@ void CFE_SB_InitPipeTbl(void){
}/* end CFE_SB_InitPipeTbl */
-
-
-/******************************************************************************
-** Function: CFE_SB_InitMsgMap()
-**
-** Purpose:
-** Initialize the Software Bus Message Map.
-**
-** Arguments:
-**
-** Notes:
-** This function MUST be called before any SB API's are called.
-**
-** Return:
-** none
-*/
-void CFE_SB_InitMsgMap(void){
-
- CFE_SB_MsgKey_Atom_t KeyVal;
-
- for (KeyVal=0; KeyVal < CFE_SB_MAX_NUMBER_OF_MSG_KEYS; KeyVal++)
- {
- CFE_SB.MsgMap[KeyVal] = CFE_SB_INVALID_ROUTE_IDX;
- }
-
-}/* end CFE_SB_InitMsgMap */
-
-
-
-/******************************************************************************
-** Function: CFE_SB_InitRoutingTbl()
-**
-** Purpose:
-** Initialize the Software Bus Routing Table.
-**
-** Arguments:
-**
-** Notes:
-** This function MUST be called before any SB API's are called.
-**
-** Return:
-** none
-*/
-void CFE_SB_InitRoutingTbl(void){
-
- uint32 i;
-
- /* Initialize routing table */
- for(i=0;i
-/******************************************************************************
-** Function: CFE_SB_InitIdxStack()
-**
-** Purpose: Initialize a push/pop stack of routing table indexes.
-** On init each must be unique. After system initialization SB_Idx_top
-** will always point/index to the next available routing table index
-**
-** Arguments:
-**
-** Return:
-** None
-*/
-
-void CFE_SB_InitIdxStack(void)
-{
- uint16 i;
-
- CFE_SB.RouteIdxTop = 0;
- for (i=0; i= CFE_PLATFORM_SB_MAX_MSG_IDS) {
- retValue = CFE_SB_INVALID_ROUTE_IDX; /* no more Idx remaining, all used */
- } else {
- retValue = CFE_SB.RouteIdxStack[CFE_SB.RouteIdxTop];
- ++CFE_SB.RouteIdxTop;
- }
-
- return (retValue);
-} /* end CFE_SB_IdxPop_Unsync */
-
-
-/******************************************************************************
-** Function: CFE_SB_RouteIdxPush_Unsync()
-**
-** Purpose:
-** SB internal function to return a Routing Table element to the available stack
-** (CFE_SB_RouteEntry_t). Typically called when an application un-subscribes
-** to a message. 0 is a valid idx.
-**
-** Assumptions, External Events, and Notes:
-** Calls to this function assumed to be protected by a semaphore
-**
-** Arguments:
-** None
-**
-** Return:
-** None
-*/
-void CFE_SB_RouteIdxPush_Unsync (CFE_SB_MsgRouteIdx_t idx) {
-
- /* This stack grows from 0 to (CFE_PLATFORM_SB_MAX_MSG_IDS - 1) */
- if (CFE_SB.RouteIdxTop > 0) {
- --CFE_SB.RouteIdxTop;
- CFE_SB.RouteIdxStack[CFE_SB.RouteIdxTop] = idx;
- }
-} /* end CFE_SB_IdxPush_Unsync */
/******************************************************************************
** Function: CFE_SB_GetPipeIdx()
@@ -363,176 +280,27 @@ CFE_SB_PipeD_t *CFE_SB_GetPipePtr(CFE_SB_PipeId_t PipeId) {
}/* end CFE_SB_GetPipePtr */
-
-
-/******************************************************************************
-** Function: CFE_SB_GetDestPtr()
-**
-** Purpose:
-** SB internal function to get a pointer to the destination descriptor
-** associated with the given message id/pipe id combination.
-**
-** Arguments:
-** MsgId : ID of the message
-** PipeId : Pipe ID for the destination.
-**
-** Return:
-** Pointer to the destination descriptor that corresponds to the msg/pipe
-** combination. If the destination does not exist, return NULL.
-*/
-CFE_SB_DestinationD_t *CFE_SB_GetDestPtr(CFE_SB_MsgKey_t MsgKey,
- CFE_SB_PipeId_t PipeId){
-
- CFE_SB_MsgRouteIdx_t Idx;
- CFE_SB_DestinationD_t *DestPtr;
-
- Idx = CFE_SB_GetRoutingTblIdx(MsgKey);
-
- if(!CFE_SB_IsValidRouteIdx(Idx))
- {
- return NULL;
- }/* end if */
-
- DestPtr = CFE_SB_GetRoutePtrFromIdx(Idx)->ListHeadPtr;
-
- while(DestPtr != NULL){
-
- if(DestPtr -> PipeId == PipeId){
- return DestPtr;
- }/* end if */
-
- DestPtr = DestPtr->Next;
-
- }/* end while */
-
- return NULL;
-
-}/* end CFE_SB_GetDestPtr */
-
-
-
/******************************************************************************
-** Function: CFE_SB_GetRoutingTblIdx()
-**
-** Purpose:
-** SB internal function to get the index of the routing table element
-** associated with the given message id.
-**
-** Assumptions:
-** Calls to this are predicated by a call to CFE_SB_IsValidMsgKey
-** which already check the MsgKey argument
-**
-** Arguments:
-** MsgKey : ID of the message
-** PipeId : Pipe ID for the destination.
-**
-** Return:
-** Will return the index of the routing table element for the given message ID
-*/
-CFE_SB_MsgRouteIdx_t CFE_SB_GetRoutingTblIdx(CFE_SB_MsgKey_t MsgKey){
-
- return CFE_SB.MsgMap[CFE_SB_MsgKeyToValue(MsgKey)];
-
-}/* end CFE_SB_GetRoutingTblIdx */
-
-
-
-/******************************************************************************
-** Function: CFE_SB_SetRoutingTblIdx()
-**
-** Purpose:
-** SB internal function to set a value in the message map. The "Value" is
-** the routing table index of the given message ID. The message map is used
-** for quick routing table index lookups of a given message ID. The cost of
-** this quick lookup is 8K bytes of memory(for CCSDS).
-**
-** Assumptions:
-** Calls to this are predicated by a call to CFE_SB_IsValidMsgKey
-** which already check the MsgKey argument
-**
-** Arguments:
-** MsgKey : ID of the message
-** Value : value to set.
-**
-** Return:
-**
-*/
-void CFE_SB_SetRoutingTblIdx(CFE_SB_MsgKey_t MsgKey, CFE_SB_MsgRouteIdx_t Value){
-
- CFE_SB.MsgMap[CFE_SB_MsgKeyToValue(MsgKey)] = Value;
-
-}/* end CFE_SB_SetRoutingTblIdx */
-
-
-/******************************************************************************
-** Function: CFE_SB_GetRoutePtrFromIdx()
-**
-** Purpose:
-** SB internal function to obtain a pointer to a routing table entry
-** based on a CFE_SB_MsgRouteIdx_t value.
-**
-** Assumptions:
-** Calls to this are predicated by a call to CFE_SB_IsValidRouteIdx
-** which already check the RouteIdx argument
-**
-** Arguments:
-** RouteIdx : ID of the route to get
-**
-** Return:
-** Pointer to route entry
-**
-*/
-CFE_SB_RouteEntry_t* CFE_SB_GetRoutePtrFromIdx(CFE_SB_MsgRouteIdx_t RouteIdx)
+ * SB private function to get destination pointer - see description in header
+ */
+CFE_SB_DestinationD_t *CFE_SB_GetDestPtr(CFE_SBR_RouteId_t RouteId, CFE_SB_PipeId_t PipeId)
{
- return &CFE_SB.RoutingTbl[CFE_SB_RouteIdxToValue(RouteIdx)];
-} /* end CFE_SB_GetRouteFromIdx */
+ CFE_SB_DestinationD_t *destptr;
-/******************************************************************************
-** Function: CFE_SB_DuplicateSubscribeCheck()
-**
-** Purpose:
-** SB internal function to check for a duplicate subscription.
-**
-** Arguments:
-** MsgId : ID of the message
-** PipeId : ID of the pipe
-**
-** Return:
-** Will return CFE_SB_DUPLICATE if the given MsgId/PipeId subscription
-** exists in SB routing tables, otherwise will return CFE_SB_NO_DUPLICATE.
-*/
-int32 CFE_SB_DuplicateSubscribeCheck(CFE_SB_MsgKey_t MsgKey,
- CFE_SB_PipeId_t PipeId){
+ destptr = CFE_SBR_GetDestListHeadPtr(RouteId);
- CFE_SB_MsgRouteIdx_t Idx;
- CFE_SB_DestinationD_t *DestPtr;
-
- Idx = CFE_SB_GetRoutingTblIdx(MsgKey);
-
- if(!CFE_SB_IsValidRouteIdx(Idx))
+ /* Check all destinations */
+ while(destptr != NULL)
{
- DestPtr = NULL;
+ if(destptr->PipeId == PipeId)
+ {
+ break;
+ }
+ destptr = destptr->Next;
}
- else
- {
- DestPtr = CFE_SB_GetRoutePtrFromIdx(Idx)->ListHeadPtr;
- }/* end if */
-
- while(DestPtr != NULL){
-
- if(DestPtr -> PipeId == PipeId){
- return CFE_SB_DUPLICATE;
- }/* end if */
-
- DestPtr = DestPtr->Next;
-
- }/* end while */
-
- return CFE_SB_NO_DUPLICATE;
-
-}/* end CFE_SB_DuplicateSubscribeCheck */
-
+ return destptr;
+}
/******************************************************************************
** Function: CFE_SB_SetMsgSeqCnt()
@@ -721,38 +489,26 @@ void CFE_SB_FinishSendEvent(CFE_ES_ResourceID_t TaskId, uint32 Bit){
CFE_CLR(CFE_SB.StopRecurseFlags[Indx],Bit);
}/* end CFE_SB_RequestToSendEvent */
-
-
/******************************************************************************
-** Function: CFE_SB_AddDest()
-**
-** Purpose:
-** This function will add the given node to the head of the list.
-**
-** Arguments:
-** RtgTblIdx - Routing table index
-** Dest - Pointer to the destination block to add to the list
-**
-** Return:
-**
-*/
-int32 CFE_SB_AddDest(CFE_SB_RouteEntry_t *RouteEntry, CFE_SB_DestinationD_t *NewNode){
+ * SB private function to add a destination node - see description in header
+ */
+int32 CFE_SB_AddDestNode(CFE_SBR_RouteId_t RouteId, CFE_SB_DestinationD_t *NewNode){
CFE_SB_DestinationD_t *WBS;/* Will Be Second (WBS) node */
+ CFE_SB_DestinationD_t *listheadptr;
- /* if first node in list */
- if(RouteEntry->ListHeadPtr == NULL){
+ listheadptr = CFE_SBR_GetDestListHeadPtr(RouteId);
+ /* if first node in list */
+ if(listheadptr == NULL)
+ {
/* initialize the new node */
NewNode->Next = NULL;
NewNode->Prev = NULL;
-
- /* insert the new node */
- RouteEntry->ListHeadPtr = NewNode;
-
- }else{
-
- WBS = RouteEntry->ListHeadPtr;
+ }
+ else
+ {
+ WBS = listheadptr;
/* initialize the new node */
NewNode->Next = WBS;
@@ -760,75 +516,63 @@ int32 CFE_SB_AddDest(CFE_SB_RouteEntry_t *RouteEntry, CFE_SB_DestinationD_t *New
/* insert the new node */
WBS -> Prev = NewNode;
- RouteEntry->ListHeadPtr = NewNode;
+ }
- }/* end if */
+ /* Update Head */
+ CFE_SBR_SetDestListHeadPtr(RouteId, NewNode);
return CFE_SUCCESS;
-
-}/* CFE_SB_AddDest */
-
-
+}
/******************************************************************************
-** Function: CFE_SB_RemoveDest()
-**
-** Purpose:
-** This function will remove the given node from the list.
-** This function assumes there is at least one node in the list.
-**
-** Arguments:
-** RtgTblIdx - Routing table index
-** Dest - Pointer to the destination block to remove from the list
-**
-** Return:
-**
-*/
-int32 CFE_SB_RemoveDest(CFE_SB_RouteEntry_t *RouteEntry, CFE_SB_DestinationD_t *NodeToRemove){
+ * SB private function to remove a destination - see description in header
+ */
+void CFE_SB_RemoveDest(CFE_SBR_RouteId_t RouteId, CFE_SB_DestinationD_t *DestPtr)
+{
+ CFE_SB_RemoveDestNode(RouteId, DestPtr);
+ CFE_SB_PutDestinationBlk(DestPtr);
+ CFE_SB.StatTlmMsg.Payload.SubscriptionsInUse--;
+}
+/******************************************************************************
+ * SB private function to remove a destination node - see description in header
+ */
+void CFE_SB_RemoveDestNode(CFE_SBR_RouteId_t RouteId, CFE_SB_DestinationD_t *NodeToRemove)
+{
CFE_SB_DestinationD_t *PrevNode;
CFE_SB_DestinationD_t *NextNode;
- /* if this is the only node in the list */
- if((NodeToRemove->Prev == NULL) && (NodeToRemove->Next == NULL)){
-
- RouteEntry->ListHeadPtr = NULL;
-
- /* if first node in the list and list has more than one */
- }else if(NodeToRemove->Prev == NULL){
-
+ if((NodeToRemove->Prev == NULL) && (NodeToRemove->Next == NULL))
+ {
+ /* Clear destinations if this is the only node in the list */
+ CFE_SBR_SetDestListHeadPtr(RouteId, NULL);
+ }
+ else if(NodeToRemove->Prev == NULL)
+ {
+ /* First in the list, set the next node to list head */
NextNode = NodeToRemove->Next;
-
NextNode -> Prev = NULL;
+ CFE_SBR_SetDestListHeadPtr(RouteId, NextNode);
+ }
+ else if(NodeToRemove->Next == NULL){
- RouteEntry->ListHeadPtr = NextNode;
-
- /* if last node in the list and list has more than one */
- }else if(NodeToRemove->Next == NULL){
-
+ /* Last in the list, remove previous pointer */
PrevNode = NodeToRemove->Prev;
-
PrevNode -> Next = NULL;
-
- /* NodeToRemove has node(s) before and node(s) after */
- }else{
-
+ }
+ else
+ {
+ /* Middle of list, remove */
PrevNode = NodeToRemove->Prev;
NextNode = NodeToRemove->Next;
-
PrevNode -> Next = NextNode;
NextNode -> Prev = PrevNode;
-
- }/* end if */
-
+ }
/* initialize the node before returning it to the heap */
NodeToRemove -> Next = NULL;
NodeToRemove -> Prev = NULL;
-
- return CFE_SUCCESS;
-
-}/* CFE_SB_RemoveDest */
+}
/******************************************************************************
diff --git a/fsw/cfe-core/src/sb/cfe_sb_priv.h b/fsw/cfe-core/src/sb/cfe_sb_priv.h
index f0a3bdcfd..efc015f79 100644
--- a/fsw/cfe-core/src/sb/cfe_sb_priv.h
+++ b/fsw/cfe-core/src/sb/cfe_sb_priv.h
@@ -37,17 +37,17 @@
*/
#include "common_types.h"
#include "private/cfe_private.h"
+#include "private/cfe_sb_destination_typedef.h"
#include "cfe_sb.h"
#include "cfe_sb_msg.h"
#include "cfe_time.h"
#include "cfe_es.h"
+#include "private/cfe_sbr.h"
/*
** Macro Definitions
*/
-#define CFE_SB_INVALID_ROUTE_IDX ((CFE_SB_MsgRouteIdx_t){ .RouteIdx = 0 })
-#define CFE_SB_INVALID_MSG_KEY ((CFE_SB_MsgKey_t){ .KeyIdx = 0 })
#define CFE_SB_UNUSED_QUEUE OS_OBJECT_ID_UNDEFINED
#define CFE_SB_INVALID_PIPE 0xFF
#define CFE_SB_NO_DESTINATION 0xFF
@@ -98,64 +98,10 @@
#define CFE_SB_Q_FULL_ERR_EID_BIT 3
#define CFE_SB_Q_WR_ERR_EID_BIT 4
-/*
- * Using the default configuration where there is a 1:1 mapping between MsgID
- * and message key values, the number of keys is equal to the number of MsgIDs.
- *
- * If using an alternative key function / hash, this may change.
- */
-#define CFE_SB_MAX_NUMBER_OF_MSG_KEYS (1+CFE_PLATFORM_SB_HIGHEST_VALID_MSGID)
/*
** Type Definitions
*/
-
-/******************************************************************************
-** Typedef: CFE_SB_MsgKey_Atom_t
-**
-** Purpose:
-** Defines the an integer type for the numeric key that is used for routing
-** table lookups. This is the "raw value" type and typically should not
-** be used directly, except by internal table lookups.
-**
-*/
-typedef uint32 CFE_SB_MsgKey_Atom_t;
-
-/******************************************************************************
-** Typedef: CFE_SB_MsgKey_t
-**
-** Purpose:
-** This is a "holding structure" for the related integer CFE_SB_MsgKey_Atom_t values.
-** This defines the data type that is stored in other structures and/or passed between
-** software bus functions.
-**
-** It is implemented this way to improve type safety and help ensure that "MsgKey"
-** values are not inadvertently exchanged with MsgId or Routing Index values.
-**
-*/
-typedef struct
-{
- CFE_SB_MsgKey_Atom_t KeyIdx; /**< Holding value, do not use directly */
-} CFE_SB_MsgKey_t;
-
-/******************************************************************************/
-/**
- * @brief An wrapper for holding a routing table index
- *
- * This is intended as a form of "strong typedef" where direct assignments should
- * be restricted. Software bus uses numeric indexes into multiple tables to perform
- * its duties, and it is important that these index values are distinct and separate
- * and not mixed together.
- *
- * Using this holding structure prevents assignment directly into a different index
- * or direct usage as numeric value.
- */
-typedef struct
-{
- CFE_SB_MsgRouteIdx_Atom_t RouteIdx; /**< Holding value, do not use directly in code */
-} CFE_SB_MsgRouteIdx_t;
-
-
/******************************************************************************
** Typedef: CFE_SB_BufferD_t
**
@@ -174,31 +120,6 @@ typedef struct {
void *Buffer;
} CFE_SB_BufferD_t;
-
-/******************************************************************************
-** Typedef: CFE_SB_DestinationD_t
-**
-** Purpose:
-** This structure defines a DESTINATION DESCRIPTOR used to specify
-** each destination pipe for a message.
-**
-** Note: Changing the size of this structure may require the memory pool
-** block sizes to change.
-*/
-
-typedef struct {
- CFE_SB_PipeId_t PipeId;
- uint8 Active;
- uint16 MsgId2PipeLim;
- uint16 BuffCount;
- uint16 DestCnt;
- uint8 Scope;
- uint8 Spare[3];
- void *Prev;
- void *Next;
-} CFE_SB_DestinationD_t;
-
-
/******************************************************************************
** Typedef: CFE_SB_ZeroCopyD_t
**
@@ -218,22 +139,6 @@ typedef struct {
void *Prev;
} CFE_SB_ZeroCopyD_t;
-
-/******************************************************************************
-** Typedef: CFE_SB_RouteEntry_t
-**
-** Purpose:
-** This structure defines an entry in the routing table
-*/
-
-typedef struct {
- CFE_SB_MsgId_t MsgId; /**< Original Message Id when the subscription was created */
- uint16 Destinations;
- uint32 SeqCnt;
- CFE_SB_DestinationD_t *ListHeadPtr;
-} CFE_SB_RouteEntry_t;
-
-
/******************************************************************************
** Typedef: CFE_SB_PipeD_t
**
@@ -257,8 +162,6 @@ typedef struct {
CFE_SB_BufferD_t *ToTrashBuff;
} CFE_SB_PipeD_t;
-
-
/******************************************************************************
** Typedef: CFE_SB_BufParams_t
**
@@ -279,29 +182,24 @@ typedef struct {
** Purpose:
** This structure contains the SB global variables.
*/
-typedef struct {
- osal_id_t SharedDataMutexId;
- uint32 SubscriptionReporting;
- uint32 SenderReporting;
- CFE_ES_ResourceID_t AppId;
- uint32 StopRecurseFlags[OS_MAX_TASKS];
- void *ZeroCopyTail;
- CFE_SB_PipeD_t PipeTbl[CFE_PLATFORM_SB_MAX_PIPES];
- CFE_SB_HousekeepingTlm_t HKTlmMsg;
- CFE_SB_StatsTlm_t StatTlmMsg;
- CFE_SB_PipeId_t CmdPipe;
- CFE_SB_Msg_t *CmdPipePktPtr;
- CFE_SB_MemParams_t Mem;
- CFE_SB_MsgRouteIdx_t MsgMap[CFE_SB_MAX_NUMBER_OF_MSG_KEYS];
- CFE_SB_RouteEntry_t RoutingTbl[CFE_PLATFORM_SB_MAX_MSG_IDS];
- CFE_SB_AllSubscriptionsTlm_t PrevSubMsg;
- CFE_SB_SingleSubscriptionTlm_t SubRprtMsg;
- CFE_EVS_BinFilter_t EventFilters[CFE_SB_MAX_CFG_FILE_EVENTS_TO_FILTER];
-
- uint16 RouteIdxTop;
- CFE_SB_MsgRouteIdx_t RouteIdxStack[CFE_PLATFORM_SB_MAX_MSG_IDS];
-
-}cfe_sb_t;
+typedef struct
+{
+ osal_id_t SharedDataMutexId;
+ uint32 SubscriptionReporting;
+ uint32 SenderReporting;
+ CFE_ES_ResourceID_t AppId;
+ uint32 StopRecurseFlags[OS_MAX_TASKS];
+ void *ZeroCopyTail;
+ CFE_SB_PipeD_t PipeTbl[CFE_PLATFORM_SB_MAX_PIPES];
+ CFE_SB_HousekeepingTlm_t HKTlmMsg;
+ CFE_SB_StatsTlm_t StatTlmMsg;
+ CFE_SB_PipeId_t CmdPipe;
+ CFE_SB_Msg_t *CmdPipePktPtr;
+ CFE_SB_MemParams_t Mem;
+ CFE_SB_AllSubscriptionsTlm_t PrevSubMsg;
+ CFE_SB_SingleSubscriptionTlm_t SubRprtMsg;
+ CFE_EVS_BinFilter_t EventFilters[CFE_SB_MAX_CFG_FILE_EVENTS_TO_FILTER];
+} cfe_sb_t;
/******************************************************************************
@@ -336,13 +234,8 @@ typedef struct{
int32 CFE_SB_AppInit(void);
int32 CFE_SB_InitBuffers(void);
void CFE_SB_InitPipeTbl(void);
-void CFE_SB_InitMsgMap(void);
-void CFE_SB_InitRoutingTbl(void);
void CFE_SB_InitIdxStack(void);
void CFE_SB_ResetCounts(void);
-void CFE_SB_RouteIdxPush_Unsync(CFE_SB_MsgRouteIdx_t idx);
-CFE_SB_MsgRouteIdx_t CFE_SB_RouteIdxPop_Unsync(void);
-CFE_SB_MsgKey_t CFE_SB_ConvertMsgIdtoMsgKey(CFE_SB_MsgId_t MsgId);
void CFE_SB_LockSharedData(const char *FuncName, int32 LineNumber);
void CFE_SB_UnlockSharedData(const char *FuncName, int32 LineNumber);
void CFE_SB_ReleaseBuffer (CFE_SB_BufferD_t *bd, CFE_SB_DestinationD_t *dest);
@@ -350,13 +243,9 @@ int32 CFE_SB_ReadQueue(CFE_SB_PipeD_t *PipeDscPtr,CFE_ES_ResourceID_t TskId,
CFE_SB_TimeOut_t Time_Out,CFE_SB_BufferD_t **Message );
int32 CFE_SB_WriteQueue(CFE_SB_PipeD_t *pd,uint32 TskId,
const CFE_SB_BufferD_t *bd,CFE_SB_MsgId_t MsgId );
-CFE_SB_MsgRouteIdx_t CFE_SB_GetRoutingTblIdx(CFE_SB_MsgKey_t MsgKey);
uint8 CFE_SB_GetPipeIdx(CFE_SB_PipeId_t PipeId);
int32 CFE_SB_ReturnBufferToPool(CFE_SB_BufferD_t *bd);
void CFE_SB_ProcessCmdPipePkt(void);
-int32 CFE_SB_DuplicateSubscribeCheck(CFE_SB_MsgKey_t MsgKey,CFE_SB_PipeId_t PipeId);
-void CFE_SB_SetRoutingTblIdx(CFE_SB_MsgKey_t MsgKey, CFE_SB_MsgRouteIdx_t Value);
-CFE_SB_RouteEntry_t* CFE_SB_GetRoutePtrFromIdx(CFE_SB_MsgRouteIdx_t RouteIdx);
void CFE_SB_ResetCounters(void);
void CFE_SB_SetMsgSeqCnt(CFE_SB_MsgPtr_t MsgPtr,uint32 Count);
char *CFE_SB_GetAppTskName(CFE_ES_ResourceID_t TaskId, char* FullName);
@@ -364,7 +253,6 @@ CFE_SB_BufferD_t *CFE_SB_GetBufferFromPool(CFE_SB_MsgId_t MsgId, uint16 Size);
CFE_SB_BufferD_t *CFE_SB_GetBufferFromCaller(CFE_SB_MsgId_t MsgId, void *Address);
CFE_SB_PipeD_t *CFE_SB_GetPipePtr(CFE_SB_PipeId_t PipeId);
CFE_SB_PipeId_t CFE_SB_GetAvailPipeIdx(void);
-CFE_SB_DestinationD_t *CFE_SB_GetDestPtr (CFE_SB_MsgKey_t MsgKey, CFE_SB_PipeId_t PipeId);
int32 CFE_SB_DeletePipeWithAppId(CFE_SB_PipeId_t PipeId,CFE_ES_ResourceID_t AppId);
int32 CFE_SB_DeletePipeFull(CFE_SB_PipeId_t PipeId,CFE_ES_ResourceID_t AppId);
int32 CFE_SB_SubscribeFull(CFE_SB_MsgId_t MsgId,
@@ -390,14 +278,60 @@ int32 CFE_SB_ValidatePipeId(CFE_SB_PipeId_t PipeId);
void CFE_SB_IncrCmdCtr(int32 status);
void CFE_SB_FileWriteByteCntErr(const char *Filename,uint32 Requested,uint32 Actual);
void CFE_SB_SetSubscriptionReporting(uint32 state);
-uint32 CFE_SB_FindGlobalMsgIdCnt(void);
uint32 CFE_SB_RequestToSendEvent(CFE_ES_ResourceID_t TaskId, uint32 Bit);
void CFE_SB_FinishSendEvent(CFE_ES_ResourceID_t TaskId, uint32 Bit);
CFE_SB_DestinationD_t *CFE_SB_GetDestinationBlk(void);
int32 CFE_SB_PutDestinationBlk(CFE_SB_DestinationD_t *Dest);
-int32 CFE_SB_AddDest(CFE_SB_RouteEntry_t *RouteEntry, CFE_SB_DestinationD_t *NewNode);
-int32 CFE_SB_RemoveDest(CFE_SB_RouteEntry_t *RouteEntry, CFE_SB_DestinationD_t *NodeToRemove);
+/**
+ * \brief Add a destination node
+ *
+ * Private function that will add a destination node to the linked list
+ *
+ * \note Assumes destination pointer is valid
+ *
+ * \param[in] RouteId The route ID to add destination node to
+ * \param[in] DestPtr Pointer to the destination to add
+ */
+int32 CFE_SB_AddDestNode(CFE_SBR_RouteId_t RouteId, CFE_SB_DestinationD_t *NewNode);
+
+/**
+ * \brief Remove a destination node
+ *
+ * Private function that will remove a destination node from the linked list
+ *
+ * \note Assumes destination pointer is valid and in route
+ *
+ * \param[in] RouteId The route ID to remove destination node from
+ * \param[in] DestPtr Pointer to the destination to remove
+ */
+void CFE_SB_RemoveDestNode(CFE_SBR_RouteId_t RouteId, CFE_SB_DestinationD_t *NodeToRemove);
+
+/**
+ * \brief Remove a destination
+ *
+ * Private function that will remove a destination by removing the node,
+ * returning the block, and decrementing counters
+ *
+ * \note Assumes destination pointer is valid and in route
+ *
+ * \param[in] RouteId The route ID to remove destination from
+ * \param[in] DestPtr Pointer to the destination to remove
+ */
+void CFE_SB_RemoveDest(CFE_SBR_RouteId_t RouteId, CFE_SB_DestinationD_t *DestPtr);
+
+/**
+ * \brief Get destination pointer for PipeId from RouteId
+ *
+ * Private function that will return the destination pointer related to the
+ * given PipeId and RouteId if it exists
+ *
+ * \param[in] RouteId The route ID to search
+ * \param[in] PipeId The pipe ID to search for
+ *
+ * \returns Then destination pointer for a match, NULL otherwise
+ */
+CFE_SB_DestinationD_t *CFE_SB_GetDestPtr(CFE_SBR_RouteId_t RouteId, CFE_SB_PipeId_t PipeId);
/*****************************************************************************/
/**
@@ -452,101 +386,5 @@ int32 CFE_SB_SendPrevSubsCmd(const CFE_SB_SendPrevSubs_t *data);
extern cfe_sb_t CFE_SB;
-
-
-/* ---------------------------------------------------------
- * HELPER FUNCTIONS FOR TYPE-SAFE WRAPPERS / HOLDING STRUCTS
- *
- * These functions implement the type conversions between "bare numbers" and
- * the holding structures, as well as sanity tests for the holding structures.
- *
- * The data within the holding structures should never be directly in the app,
- * one of these helpers should be used once it is verified that the conversion
- * or use case is legitimate.
- * --------------------------------------------------------- */
-
-/**
- * @brief Identifies whether a given CFE_SB_MsgKey_t is valid
- *
- * Implements a basic sanity check on the value provided
- *
- * @returns true if sanity checks passed, false otherwise.
- */
-static inline bool CFE_SB_IsValidMsgKey(CFE_SB_MsgKey_t MsgKey)
-{
- return (MsgKey.KeyIdx != 0 && MsgKey.KeyIdx <= CFE_SB_MAX_NUMBER_OF_MSG_KEYS);
-}
-
-/**
- * @brief Identifies whether a given CFE_SB_MsgRouteIdx_t is valid
- *
- * Implements a basic sanity check on the value provided
- *
- * @returns true if sanity checks passed, false otherwise.
- */
-static inline bool CFE_SB_IsValidRouteIdx(CFE_SB_MsgRouteIdx_t RouteIdx)
-{
- return (RouteIdx.RouteIdx != 0 && RouteIdx.RouteIdx <= CFE_PLATFORM_SB_MAX_MSG_IDS);
-}
-
-/**
- * @brief Converts between a CFE_SB_MsgKey_t and a raw value
- *
- * Converts the supplied value into a "bare number" suitable for performing
- * array lookups or other tasks for which the holding structure cannot be used directly.
- *
- * Use with caution, as this removes the type safety information from the value.
- *
- * @note It is assumed the value has already been validated using CFE_SB_IsValidMsgKey()
- *
- * @returns The underlying index value
- */
-static inline CFE_SB_MsgKey_Atom_t CFE_SB_MsgKeyToValue(CFE_SB_MsgKey_t MsgKey)
-{
- return (MsgKey.KeyIdx - 1);
-}
-
-/**
- * @brief Converts between a CFE_SB_MsgKey_t and a raw value
- *
- * Converts the supplied "bare number" into a type-safe CFE_SB_MsgKey_t value
- *
- * @returns A CFE_SB_MsgKey_t value
- */
-static inline CFE_SB_MsgKey_t CFE_SB_ValueToMsgKey(CFE_SB_MsgKey_Atom_t KeyIdx)
-{
- return ((CFE_SB_MsgKey_t){ .KeyIdx = 1 + KeyIdx });
-}
-
-/**
- * @brief Converts between a CFE_SB_MsgRouteIdx_t and a raw value
- *
- * Converts the supplied "bare number" into a type-safe CFE_SB_MsgRouteIdx_t value
- *
- * @returns A CFE_SB_MsgRouteIdx_t value
- */
-static inline CFE_SB_MsgRouteIdx_t CFE_SB_ValueToRouteIdx(CFE_SB_MsgRouteIdx_Atom_t TableIdx)
-{
- return ((CFE_SB_MsgRouteIdx_t){ .RouteIdx = 1 + TableIdx });
-}
-
-/**
- * @brief Converts between a CFE_SB_MsgRouteIdx_t and a raw value
- *
- * Converts the supplied value into a "bare number" suitable for performing
- * array lookups or other tasks for which the holding structure cannot be used directly.
- *
- * Use with caution, as this removes the type safety information from the value.
- *
- * @note It is assumed the value has already been validated using CFE_SB_IsValidRouteIdx()
- *
- * @returns The underlying index value
- */
-static inline CFE_SB_MsgRouteIdx_Atom_t CFE_SB_RouteIdxToValue(CFE_SB_MsgRouteIdx_t RouteIdx)
-{
- return (RouteIdx.RouteIdx - 1);
-}
-
-
#endif /* _cfe_sb_priv_ */
/*****************************************************************************/
diff --git a/fsw/cfe-core/src/sb/cfe_sb_task.c b/fsw/cfe-core/src/sb/cfe_sb_task.c
index 3ead76756..97c587186 100644
--- a/fsw/cfe-core/src/sb/cfe_sb_task.c
+++ b/fsw/cfe-core/src/sb/cfe_sb_task.c
@@ -48,6 +48,15 @@
cfe_sb_t CFE_SB;
CFE_SB_Qos_t CFE_SB_Default_Qos;
+/* Local structure for file writing callbacks */
+typedef struct
+{
+ const char *Filename; /* File name for error reporting */
+ osal_id_t Fd; /* File id for writing */
+ uint32 FileSize; /* File size for reporting */
+ uint32 EntryCount; /* Entry count for reporting */
+ int32 Status; /* File write status */
+} CFE_SB_FileWriteCallback_t;
/******************************************************************************
** Function: CFE_SB_TaskMain()
@@ -638,7 +647,7 @@ int32 CFE_SB_EnableRouteCmd(const CFE_SB_EnableRoute_t *data)
return CFE_SUCCESS;
}/* end if */
- DestPtr = CFE_SB_GetDestPtr(CFE_SB_ConvertMsgIdtoMsgKey(MsgId), PipeId);
+ DestPtr = CFE_SB_GetDestPtr(CFE_SBR_GetRouteId(MsgId), PipeId);
if(DestPtr == NULL){
CFE_EVS_SendEvent(CFE_SB_ENBL_RTE1_EID,CFE_EVS_EventType_ERROR,
"Enbl Route Cmd:Route does not exist.Msg 0x%x,Pipe %d",
@@ -702,7 +711,7 @@ int32 CFE_SB_DisableRouteCmd(const CFE_SB_DisableRoute_t *data)
return CFE_SUCCESS;
}/* end if */
- DestPtr = CFE_SB_GetDestPtr(CFE_SB_ConvertMsgIdtoMsgKey(MsgId), PipeId);
+ DestPtr = CFE_SB_GetDestPtr(CFE_SBR_GetRouteId(MsgId), PipeId);
if(DestPtr == NULL){
CFE_EVS_SendEvent(CFE_SB_DSBL_RTE1_EID,CFE_EVS_EventType_ERROR,
"Disable Route Cmd:Route does not exist,Msg 0x%x,Pipe %d",
@@ -843,6 +852,61 @@ int32 CFE_SB_SendMapInfoCmd(const CFE_SB_SendMapInfo_t *data)
return CFE_SUCCESS;
}/* end CFE_SB_SendMapInfoCmd */
+/******************************************************************************
+ * Local callback helper for writing routing info to a file
+ */
+void CFE_SB_WriteRouteToFile(CFE_SBR_RouteId_t RouteId, void *ArgPtr)
+{
+ CFE_SB_FileWriteCallback_t *args;
+ CFE_SB_DestinationD_t *destptr;
+ CFE_SB_PipeD_t *pipedptr;
+ int32 status;
+ CFE_SB_RoutingFileEntry_t entry;
+
+ /* Cast arguments for local use */
+ args = (CFE_SB_FileWriteCallback_t *)ArgPtr;
+
+ destptr = CFE_SBR_GetDestListHeadPtr(RouteId);
+
+ while((destptr != NULL) && (args->Status != CFE_SB_FILE_IO_ERR))
+ {
+
+ pipedptr = CFE_SB_GetPipePtr(destptr->PipeId);
+
+ /* If invalid id, continue on to next entry */
+ if (pipedptr != NULL)
+ {
+
+ entry.MsgId = CFE_SBR_GetMsgId(RouteId);
+ entry.PipeId = destptr->PipeId;
+ entry.State = destptr->Active;
+ entry.MsgCnt = destptr->DestCnt;
+
+ entry.AppName[0] = 0;
+ /*
+ * NOTE: as long as CFE_ES_GetAppName() returns success, then it
+ * guarantees null termination of the output. Return code is not
+ * checked here (bad) but in case of error it does not seem to touch
+ * the buffer, therefore the initialization above will protect for now
+ */
+ CFE_ES_GetAppName(entry.AppName, pipedptr->AppId, sizeof(entry.AppName));
+ CFE_SB_GetPipeName(entry.PipeName, sizeof(entry.PipeName), entry.PipeId);
+
+ status = OS_write (args->Fd, &entry, sizeof(CFE_SB_RoutingFileEntry_t));
+ if(status != sizeof(CFE_SB_RoutingFileEntry_t))
+ {
+ CFE_SB_FileWriteByteCntErr(args->Filename, sizeof(CFE_SB_RoutingFileEntry_t), status);
+ OS_close(args->Fd);
+ args->Status = CFE_SB_FILE_IO_ERR;
+ }
+
+ args->FileSize += status;
+ args->EntryCount++;
+ }
+
+ destptr = destptr->Next;
+ }
+}
/******************************************************************************
** Function: CFE_SB_SendRoutingInfo()
@@ -858,103 +922,49 @@ int32 CFE_SB_SendMapInfoCmd(const CFE_SB_SendMapInfo_t *data)
*/
int32 CFE_SB_SendRtgInfo(const char *Filename)
{
- CFE_SB_MsgRouteIdx_t RtgTblIdx;
- const CFE_SB_RouteEntry_t* RtgTblPtr;
- CFE_SB_MsgKey_Atom_t MsgKeyVal;
- osal_id_t fd;
+ CFE_SB_FileWriteCallback_t args = {0};
int32 Status;
- uint32 FileSize = 0;
- uint32 EntryCount = 0;
- CFE_SB_RoutingFileEntry_t Entry;
CFE_FS_Header_t FileHdr;
- CFE_SB_PipeD_t *pd;
- CFE_SB_DestinationD_t *DestPtr;
- Status = OS_OpenCreate(&fd, Filename,
- OS_FILE_FLAG_CREATE | OS_FILE_FLAG_TRUNCATE, OS_WRITE_ONLY);
- if(Status < OS_SUCCESS){
- CFE_EVS_SendEvent(CFE_SB_SND_RTG_ERR1_EID,CFE_EVS_EventType_ERROR,
+ Status = OS_OpenCreate(&args.Fd, Filename, OS_FILE_FLAG_CREATE | OS_FILE_FLAG_TRUNCATE, OS_WRITE_ONLY);
+ if(Status < OS_SUCCESS)
+ {
+ CFE_EVS_SendEvent(CFE_SB_SND_RTG_ERR1_EID, CFE_EVS_EventType_ERROR,
"Error creating file %s, stat=0x%x",
- Filename,(unsigned int)Status);
+ Filename, (unsigned int)Status);
return CFE_SB_FILE_IO_ERR;
- }/* end if */
+ }
/* clear out the cfe file header fields, then populate description and subtype */
CFE_FS_InitHeader(&FileHdr, "SB Routing Information", CFE_FS_SubType_SB_ROUTEDATA);
- Status = CFE_FS_WriteHeader(fd, &FileHdr);
- if(Status != sizeof(CFE_FS_Header_t)){
+ Status = CFE_FS_WriteHeader(args.Fd, &FileHdr);
+ if(Status != sizeof(CFE_FS_Header_t))
+ {
CFE_SB_FileWriteByteCntErr(Filename,sizeof(CFE_FS_Header_t),Status);
- OS_close(fd);
+ OS_close(args.Fd);
return CFE_SB_FILE_IO_ERR;
- }/* end if */
-
- FileSize = Status;
-
- /* loop through the entire MsgMap */
- for(MsgKeyVal=0; MsgKeyVal < CFE_SB_MAX_NUMBER_OF_MSG_KEYS; ++MsgKeyVal)
- {
- RtgTblIdx = CFE_SB.MsgMap[MsgKeyVal];
-
- /* Only process table entry if it is used. */
- if(!CFE_SB_IsValidRouteIdx(RtgTblIdx))
- {
- DestPtr = NULL;
- RtgTblPtr = NULL;
- }
- else
- {
- RtgTblPtr = CFE_SB_GetRoutePtrFromIdx(RtgTblIdx);
- DestPtr = RtgTblPtr->ListHeadPtr;
- }
-
- while(DestPtr != NULL){
-
- pd = CFE_SB_GetPipePtr(DestPtr -> PipeId);
- /* If invalid id, continue on to next entry */
- if (pd != NULL) {
-
- Entry.MsgId = RtgTblPtr->MsgId;
- Entry.PipeId = DestPtr -> PipeId;
- Entry.State = DestPtr -> Active;
- Entry.MsgCnt = DestPtr -> DestCnt;
-
- Entry.AppName[0] = 0;
- /*
- * NOTE: as long as CFE_ES_GetAppName() returns success, then it
- * guarantees null termination of the output. Return code is not
- * checked here (bad) but in case of error it does not seem to touch
- * the buffer, therefore the initialization above will protect for now
- */
- CFE_ES_GetAppName(&Entry.AppName[0], pd->AppId, sizeof(Entry.AppName));
- CFE_SB_GetPipeName(Entry.PipeName, sizeof(Entry.PipeName), Entry.PipeId);
-
- Status = OS_write (fd, &Entry, sizeof(CFE_SB_RoutingFileEntry_t));
- if(Status != sizeof(CFE_SB_RoutingFileEntry_t)){
- CFE_SB_FileWriteByteCntErr(Filename,
- sizeof(CFE_SB_RoutingFileEntry_t),
- Status);
- OS_close(fd);
- return CFE_SB_FILE_IO_ERR;
- }/* end if */
-
- FileSize += Status;
- EntryCount ++;
- }
-
- DestPtr = DestPtr->Next;
-
- }/* end while */
-
- }/* end for */
+ }
- OS_close(fd);
+ /* Initialize the reset of the nonzero callback argument elements */
+ args.FileSize = Status;
+ args.Filename = Filename;
- CFE_EVS_SendEvent(CFE_SB_SND_RTG_EID,CFE_EVS_EventType_DEBUG,
- "%s written:Size=%d,Entries=%d",
- Filename,(int)FileSize,(int)EntryCount);
+ /* Write route info to file */
+ CFE_SBR_ForEachRouteId(CFE_SB_WriteRouteToFile, &args, NULL);
- return CFE_SUCCESS;
+ if (args.Status != 0)
+ {
+ return args.Status;
+ }
+ else
+ {
+ OS_close(args.Fd);
+ CFE_EVS_SendEvent(CFE_SB_SND_RTG_EID,CFE_EVS_EventType_DEBUG,
+ "%s written:Size=%d,Entries=%d",
+ Filename, (int)args.FileSize, (int)args.EntryCount);
+ return CFE_SUCCESS;
+ }
}/* end CFE_SB_SendRtgInfo */
@@ -1031,6 +1041,36 @@ int32 CFE_SB_SendPipeInfo(const char *Filename)
}/* end CFE_SB_SendPipeInfo */
+/******************************************************************************
+ * Local callback helper for writing map info to a file
+ */
+void CFE_SB_WriteMapToFile(CFE_SBR_RouteId_t RouteId, void *ArgPtr)
+{
+ CFE_SB_FileWriteCallback_t *args;
+ int32 status;
+ CFE_SB_MsgMapFileEntry_t entry;
+
+ /* Cast arguments for local use */
+ args = (CFE_SB_FileWriteCallback_t *)ArgPtr;
+
+ if(args->Status != CFE_SB_FILE_IO_ERR)
+ {
+ entry.MsgId = CFE_SBR_GetMsgId(RouteId);
+ entry.Index = CFE_SBR_RouteIdToValue(RouteId);
+
+ status = OS_write (args->Fd, &entry, sizeof(CFE_SB_MsgMapFileEntry_t));
+ if(status != sizeof(CFE_SB_MsgMapFileEntry_t))
+ {
+ CFE_SB_FileWriteByteCntErr(args->Filename, sizeof(CFE_SB_MsgMapFileEntry_t), status);
+ OS_close(args->Fd);
+ args->Status = CFE_SB_FILE_IO_ERR;
+ }
+
+ args->FileSize += status;
+ args->EntryCount++;
+ }
+}
+
/******************************************************************************
** Function: CFE_SB_SendMapInfo()
**
@@ -1045,73 +1085,103 @@ int32 CFE_SB_SendPipeInfo(const char *Filename)
*/
int32 CFE_SB_SendMapInfo(const char *Filename)
{
- const CFE_SB_RouteEntry_t* RtgTblPtr;
- CFE_SB_MsgRouteIdx_t RtgTblIdx;
- CFE_SB_MsgKey_Atom_t MsgKeyVal;
- osal_id_t fd;
- int32 Status;
- uint32 FileSize = 0;
- uint32 EntryCount = 0;
- CFE_SB_MsgMapFileEntry_t Entry;
- CFE_FS_Header_t FileHdr;
+ CFE_SB_FileWriteCallback_t args = {0};
+ int32 Status;
+ CFE_FS_Header_t FileHdr;
- Status = OS_OpenCreate(&fd, Filename, OS_FILE_FLAG_CREATE | OS_FILE_FLAG_TRUNCATE, OS_WRITE_ONLY);
+ Status = OS_OpenCreate(&args.Fd, Filename, OS_FILE_FLAG_CREATE | OS_FILE_FLAG_TRUNCATE, OS_WRITE_ONLY);
- if (Status < OS_SUCCESS){
- CFE_EVS_SendEvent(CFE_SB_SND_RTG_ERR1_EID,CFE_EVS_EventType_ERROR,
+ if (Status < OS_SUCCESS)
+ {
+ CFE_EVS_SendEvent(CFE_SB_SND_RTG_ERR1_EID, CFE_EVS_EventType_ERROR,
"Error creating file %s, stat=0x%x",
- Filename,(unsigned int)Status);
+ Filename, (unsigned int)Status);
return CFE_SB_FILE_IO_ERR;
- }/* end if */
+ }
/* clear out the cfe file header fields, then populate description and subtype */
CFE_FS_InitHeader(&FileHdr, "SB Message Map Information", CFE_FS_SubType_SB_MAPDATA);
- Status = CFE_FS_WriteHeader(fd, &FileHdr);
- if(Status != sizeof(CFE_FS_Header_t)){
- CFE_SB_FileWriteByteCntErr(Filename,sizeof(CFE_FS_Header_t),Status);
- OS_close(fd);
- return CFE_SB_FILE_IO_ERR;
- }/* end if */
-
- FileSize = Status;
-
- /* loop through the entire MsgMap */
- for(MsgKeyVal=0; MsgKeyVal < CFE_SB_MAX_NUMBER_OF_MSG_KEYS; ++MsgKeyVal)
+ Status = CFE_FS_WriteHeader(args.Fd, &FileHdr);
+ if(Status != sizeof(CFE_FS_Header_t))
{
- RtgTblIdx = CFE_SB_GetRoutingTblIdx(CFE_SB_ValueToMsgKey(MsgKeyVal));
+ CFE_SB_FileWriteByteCntErr(Filename, sizeof(CFE_FS_Header_t), Status);
+ OS_close(args.Fd);
+ return CFE_SB_FILE_IO_ERR;
+ }
- if(CFE_SB_IsValidRouteIdx(RtgTblIdx))
- {
- RtgTblPtr = CFE_SB_GetRoutePtrFromIdx(RtgTblIdx);
+ /* Initialize the reset of the nonzero callback argument elements */
+ args.FileSize = Status;
+ args.Filename = Filename;
- Entry.MsgId = RtgTblPtr->MsgId;
- Entry.Index = CFE_SB_RouteIdxToValue(RtgTblIdx);
+ /* Write route info to file */
+ CFE_SBR_ForEachRouteId(CFE_SB_WriteMapToFile, &args, NULL);
- Status = OS_write (fd, &Entry, sizeof(CFE_SB_MsgMapFileEntry_t));
- if(Status != sizeof(CFE_SB_MsgMapFileEntry_t)){
- CFE_SB_FileWriteByteCntErr(Filename,sizeof(CFE_SB_MsgMapFileEntry_t),Status);
- OS_close(fd);
- return CFE_SB_FILE_IO_ERR;
- }/* end if */
+ if (args.Status != 0)
+ {
+ return args.Status;
+ }
+ else
+ {
+ OS_close(args.Fd);
+ CFE_EVS_SendEvent(CFE_SB_SND_RTG_EID, CFE_EVS_EventType_DEBUG,
+ "%s written:Size=%d,Entries=%d",
+ Filename, (int)args.FileSize, (int)args.EntryCount);
+ return CFE_SUCCESS;
+ }
+}
- FileSize += Status;
- EntryCount ++;
+/******************************************************************************
+ * Local callback helper for sending route subscriptions
+ */
+void CFE_SB_SendRouteSub(CFE_SBR_RouteId_t RouteId, void *ArgPtr)
+{
+ CFE_SB_DestinationD_t *destptr;
+ int32 status;
- }/* end for */
- }/* end for */
+ destptr = CFE_SBR_GetDestListHeadPtr(RouteId);
- OS_close(fd);
+ /* Loop through destinations */
+ while(destptr != NULL)
+ {
- CFE_EVS_SendEvent(CFE_SB_SND_RTG_EID,CFE_EVS_EventType_DEBUG,
- "%s written:Size=%d,Entries=%d",
- Filename,(int)FileSize,(int)EntryCount);
+ if(destptr->Scope == CFE_SB_GLOBAL)
+ {
- return CFE_SUCCESS;
+ /* ...add entry into pkt */
+ CFE_SB.PrevSubMsg.Payload.Entry[CFE_SB.PrevSubMsg.Payload.Entries].MsgId = CFE_SBR_GetMsgId(RouteId);
+ CFE_SB.PrevSubMsg.Payload.Entry[CFE_SB.PrevSubMsg.Payload.Entries].Qos.Priority = 0;
+ CFE_SB.PrevSubMsg.Payload.Entry[CFE_SB.PrevSubMsg.Payload.Entries].Qos.Reliability = 0;
+ CFE_SB.PrevSubMsg.Payload.Entries++;
+
+ /* send pkt if full */
+ if(CFE_SB.PrevSubMsg.Payload.Entries >= CFE_SB_SUB_ENTRIES_PER_PKT)
+ {
+ CFE_SB_UnlockSharedData(__func__,__LINE__);
+ status = CFE_SB_SendMsg((CFE_SB_Msg_t *)&CFE_SB.PrevSubMsg);
+ CFE_EVS_SendEvent(CFE_SB_FULL_SUB_PKT_EID, CFE_EVS_EventType_DEBUG,
+ "Full Sub Pkt %d Sent,Entries=%d,Stat=0x%x\n",
+ (int)CFE_SB.PrevSubMsg.Payload.PktSegment,
+ (int)CFE_SB.PrevSubMsg.Payload.Entries, (unsigned int)status);
+ CFE_SB_LockSharedData(__func__,__LINE__);
+ CFE_SB.PrevSubMsg.Payload.Entries = 0;
+ CFE_SB.PrevSubMsg.Payload.PktSegment++;
+ }
-}/* end CFE_SB_SendMapInfo */
+ /*
+ * break while loop through destinations, onto next route
+ * This is done because we want only one network subscription per msgid
+ * Later when Qos is used, we may want to take just the highest priority
+ * subscription if there are more than one
+ */
+ break;
+ }
+ /* Advance to next destination */
+ destptr = destptr->Next;
+ }
+}
/******************************************************************************
** Function: CFE_SB_SendPrevSubsCmd()
@@ -1129,140 +1199,32 @@ int32 CFE_SB_SendMapInfo(const char *Filename)
*/
int32 CFE_SB_SendPrevSubsCmd(const CFE_SB_SendPrevSubs_t *data)
{
- CFE_SB_MsgRouteIdx_Atom_t i;
- const CFE_SB_RouteEntry_t* RoutePtr;
- uint32 EntryNum = 0;
- uint32 SegNum = 1;
- int32 Stat;
- CFE_SB_DestinationD_t *DestPtr = NULL;
-
- /* Take semaphore to ensure data does not change during this function */
- CFE_SB_LockSharedData(__func__,__LINE__);
-
- /* seek msgids that are in use */
- for(i=0;iMsgId))
- {
- DestPtr = NULL;
- }
- else
- {
- DestPtr = CFE_SB.RoutingTbl[i].ListHeadPtr;
- }
-
- while(DestPtr != NULL){
-
- if(DestPtr->Scope == CFE_SB_GLOBAL){
-
- /* ...add entry into pkt */
- CFE_SB.PrevSubMsg.Payload.Entry[EntryNum].MsgId = RoutePtr->MsgId;
- CFE_SB.PrevSubMsg.Payload.Entry[EntryNum].Qos.Priority = 0;
- CFE_SB.PrevSubMsg.Payload.Entry[EntryNum].Qos.Reliability = 0;
- EntryNum++;
-
- /* send pkt if full */
- if(EntryNum >= CFE_SB_SUB_ENTRIES_PER_PKT){
- CFE_SB.PrevSubMsg.Payload.PktSegment = SegNum;
- CFE_SB.PrevSubMsg.Payload.Entries = EntryNum;
- CFE_SB_UnlockSharedData(__func__,__LINE__);
- Stat = CFE_SB_SendMsg((CFE_SB_Msg_t *)&CFE_SB.PrevSubMsg);
- CFE_SB_LockSharedData(__func__,__LINE__);
- CFE_EVS_SendEvent(CFE_SB_FULL_SUB_PKT_EID,CFE_EVS_EventType_DEBUG,
- "Full Sub Pkt %d Sent,Entries=%d,Stat=0x%x\n",(int)SegNum,(int)EntryNum,(unsigned int)Stat);
- EntryNum = 0;
- SegNum++;
- }/* end if */
-
- /* break while loop through destinations, onto next CFE_SB.RoutingTbl index */
- /* This is done because we want only one network subscription per msgid */
- /* Later when Qos is used, we may want to take just the highest priority */
- /* subscription if there are more than one */
- break;
-
- }/* end if */
-
- /* Check next destination (if another exists) for global scope */
- DestPtr = DestPtr -> Next;
-
- }/* end while */
-
- }/* end for */
-
- /* if pkt has any number of entries, send it as a partial pkt */
- if(EntryNum > 0){
- CFE_SB.PrevSubMsg.Payload.PktSegment = SegNum;
- CFE_SB.PrevSubMsg.Payload.Entries = EntryNum;
- CFE_SB_UnlockSharedData(__func__,__LINE__);
- Stat = CFE_SB_SendMsg((CFE_SB_Msg_t *)&CFE_SB.PrevSubMsg);
- CFE_SB_LockSharedData(__func__,__LINE__);
- CFE_EVS_SendEvent(CFE_SB_PART_SUB_PKT_EID,CFE_EVS_EventType_DEBUG,
- "Partial Sub Pkt %d Sent,Entries=%d,Stat=0x%x",(int)SegNum,(int)EntryNum,(unsigned int)Stat);
- }/* end if */
+ int32 status;
- CFE_SB_UnlockSharedData(__func__,__LINE__);
+ /* Take semaphore to ensure data does not change during this function */
+ CFE_SB_LockSharedData(__func__,__LINE__);
- return CFE_SUCCESS;
-}/* end CFE_SB_SendPrevSubsCmd */
+ /* Initialize entry/segment tracking */
+ CFE_SB.PrevSubMsg.Payload.PktSegment = 1;
+ CFE_SB.PrevSubMsg.Payload.Entries = 0;
+ /* Send subcription for each route */
+ CFE_SBR_ForEachRouteId(CFE_SB_SendRouteSub, NULL, NULL);
-/******************************************************************************
-** Function: CFE_SB_FindGlobalMsgIdCnt()
-**
-** Purpose:
-** SB internal function to get a count of the global message ids in use.
-**
-** Notes:
-** Subscriptions made with CFE_SB_SubscribeLocal would not be counted.
-** Subscription made with a subscribe API other than CFE_SB_SubscribeLocal are
-** considerd to be global subscriptions. MsgIds with both global and local
-** subscriptions would be counted.
-**
-** Arguments:
-**
-** Return:
-** None
-*/
-uint32 CFE_SB_FindGlobalMsgIdCnt(void){
+ CFE_SB_UnlockSharedData(__func__,__LINE__);
- CFE_SB_MsgRouteIdx_Atom_t i;
- uint32 cnt = 0;
- const CFE_SB_RouteEntry_t* RoutePtr;
- CFE_SB_DestinationD_t *DestPtr = NULL;
-
- for(i=0;i 0)
{
- RoutePtr = CFE_SB_GetRoutePtrFromIdx(CFE_SB_ValueToRouteIdx(i));
- if(!CFE_SB_IsValidMsgId(RoutePtr->MsgId))
- {
- DestPtr = NULL;
- }
- else
- {
- DestPtr = RoutePtr->ListHeadPtr;
- }
-
- while(DestPtr != NULL){
-
- if(DestPtr->Scope == CFE_SB_GLOBAL){
-
- cnt++;
- break;
-
- }/* end if */
-
- /* Check next destination (if another exists) for global scope */
- DestPtr = DestPtr -> Next;
-
- }/* end while */
-
- }/* end for */
-
- return cnt;
-
-}/* end CFE_SB_FindGlobalMsgIdCnt */
+ status = CFE_SB_SendMsg((CFE_SB_Msg_t *)&CFE_SB.PrevSubMsg);
+ CFE_EVS_SendEvent(CFE_SB_PART_SUB_PKT_EID, CFE_EVS_EventType_DEBUG,
+ "Partial Sub Pkt %d Sent,Entries=%d,Stat=0x%x",
+ (int)CFE_SB.PrevSubMsg.Payload.PktSegment, (int)CFE_SB.PrevSubMsg.Payload.Entries,
+ (unsigned int)status);
+ }
+ return CFE_SUCCESS;
+}/* end CFE_SB_SendPrevSubsCmd */
diff --git a/fsw/cfe-core/unit-test/CMakeLists.txt b/fsw/cfe-core/unit-test/CMakeLists.txt
index a61043a71..7e79e5c69 100644
--- a/fsw/cfe-core/unit-test/CMakeLists.txt
+++ b/fsw/cfe-core/unit-test/CMakeLists.txt
@@ -71,6 +71,7 @@ foreach(MODULE ${CFE_CORE_MODULES})
${UT_COVERAGE_LINK_FLAGS}
ut_cfe-core_support
ut_cfe-core_stubs
+ sbr # TODO remove this
ut_assert)
add_test(${UT_TARGET_NAME}_UT ${UT_TARGET_NAME}_UT)
diff --git a/fsw/cfe-core/unit-test/sb_UT.c b/fsw/cfe-core/unit-test/sb_UT.c
index 820957f0f..600fa5b6a 100644
--- a/fsw/cfe-core/unit-test/sb_UT.c
+++ b/fsw/cfe-core/unit-test/sb_UT.c
@@ -1287,7 +1287,16 @@ void Test_SB_Cmds_SendPrevSubs(void)
CFE_SB_ProcessCmdPipePkt();
NumEvts += 8; /* +2 for the subscribe, +6 for the SEND_PREV_SUBS_CC */
- EVTCNT(NumEvts);
+
+ /* Event count is only exact if there were no collisions */
+ if (UT_EventIsInHistory(CFE_SB_HASHCOLLISION_EID))
+ {
+ ASSERT_TRUE(UT_GetNumEventsSent() > NumEvts);
+ }
+ else
+ {
+ EVTCNT(NumEvts);
+ }
/* Round out the number to three full pkts in order to test branch path
* coverage, MSGID 0x0D was skipped in previous subscription loop
@@ -1321,7 +1330,15 @@ void Test_SB_Cmds_SendPrevSubs(void)
NumEvts += 8; /* +2 for the subscribe, +6 for the SEND_PREV_SUBS_CC */
- EVTCNT(NumEvts);
+ /* Event count is only exact if there were no collisions */
+ if (UT_EventIsInHistory(CFE_SB_HASHCOLLISION_EID))
+ {
+ ASSERT_TRUE(UT_GetNumEventsSent() > NumEvts);
+ }
+ else
+ {
+ EVTCNT(NumEvts);
+ }
EVTSENT(CFE_SB_SUBSCRIPTION_RCVD_EID);
EVTSENT(CFE_SB_SEND_NO_SUBS_EID);
@@ -1704,7 +1721,7 @@ void Test_DeletePipe_WithSubs(void)
SETUP(CFE_SB_Subscribe(MsgId3, PipedId));
ASSERT(CFE_SB_DeletePipe(PipedId));
- EVTCNT(14);
+ EVTCNT(10);
EVTSENT(CFE_SB_PIPE_ADDED_EID);
EVTSENT(CFE_SB_PIPE_DELETED_EID);
@@ -1772,7 +1789,7 @@ void Test_DeletePipe_WithAppid(void)
ASSERT(CFE_SB_DeletePipeWithAppId(PipedId, AppId));
- EVTCNT(14);
+ EVTCNT(10);
} /* end Test_DeletePipe_WithAppid */
@@ -2030,7 +2047,6 @@ void Test_Subscribe_API(void)
SB_UT_ADD_SUBTEST(Test_Subscribe_MaxDestCount);
SB_UT_ADD_SUBTEST(Test_Subscribe_MaxMsgIdCount);
SB_UT_ADD_SUBTEST(Test_Subscribe_SendPrevSubs);
- SB_UT_ADD_SUBTEST(Test_Subscribe_FindGlobalMsgIdCnt);
SB_UT_ADD_SUBTEST(Test_Subscribe_PipeNonexistent);
SB_UT_ADD_SUBTEST(Test_Subscribe_SubscriptionReporting);
SB_UT_ADD_SUBTEST(Test_Subscribe_InvalidPipeOwner);
@@ -2274,9 +2290,6 @@ void Test_Subscribe_SendPrevSubs(void)
SETUP(CFE_SB_Subscribe(MsgId2, PipeId1));
SETUP(CFE_SB_Subscribe(MsgId0, PipeId2));
- /* Set the last list header pointer to NULL to get branch path coverage */
- CFE_SB.RoutingTbl[2].ListHeadPtr = NULL;
-
/* For internal SendMsg call */
MsgIdCmd = CFE_SB_ValueToMsgId(CFE_SB_ALLSUBS_TLM_MID);
Size = sizeof(CFE_SB.PrevSubMsg);
@@ -2295,46 +2308,6 @@ void Test_Subscribe_SendPrevSubs(void)
} /* end Test_Subscribe_SendPrevSubs */
-/*
-** Test function to get a count of the global message ids in use
-*/
-void Test_Subscribe_FindGlobalMsgIdCnt(void)
-{
- CFE_SB_PipeId_t PipeId0;
- CFE_SB_PipeId_t PipeId1;
- CFE_SB_PipeId_t PipeId2;
- CFE_SB_MsgId_t MsgId0 = SB_UT_TLM_MID1;
- CFE_SB_MsgId_t MsgId1 = SB_UT_TLM_MID2;
- CFE_SB_MsgId_t MsgId2 = SB_UT_TLM_MID3;
- uint16 PipeDepth = 50;
- uint16 MsgLim = 4;
-
- SETUP(CFE_SB_CreatePipe(&PipeId0, PipeDepth, "TestPipe0"));
- SETUP(CFE_SB_CreatePipe(&PipeId1, PipeDepth, "TestPipe1"));
- SETUP(CFE_SB_CreatePipe(&PipeId2, PipeDepth, "TestPipe2"));
- SETUP(CFE_SB_Subscribe(MsgId0, PipeId0));
- SETUP(CFE_SB_Subscribe(MsgId1, PipeId0));
- SETUP(CFE_SB_Subscribe(MsgId2, PipeId0));
- SETUP(CFE_SB_Subscribe(MsgId0, PipeId1));
- SETUP(CFE_SB_Subscribe(MsgId1, PipeId1));
- SETUP(CFE_SB_Subscribe(MsgId2, PipeId1));
- SETUP(CFE_SB_SubscribeLocal(MsgId0, PipeId2, MsgLim));
-
- /* Set the last list head pointer to NULL for branch path coverage */
- CFE_SB.RoutingTbl[2].ListHeadPtr = NULL;
-
- ASSERT_EQ(CFE_SB_FindGlobalMsgIdCnt(), 2); /* 2 unique msg ids; the third is set to skip */
-
- EVTCNT(17);
-
- EVTSENT(CFE_SB_PIPE_ADDED_EID);
-
- TEARDOWN(CFE_SB_DeletePipe(PipeId0));
- TEARDOWN(CFE_SB_DeletePipe(PipeId1));
- TEARDOWN(CFE_SB_DeletePipe(PipeId2));
-
-} /* end Test_Subscribe_FindGlobalMsgIdCnt */
-
/*
** Test message subscription response to nonexistent pipe
*/
@@ -2366,7 +2339,7 @@ void Test_Subscribe_SubscriptionReporting(void)
SETUP(CFE_SB_CreatePipe(&PipeId, PipeDepth, "TestPipe"));
/* Enable subscription reporting */
- CFE_SB_SetSubscriptionReporting(CFE_SB_ENABLE);
+ CFE_SB_SetSubscriptionReporting(CFE_SB_ENABLE);
/* For internal SendMsg call that will report subscription */
MsgIdRpt = CFE_SB_ValueToMsgId(CFE_SB_ONESUB_TLM_MID);
@@ -2374,21 +2347,21 @@ void Test_Subscribe_SubscriptionReporting(void)
UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgIdRpt, sizeof(MsgIdRpt), false);
UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false);
- /* Subscribe to message: GLOBAL */
- SETUP(CFE_SB_Subscribe(MsgId, PipeId));
+ /* Subscribe to message: GLOBAL */
+ SETUP(CFE_SB_Subscribe(MsgId, PipeId));
- /* Unsubscribe so that a local subscription can be tested */
- SETUP(CFE_SB_Unsubscribe(MsgId, PipeId));
+ /* Unsubscribe so that a local subscription can be tested */
+ SETUP(CFE_SB_Unsubscribe(MsgId, PipeId));
- /* Subscribe to message: LOCAL */
- ASSERT(CFE_SB_SubscribeFull(MsgId, PipeId, Quality, CFE_PLATFORM_SB_DEFAULT_MSG_LIMIT, CFE_SB_LOCAL));
+ /* Subscribe to message: LOCAL */
+ ASSERT(CFE_SB_SubscribeFull(MsgId, PipeId, Quality, CFE_PLATFORM_SB_DEFAULT_MSG_LIMIT, CFE_SB_LOCAL));
- EVTCNT(8);
+ EVTCNT(8);
- EVTSENT(CFE_SB_SUBSCRIPTION_RPT_EID);
+ EVTSENT(CFE_SB_SUBSCRIPTION_RPT_EID);
- /* Disable subscription reporting */
- CFE_SB_SetSubscriptionReporting(CFE_SB_DISABLE);
+ /* Disable subscription reporting */
+ CFE_SB_SetSubscriptionReporting(CFE_SB_DISABLE);
TEARDOWN(CFE_SB_DeletePipe(PipeId));
@@ -2538,22 +2511,21 @@ void Test_Unsubscribe_NoMatch(void)
{
CFE_SB_PipeId_t TestPipe;
CFE_SB_MsgId_t MsgId = SB_UT_TLM_MID;
- CFE_SB_MsgRouteIdx_t Idx;
uint16 PipeDepth = 50;
+ /* Create pipe, subscribe, unsubscribe */
SETUP(CFE_SB_CreatePipe(&TestPipe, PipeDepth, "TestPipe"));
SETUP(CFE_SB_Subscribe(MsgId, TestPipe));
+ SETUP(CFE_SB_Unsubscribe(MsgId, TestPipe));
+ UT_ClearEventHistory();
+ /* Check that unsubscribe to msgid that was never subscribed reports error */
ASSERT(CFE_SB_Unsubscribe(SB_UT_TLM_MID1, TestPipe));
+ EVTSENT(CFE_SB_UNSUB_NO_SUBS_EID);
+ UT_ClearEventHistory();
- /* Get index into routing table */
- Idx = CFE_SB_GetRoutingTblIdx(CFE_SB_ConvertMsgIdtoMsgKey(MsgId));
- CFE_SB.RoutingTbl[CFE_SB_RouteIdxToValue(Idx)].ListHeadPtr->PipeId = 1;
- CFE_SB.RoutingTbl[CFE_SB_RouteIdxToValue(Idx)].ListHeadPtr->Next = NULL;
+ /* Check that repeated unsubscribe to msgid that was subscribted reports error */
ASSERT(CFE_SB_Unsubscribe(MsgId, TestPipe));
-
- EVTCNT(7);
-
EVTSENT(CFE_SB_UNSUB_NO_SUBS_EID);
TEARDOWN(CFE_SB_DeletePipe(TestPipe));
@@ -2681,10 +2653,11 @@ void Test_Unsubscribe_MiddleDestWithMany(void)
*/
void Test_Unsubscribe_GetDestPtr(void)
{
- CFE_SB_MsgId_t MsgId = SB_UT_CMD_MID;
- CFE_SB_PipeId_t TestPipe1;
- CFE_SB_PipeId_t TestPipe2;
- uint16 PipeDepth = 50;
+ CFE_SB_MsgId_t MsgId = SB_UT_CMD_MID;
+ CFE_SB_PipeId_t TestPipe1;
+ CFE_SB_PipeId_t TestPipe2;
+ uint16 PipeDepth = 50;
+ CFE_SBR_RouteId_t RouteId;
SETUP(CFE_SB_CreatePipe(&TestPipe1, PipeDepth, "TestPipe1"));
SETUP(CFE_SB_CreatePipe(&TestPipe2, PipeDepth, "TestPipe2"));
@@ -2692,7 +2665,9 @@ void Test_Unsubscribe_GetDestPtr(void)
SETUP(CFE_SB_Subscribe(MsgId, TestPipe2));
SETUP(CFE_SB_Unsubscribe(MsgId, TestPipe2));
- ASSERT_TRUE(CFE_SB_GetDestPtr(CFE_SB_ConvertMsgIdtoMsgKey(MsgId), TestPipe2) == NULL);
+ /* TODO for now just get route id and use it, will need update when stubbed */
+ RouteId = CFE_SBR_GetRouteId(MsgId);
+ ASSERT_TRUE(CFE_SB_GetDestPtr(RouteId, TestPipe2) == NULL);
EVTCNT(7);
@@ -3252,12 +3227,15 @@ void Test_SendMsg_DisabledDestination(void)
int32 PipeDepth;
CFE_MSG_Type_t Type = CFE_MSG_Type_Tlm;
CFE_MSG_Size_t Size = sizeof(TlmPkt);
+ CFE_SBR_RouteId_t RouteId;
PipeDepth = 2;
SETUP(CFE_SB_CreatePipe(&PipeId, PipeDepth, "TestPipe"));
SETUP(CFE_SB_Subscribe(MsgId, PipeId));
- DestPtr = CFE_SB_GetDestPtr(CFE_SB_ConvertMsgIdtoMsgKey(MsgId), PipeId);
+
+ RouteId = CFE_SBR_GetRouteId(MsgId);
+ DestPtr = CFE_SB_GetDestPtr(RouteId, PipeId);
DestPtr->Active = CFE_SB_INACTIVE;
UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false);
@@ -3857,41 +3835,8 @@ void Test_SB_SpecialCases(void)
SB_UT_ADD_SUBTEST(Test_SB_SendMsgPaths_IgnoreOpt);
SB_UT_ADD_SUBTEST(Test_RcvMsg_UnsubResubPath);
SB_UT_ADD_SUBTEST(Test_MessageString);
- SB_UT_ADD_SUBTEST(Test_SB_IdxPushPop);
} /* end Test_SB_SpecialCases */
-/*
-** Test msg key idx push pop
-*/
-void Test_SB_IdxPushPop()
-{
- int32 i;
- CFE_SB_MsgRouteIdx_t Idx;
-
- CFE_SB_InitIdxStack();
-
- for (i = 0; i < CFE_PLATFORM_SB_MAX_MSG_IDS; i++)
- {
- /* Subscribe to maximum number of messages */
- Idx = CFE_SB_RouteIdxPop_Unsync();
- ASSERT_EQ(CFE_SB_RouteIdxToValue(Idx), i);
- }
-
-
- Idx = CFE_SB_RouteIdxPop_Unsync();
- ASSERT_EQ(CFE_SB_RouteIdxToValue(Idx), CFE_SB_RouteIdxToValue(CFE_SB_INVALID_ROUTE_IDX));
-
- for (i = 0; i < CFE_PLATFORM_SB_MAX_MSG_IDS; i++)
- {
- /* Un-subscribe from all messages */
- CFE_SB_RouteIdxPush_Unsync(CFE_SB_ValueToRouteIdx(i));
- }
-
- CFE_SB_RouteIdxPush_Unsync(CFE_SB_ValueToRouteIdx(i));
-
-
-} /* end Test_SB_IdxPushPop */
-
/*
** Test pipe creation with semaphore take and give failures
*/
@@ -4037,10 +3982,10 @@ void Test_CFE_SB_BadPipeInfo(void)
} /* end Test_CFE_SB_BadPipeInfo */
+
/*
** Test send housekeeping information command
*/
-
void Test_SB_SendMsgPaths_Nominal(void)
{
CFE_SB_CmdHdr_t NoParamCmd;
@@ -4062,12 +4007,17 @@ void Test_SB_SendMsgPaths_Nominal(void)
MsgId = CFE_SB_ValueToMsgId(CFE_SB_SEND_HK_MID);
UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false);
+ /* Repress sending the no subscriptions event and process request */
+ CFE_SB.HKTlmMsg.Payload.NoSubscribersCounter = 0;
CFE_SB.CmdPipePktPtr = (CFE_SB_MsgPtr_t) &NoParamCmd;
CFE_SB.StopRecurseFlags[1] |= CFE_BIT(CFE_SB_SEND_NO_SUBS_EID_BIT);
CFE_SB_ProcessCmdPipePkt();
+ /* The no subs event should not be in history but count should increment */
ASSERT_TRUE(!UT_EventIsInHistory(CFE_SB_SEND_NO_SUBS_EID));
+ ASSERT_EQ(CFE_SB.HKTlmMsg.Payload.NoSubscribersCounter, 1);
+ /* Repress get buffer error */
CFE_SB.HKTlmMsg.Payload.MsgSendErrorCounter = 0;
CFE_SB.StopRecurseFlags[1] |= CFE_BIT(CFE_SB_GET_BUF_ERR_EID_BIT);
@@ -4081,7 +4031,6 @@ void Test_SB_SendMsgPaths_Nominal(void)
MsgId = CFE_SB_ValueToMsgId(CFE_SB_SEND_HK_MID);
UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false);
- CFE_SB.MsgMap[CFE_SB_MsgKeyToValue(CFE_SB_ConvertMsgIdtoMsgKey(CFE_SB_HK_TLM_MID))] = CFE_SB_INVALID_ROUTE_IDX;
UT_SetDeferredRetcode(UT_KEY(CFE_ES_GetPoolBuf), 1, CFE_ES_ERR_MEM_BLOCK_SIZE);
CFE_SB_ProcessCmdPipePkt();
ASSERT_EQ(CFE_SB.HKTlmMsg.Payload.MsgSendErrorCounter, 0);
diff --git a/modules/sbr/CMakeLists.txt b/modules/sbr/CMakeLists.txt
new file mode 100644
index 000000000..615589ca3
--- /dev/null
+++ b/modules/sbr/CMakeLists.txt
@@ -0,0 +1,43 @@
+##################################################################
+#
+# cFE software bus routing module CMake build recipe
+#
+# This CMakeLists.txt adds source files for the
+# SBR module included in the cFE distribution. Selected
+# files are built into a static library that in turn
+# is linked into the final executable.
+#
+# Note this is different than applications which are dynamically
+# linked to support runtime loading. The core applications all
+# use static linkage.
+#
+##################################################################
+
+if (NOT MISSION_MSGMAP_IMPLEMENTATION)
+ set(MISSION_MSGMAP_IMPLEMENTATION "DIRECT")
+endif (NOT MISSION_MSGMAP_IMPLEMENTATION)
+
+if (MISSION_MSGMAP_IMPLEMENTATION STREQUAL "DIRECT")
+ message(STATUS "Using direct map software bus routing implementation")
+ set(${DEP}_SRC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/cfe_sbr_map_direct.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/cfe_sbr_route_unsorted.c)
+elseif (MISSION_MSGMAP_IMPLEMENTATION STREQUAL "HASH")
+ message(STATUS "Using hashed map software bus routing implementation")
+ set(${DEP}_SRC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/cfe_sbr_map_hash.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/cfe_sbr_route_unsorted.c)
+else()
+ message(ERROR "Invalid software bush routing implementation selected:" MISSION_MSGMAP_IMPLEMENTATION)
+endif()
+
+# Module library
+add_library(${DEP} STATIC ${${DEP}_SRC})
+
+# Add private include
+target_include_directories(${DEP} PRIVATE private_inc)
+
+# Add unit test coverage subdirectory
+if(ENABLE_UNIT_TESTS)
+ add_subdirectory(unit-test-coverage)
+endif(ENABLE_UNIT_TESTS)
diff --git a/modules/sbr/private_inc/cfe_sbr_priv.h b/modules/sbr/private_inc/cfe_sbr_priv.h
new file mode 100644
index 000000000..3d0fcce59
--- /dev/null
+++ b/modules/sbr/private_inc/cfe_sbr_priv.h
@@ -0,0 +1,66 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** 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.
+*/
+
+/******************************************************************************
+ * Prototypes for private functions and type definitions for SB
+ * routing internal use.
+ *****************************************************************************/
+
+#ifndef CFE_SBR_PRIV_H_
+#define CFE_SBR_PRIV_H_
+
+/*
+ * Includes
+ */
+#include "private/cfe_sbr.h"
+
+/*
+ * Macro Definitions
+ */
+
+/** \brief Invalid route id */
+#define CFE_SBR_INVALID_ROUTE_ID ((CFE_SBR_RouteId_t) {.RouteId = 0})
+
+/******************************************************************************
+ * Function prototypes
+ */
+
+/**
+ * \brief Routing map initialization
+ */
+void CFE_SBR_Init_Map(void);
+
+/**
+ * \brief Associates the given route ID with the given message ID
+ *
+ * Used for implementations that use a mapping table (typically hash or direct)
+ * and need this information to later get the route id from the message id.
+ *
+ * \note Typically not needed for a search implementation. Assumes
+ * message ID is valid
+ *
+ * \param[in] MsgId Message id to associate with route id
+ * \param[in] RouteId Route id to associate with message id
+ *
+ * \returns Number of collisions
+ */
+uint32 CFE_SBR_SetRouteId(CFE_SB_MsgId_t MsgId, CFE_SBR_RouteId_t RouteId);
+
+#endif /* CFE_SBR_PRIV_H_ */
diff --git a/modules/sbr/src/cfe_sbr_map_direct.c b/modules/sbr/src/cfe_sbr_map_direct.c
new file mode 100644
index 000000000..1545bf4ef
--- /dev/null
+++ b/modules/sbr/src/cfe_sbr_map_direct.c
@@ -0,0 +1,93 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** 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.
+*/
+
+/******************************************************************************
+ * Direct routing map implementation
+ *
+ * Notes:
+ * These functions manipulate/access global variables and need
+ * to be protected by the SB Shared data lock.
+ *
+ */
+
+/*
+ * Include Files
+ */
+
+#include "common_types.h"
+#include "private/cfe_sbr.h"
+#include "cfe_sbr_priv.h"
+#include
+
+/*
+ * Macro Definitions
+ */
+
+/**
+ * \brief Message map size
+ *
+ * For direct mapping, map size is maximum valid MsgId value + 1 (since MsgId 0 is valid)
+ */
+#define CFE_SBR_MSG_MAP_SIZE (CFE_PLATFORM_SB_HIGHEST_VALID_MSGID + 1)
+
+/******************************************************************************
+ * Shared data
+ */
+
+/** \brief Message map shared data */
+CFE_SBR_RouteId_t CFE_SBR_MSGMAP[CFE_SBR_MSG_MAP_SIZE];
+
+/******************************************************************************
+ * Interface function - see header for description
+ */
+void CFE_SBR_Init_Map(void)
+{
+ /* Clear the shared data */
+ memset(&CFE_SBR_MSGMAP, 0, sizeof(CFE_SBR_MSGMAP));
+}
+
+/******************************************************************************
+ * Interface function - see header for description
+ */
+uint32 CFE_SBR_SetRouteId(CFE_SB_MsgId_t MsgId, CFE_SBR_RouteId_t RouteId)
+{
+ if (CFE_SB_IsValidMsgId(MsgId))
+ {
+ CFE_SBR_MSGMAP[CFE_SB_MsgIdToValue(MsgId)] = RouteId;
+ }
+
+ /* Direct lookup never collides, always return 0 */
+ return 0;
+}
+
+/******************************************************************************
+ * Interface function - see API for description
+ */
+CFE_SBR_RouteId_t CFE_SBR_GetRouteId(CFE_SB_MsgId_t MsgId)
+{
+ CFE_SBR_RouteId_t routeid = CFE_SBR_INVALID_ROUTE_ID;
+
+ if (CFE_SB_IsValidMsgId(MsgId))
+ {
+ routeid = CFE_SBR_MSGMAP[CFE_SB_MsgIdToValue(MsgId)];
+ }
+
+ return routeid;
+}
diff --git a/modules/sbr/src/cfe_sbr_map_hash.c b/modules/sbr/src/cfe_sbr_map_hash.c
new file mode 100644
index 000000000..dd9b8bd5c
--- /dev/null
+++ b/modules/sbr/src/cfe_sbr_map_hash.c
@@ -0,0 +1,163 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** 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.
+*/
+
+/******************************************************************************
+ * Hash routing map implementation
+ *
+ * Notes:
+ * These functions manipulate/access global variables and need
+ * to be protected by the SB Shared data lock.
+ *
+ */
+
+/*
+ * Include Files
+ */
+
+#include "common_types.h"
+#include "private/cfe_sbr.h"
+#include "cfe_sbr_priv.h"
+#include
+#include
+
+/*
+ * Macro Definitions
+ */
+
+/**
+ * \brief Message map size
+ *
+ * For hash mapping, map size is a multiple of maximum number of routes.
+ * The multiple impacts the number of collisions when the routes fill up.
+ * 4 was initially chosen to provide for plenty of holes in the map, while
+ * still remaining much smaller than the routing table. Note the
+ * multiple must be a factor of 2 to use the efficient shift logic, and
+ * can't be bigger than what can be indexed by CFE_SB_MsgId_Atom_t
+ */
+#define CFE_SBR_MSG_MAP_SIZE (4 * CFE_PLATFORM_SB_MAX_MSG_IDS)
+
+/* Verify power of two */
+#if ((CFE_SBR_MSG_MAP_SIZE & (CFE_SBR_MSG_MAP_SIZE - 1)) != 0)
+#error CFE_SBR_MSG_MAP_SIZE must be a power of 2 for hash algorithm to work
+#endif
+
+/** \brief Hash algorithm magic number
+ *
+ * Ref:
+ * https://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key/12996028#12996028
+ */
+#define CFE_SBR_HASH_MAGIC (0x45d9f3b)
+
+/******************************************************************************
+ * Shared data
+ */
+
+/** \brief Message map shared data */
+CFE_SBR_RouteId_t CFE_SBR_MSGMAP[CFE_SBR_MSG_MAP_SIZE];
+
+/******************************************************************************
+ * Internal helper function to hash the message id
+ *
+ * Note: algorithm designed for a 32 bit int, changing the size of
+ * CFE_SB_MsgId_Atom_t may require an update to this impelementation
+ */
+CFE_SB_MsgId_Atom_t CFE_SBR_MsgIdHash(CFE_SB_MsgId_t MsgId)
+{
+ CFE_SB_MsgId_Atom_t hash;
+
+ hash = CFE_SB_MsgIdToValue(MsgId);
+
+ hash = ((hash >> 16) ^ hash) * CFE_SBR_HASH_MAGIC;
+ hash = ((hash >> 16) ^ hash) * CFE_SBR_HASH_MAGIC;
+ hash = (hash >> 16) ^ hash;
+
+ /* Reduce to fit in map */
+ hash &= CFE_SBR_MSG_MAP_SIZE - 1;
+
+ return hash;
+}
+
+/******************************************************************************
+ * Interface function - see header for description
+ */
+void CFE_SBR_Init_Map(void)
+{
+ /* Clear the shared data */
+ memset(&CFE_SBR_MSGMAP, 0, sizeof(CFE_SBR_MSGMAP));
+}
+
+/******************************************************************************
+ * Interface function - see header for description
+ */
+uint32 CFE_SBR_SetRouteId(CFE_SB_MsgId_t MsgId, CFE_SBR_RouteId_t RouteId)
+{
+ CFE_SB_MsgId_Atom_t hash;
+ uint32 collisions = 0;
+
+ if (CFE_SB_IsValidMsgId(MsgId))
+ {
+ hash = CFE_SBR_MsgIdHash(MsgId);
+
+ /*
+ * Increment from original hash to find the next open slot.
+ * Since map is larger than possible routes this will
+ * never deadlock
+ */
+ while (CFE_SBR_IsValidRouteId(CFE_SBR_MSGMAP[hash]))
+ {
+ /* Increment or loop to start of array */
+ hash = (hash + 1) & (CFE_SBR_MSG_MAP_SIZE - 1);
+ collisions++;
+ }
+
+ CFE_SBR_MSGMAP[hash] = RouteId;
+ }
+
+ return collisions;
+}
+
+/******************************************************************************
+ * Interface function - see API for description
+ */
+CFE_SBR_RouteId_t CFE_SBR_GetRouteId(CFE_SB_MsgId_t MsgId)
+{
+ CFE_SB_MsgId_Atom_t hash;
+ CFE_SBR_RouteId_t routeid = CFE_SBR_INVALID_ROUTE_ID;
+
+ if (CFE_SB_IsValidMsgId(MsgId))
+ {
+ hash = CFE_SBR_MsgIdHash(MsgId);
+ routeid = CFE_SBR_MSGMAP[hash];
+
+ /*
+ * Increment from original hash to find matching route.
+ * Since map is larger than possible routes this will
+ * never deadlock
+ */
+ while (CFE_SBR_IsValidRouteId(routeid) && !CFE_SB_MsgId_Equal(CFE_SBR_GetMsgId(routeid), MsgId))
+ {
+ /* Increment or loop to start of array */
+ hash = (hash + 1) & (CFE_SBR_MSG_MAP_SIZE - 1);
+ routeid = CFE_SBR_MSGMAP[hash];
+ }
+ }
+
+ return routeid;
+}
diff --git a/modules/sbr/src/cfe_sbr_route_unsorted.c b/modules/sbr/src/cfe_sbr_route_unsorted.c
new file mode 100644
index 000000000..716cd50e4
--- /dev/null
+++ b/modules/sbr/src/cfe_sbr_route_unsorted.c
@@ -0,0 +1,219 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** 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.
+*/
+
+/******************************************************************************
+ * Purpose:
+ * Unsorted routing implemenation
+ * Used with route map implementations where order of routes doesn't matter
+ *
+ * Notes:
+ * These functions manipulate/access global variables and need
+ * to be protected by the SB Shared data lock.
+ */
+
+/*
+ * Include Files
+ */
+
+#include "common_types.h"
+#include "private/cfe_sbr.h"
+#include "cfe_sbr_priv.h"
+#include
+
+/******************************************************************************
+ * Type Definitions
+ */
+
+/** \brief Routing table entry */
+typedef struct
+{
+ CFE_SB_DestinationD_t * ListHeadPtr; /**< \brief Destination list head */
+ CFE_SB_MsgId_t MsgId; /**< \brief Message ID associated with route */
+ CFE_MSG_SequenceCount_t SeqCnt; /**< \brief Message sequence counter */
+} CFE_SBR_RouteEntry_t;
+
+/** \brief Module data */
+typedef struct
+{
+ CFE_SBR_RouteEntry_t RoutingTbl[CFE_PLATFORM_SB_MAX_MSG_IDS]; /**< \brief Routing table */
+ CFE_SB_RouteId_Atom_t RouteIdxTop; /**< \brief First unused entry in RoutingTbl */
+} cfe_sbr_route_data_t;
+
+/******************************************************************************
+ * Shared data
+ */
+
+/** \brief Routing module shared data */
+cfe_sbr_route_data_t CFE_SBR_RDATA;
+
+/******************************************************************************
+ * Interface function - see API for description
+ */
+void CFE_SBR_Init(void)
+{
+ CFE_SB_RouteId_Atom_t routeidx;
+
+ /* Clear the shared data */
+ memset(&CFE_SBR_RDATA, 0, sizeof(CFE_SBR_RDATA));
+
+ /* Only non-zero value for shared data initialization is the invalid MsgId */
+ for (routeidx = 0; routeidx < CFE_PLATFORM_SB_MAX_MSG_IDS; routeidx++)
+ {
+ CFE_SBR_RDATA.RoutingTbl[routeidx].MsgId = CFE_SB_INVALID_MSG_ID;
+ }
+
+ /* Initialize map */
+ CFE_SBR_Init_Map();
+}
+
+/******************************************************************************
+ * Interface function - see API for description
+ */
+CFE_SBR_RouteId_t CFE_SBR_AddRoute(CFE_SB_MsgId_t MsgId, uint32 *CollisionsPtr)
+{
+ CFE_SBR_RouteId_t routeid = CFE_SBR_INVALID_ROUTE_ID;
+ uint32 collisions = 0;
+
+ if (CFE_SB_IsValidMsgId(MsgId) && (CFE_SBR_RDATA.RouteIdxTop < CFE_PLATFORM_SB_MAX_MSG_IDS))
+ {
+ routeid = CFE_SBR_ValueToRouteId(CFE_SBR_RDATA.RouteIdxTop);
+ collisions = CFE_SBR_SetRouteId(MsgId, routeid);
+
+ CFE_SBR_RDATA.RoutingTbl[CFE_SBR_RDATA.RouteIdxTop].MsgId = MsgId;
+ CFE_SBR_RDATA.RouteIdxTop++;
+ }
+
+ if (CollisionsPtr != NULL)
+ {
+ *CollisionsPtr = collisions;
+ }
+
+ return routeid;
+}
+
+/******************************************************************************
+ * Interface function - see API for description
+ */
+CFE_SB_MsgId_t CFE_SBR_GetMsgId(CFE_SBR_RouteId_t RouteId)
+{
+ CFE_SB_MsgId_t msgid = CFE_SB_INVALID_MSG_ID;
+
+ if (CFE_SBR_IsValidRouteId(RouteId))
+ {
+ msgid = CFE_SBR_RDATA.RoutingTbl[CFE_SBR_RouteIdToValue(RouteId)].MsgId;
+ }
+
+ return msgid;
+}
+
+/******************************************************************************
+ * Interface function - see API for description
+ */
+CFE_SB_DestinationD_t *CFE_SBR_GetDestListHeadPtr(CFE_SBR_RouteId_t RouteId)
+{
+
+ CFE_SB_DestinationD_t *destptr = NULL;
+
+ if (CFE_SBR_IsValidRouteId(RouteId))
+ {
+ destptr = CFE_SBR_RDATA.RoutingTbl[CFE_SBR_RouteIdToValue(RouteId)].ListHeadPtr;
+ }
+
+ return destptr;
+}
+
+/******************************************************************************
+ * Interface function - see API for description
+ */
+void CFE_SBR_SetDestListHeadPtr(CFE_SBR_RouteId_t RouteId, CFE_SB_DestinationD_t *DestPtr)
+{
+
+ if (CFE_SBR_IsValidRouteId(RouteId))
+ {
+ CFE_SBR_RDATA.RoutingTbl[CFE_SBR_RouteIdToValue(RouteId)].ListHeadPtr = DestPtr;
+ }
+}
+
+/******************************************************************************
+ * Interface function - see API for description
+ */
+void CFE_SBR_IncrementSequenceCounter(CFE_SBR_RouteId_t RouteId)
+{
+ if (CFE_SBR_IsValidRouteId(RouteId))
+ {
+ CFE_SBR_RDATA.RoutingTbl[CFE_SBR_RouteIdToValue(RouteId)].SeqCnt++;
+ }
+}
+
+/******************************************************************************
+ * Interface function - see API for description
+ */
+CFE_MSG_SequenceCount_t CFE_SBR_GetSequenceCounter(CFE_SBR_RouteId_t RouteId)
+{
+ uint32 seqcnt = 0;
+
+ if (CFE_SBR_IsValidRouteId(RouteId))
+ {
+ seqcnt = CFE_SBR_RDATA.RoutingTbl[CFE_SBR_RouteIdToValue(RouteId)].SeqCnt;
+ }
+
+ return seqcnt;
+}
+
+/******************************************************************************
+ * Local helper function for throttling foreach routines
+ *
+ * Updates StartIdxPtr, EndIdxPtr and ThrottlePtr.NextIndex. Note EndIdxPtr
+ * must be set to maximum prior to calling.
+ */
+void CFE_SBR_Throttle(uint32 *StartIdxPtr, uint32 *EndIdxPtr, CFE_SBR_Throttle_t *ThrottlePtr)
+{
+ if (ThrottlePtr != NULL)
+ {
+ *StartIdxPtr = ThrottlePtr->StartIndex;
+
+ /* Return next index of zero if full range is processed */
+ ThrottlePtr->NextIndex = 0;
+
+ if ((*StartIdxPtr + ThrottlePtr->MaxLoop) < *EndIdxPtr)
+ {
+ *EndIdxPtr = *StartIdxPtr + ThrottlePtr->MaxLoop;
+ ThrottlePtr->NextIndex = *EndIdxPtr;
+ }
+ }
+}
+
+/******************************************************************************
+ * Interface function - see API for description
+ */
+void CFE_SBR_ForEachRouteId(CFE_SBR_CallbackPtr_t CallbackPtr, void *ArgPtr, CFE_SBR_Throttle_t *ThrottlePtr)
+{
+ CFE_SB_RouteId_Atom_t routeidx;
+ CFE_SB_MsgId_Atom_t startidx = 0;
+ CFE_SB_MsgId_Atom_t endidx = CFE_SBR_RDATA.RouteIdxTop;
+
+ /* Update throttle settings if needed */
+ CFE_SBR_Throttle(&startidx, &endidx, ThrottlePtr);
+
+ for (routeidx = startidx; routeidx < endidx; routeidx++)
+ {
+ (*CallbackPtr)(CFE_SBR_ValueToRouteId(routeidx), ArgPtr);
+ }
+}
diff --git a/modules/sbr/unit-test-coverage/CMakeLists.txt b/modules/sbr/unit-test-coverage/CMakeLists.txt
new file mode 100644
index 000000000..95b22232e
--- /dev/null
+++ b/modules/sbr/unit-test-coverage/CMakeLists.txt
@@ -0,0 +1,59 @@
+##################################################################
+#
+# cFE unit test build recipe
+#
+# This CMake file contains the recipe for building the cFE unit tests.
+# It is invoked from the parent directory when unit tests are enabled.
+#
+##################################################################
+
+# Set tests once so name changes are in one location
+set(SBR_TEST_MAP_DIRECT "sbr_map_direct")
+set(SBR_TEST_MAP_HASH "sbr_map_hash")
+set(SBR_TEST_ROUTE_UNSORTED "sbr_route_unsorted")
+
+# All coverage tests always built
+set(SBR_TEST_SET ${SBR_TEST_MAP_DIRECT} ${SBR_TEST_MAP_HASH} ${SBR_TEST_ROUTE_UNSORTED})
+
+# Add configured map implementation to routing test source
+if (MISSION_MSGMAP_IMPLEMENTATION STREQUAL "DIRECT")
+ set(${SBR_TEST_ROUTE_UNSORTED}_SRC ../src/cfe_sbr_map_direct.c)
+elseif (MISSION_MSGMAP_IMPLEMENTATION STREQUAL "HASH")
+ set(${SBR_TEST_ROUTE_UNSORTED}_SRC ../src/cfe_sbr_map_hash.c)
+endif()
+
+# Add route implementation to map hash
+set(${SBR_TEST_MAP_HASH}_SRC ../src/cfe_sbr_route_unsorted.c)
+
+foreach(SBR_TEST ${SBR_TEST_SET})
+
+ # Unit test object library sources, options, and includes
+ add_library(ut_${SBR_TEST}_objs OBJECT ${${SBR_TEST}_SRC} ../src/cfe_${SBR_TEST}.c)
+ target_compile_options(ut_${SBR_TEST}_objs PRIVATE ${UT_COVERAGE_COMPILE_FLAGS})
+ target_include_directories(ut_${SBR_TEST}_objs PRIVATE
+ $)
+
+ set (ut_${SBR_TEST}_tests
+ test_cfe_${SBR_TEST}.c
+ $)
+
+ # Add executable
+ add_executable(${SBR_TEST}_UT ${ut_${SBR_TEST}_tests})
+
+ # Add include to get private defaults
+ target_include_directories(${SBR_TEST}_UT PRIVATE ../private_inc)
+
+ # Also add the UT_COVERAGE_LINK_FLAGS to the link command
+ # This should enable coverage analysis on platforms that support this
+ target_link_libraries(${SBR_TEST}_UT
+ ${UT_COVERAGE_LINK_FLAGS}
+ ut_cfe-core_support
+ ut_cfe-core_stubs
+ ut_assert)
+
+ add_test(${SBR_TEST}_UT ${SBR_TEST}_UT)
+ foreach(TGT ${INSTALL_TARGET_LIST})
+ install(TARGETS ${SBR_TEST}_UT DESTINATION ${TGT}/${UT_INSTALL_SUBDIR})
+ endforeach()
+
+endforeach(SBR_TEST ${SBR_TEST_SET})
diff --git a/modules/sbr/unit-test-coverage/test_cfe_sbr_map_direct.c b/modules/sbr/unit-test-coverage/test_cfe_sbr_map_direct.c
new file mode 100644
index 000000000..a47c3e388
--- /dev/null
+++ b/modules/sbr/unit-test-coverage/test_cfe_sbr_map_direct.c
@@ -0,0 +1,112 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** 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.
+*/
+
+/*
+ * Test SBR direct message map implementation
+ */
+
+/*
+ * Includes
+ */
+#include "utassert.h"
+#include "ut_support.h"
+#include "private/cfe_sbr.h"
+#include "cfe_sbr_priv.h"
+#include
+
+void Test_SBR_Map_Direct(void)
+{
+
+ CFE_SB_MsgId_Atom_t msgidx;
+ CFE_SBR_RouteId_t routeid;
+ CFE_SB_MsgId_t msgid;
+ uint32 count;
+ uint32 i;
+
+ UtPrintf("Invalid msg checks");
+ ASSERT_EQ(CFE_SBR_SetRouteId(CFE_SB_ValueToMsgId(0), CFE_SBR_ValueToRouteId(0)), 0);
+ ASSERT_EQ(CFE_SBR_IsValidRouteId(CFE_SBR_GetRouteId(CFE_SB_ValueToMsgId(0))), false);
+
+ UtPrintf("Initialize map");
+ CFE_SBR_Init_Map();
+
+ /* Force valid msgid responses */
+ UT_SetForceFail(UT_KEY(CFE_SB_IsValidMsgId), true);
+
+ UtPrintf("Check that all entries are set invalid");
+ count = 0;
+ for (msgidx = 0; msgidx <= CFE_PLATFORM_SB_HIGHEST_VALID_MSGID; msgidx++)
+ {
+ if (!CFE_SBR_IsValidRouteId(CFE_SBR_GetRouteId(CFE_SB_ValueToMsgId(msgidx))))
+ {
+ count++;
+ }
+ }
+ ASSERT_EQ(count, CFE_PLATFORM_SB_HIGHEST_VALID_MSGID + 1);
+
+ UtPrintf("Set/Get a range of ids ");
+ routeid = CFE_SBR_ValueToRouteId(CFE_PLATFORM_SB_MAX_MSG_IDS + 1);
+ msgid = CFE_SB_ValueToMsgId(0);
+ ASSERT_EQ(CFE_SBR_SetRouteId(msgid, routeid), 0);
+ ASSERT_EQ(CFE_SBR_GetRouteId(msgid).RouteId, routeid.RouteId);
+
+ routeid = CFE_SBR_ValueToRouteId(0);
+ msgid = CFE_SB_ValueToMsgId(CFE_PLATFORM_SB_HIGHEST_VALID_MSGID);
+ ASSERT_EQ(CFE_SBR_SetRouteId(msgid, routeid), 0);
+ ASSERT_EQ(CFE_SBR_GetRouteId(msgid).RouteId, routeid.RouteId);
+
+ UtPrintf("Check there is now 1 valid entry in map");
+ count = 0;
+ for (msgidx = 0; msgidx <= CFE_PLATFORM_SB_HIGHEST_VALID_MSGID; msgidx++)
+ {
+ if (!CFE_SBR_IsValidRouteId(CFE_SBR_GetRouteId(CFE_SB_ValueToMsgId(msgidx))))
+ {
+ count++;
+ }
+ }
+ ASSERT_EQ(count, CFE_PLATFORM_SB_HIGHEST_VALID_MSGID);
+
+ UtPrintf("Set back to invalid and check again");
+ routeid = CFE_SBR_INVALID_ROUTE_ID;
+ ASSERT_EQ(CFE_SBR_SetRouteId(msgid, routeid), 0);
+ ASSERT_EQ(CFE_SBR_GetRouteId(msgid).RouteId, routeid.RouteId);
+ ASSERT_EQ(CFE_SBR_IsValidRouteId(CFE_SBR_GetRouteId(msgid)), false);
+
+ /* Performance check, 0xFFFFFF on 3.2GHz linux box is around 8-9 seconds */
+ count = 0;
+ for (i = 0; i <= 0xFFFF; i++)
+ {
+ msgidx = rand() % CFE_PLATFORM_SB_HIGHEST_VALID_MSGID;
+ if (CFE_SBR_IsValidRouteId(CFE_SBR_GetRouteId(CFE_SB_ValueToMsgId(msgidx))))
+ {
+ count++;
+ }
+ }
+ UtPrintf("Valid route id's encountered in performance loop: %u", count);
+}
+
+/* Main unit test routine */
+void UtTest_Setup(void)
+{
+ UT_Init("map_direct");
+ UtPrintf("Software Bus Routing direct map coverage test...");
+
+ UT_ADD_TEST(Test_SBR_Map_Direct);
+}
diff --git a/modules/sbr/unit-test-coverage/test_cfe_sbr_map_hash.c b/modules/sbr/unit-test-coverage/test_cfe_sbr_map_hash.c
new file mode 100644
index 000000000..6e93d257b
--- /dev/null
+++ b/modules/sbr/unit-test-coverage/test_cfe_sbr_map_hash.c
@@ -0,0 +1,118 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** 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.
+*/
+
+/*
+ * Test SBR direct message map implementation
+ */
+
+/*
+ * Includes
+ */
+#include "utassert.h"
+#include "ut_support.h"
+#include "private/cfe_sbr.h"
+#include "cfe_sbr_priv.h"
+
+/*
+ * Defines
+ */
+
+/* Unhash magic number */
+#define CFE_SBR_UNHASH_MAGIC (0x119de1f3)
+
+/******************************************************************************
+ * Local helper to unhash
+ */
+CFE_SB_MsgId_t Test_SBR_Unhash(CFE_SB_MsgId_Atom_t Hash)
+{
+
+ Hash = ((Hash >> 16) ^ Hash) * CFE_SBR_UNHASH_MAGIC;
+ Hash = ((Hash >> 16) ^ Hash) * CFE_SBR_UNHASH_MAGIC;
+ Hash = (Hash >> 16) ^ Hash;
+
+ return CFE_SB_ValueToMsgId(Hash);
+}
+
+void Test_SBR_Map_Hash(void)
+{
+
+ CFE_SB_MsgId_Atom_t msgidx;
+ CFE_SBR_RouteId_t routeid[3];
+ CFE_SB_MsgId_t msgid[3];
+ uint32 count;
+ uint32 collisions;
+
+ UtPrintf("Invalid msg checks");
+ ASSERT_EQ(CFE_SBR_SetRouteId(CFE_SB_ValueToMsgId(0), CFE_SBR_ValueToRouteId(0)), 0);
+ ASSERT_EQ(CFE_SBR_IsValidRouteId(CFE_SBR_GetRouteId(CFE_SB_ValueToMsgId(0))), false);
+
+ UtPrintf("Initialize routing and map");
+ CFE_SBR_Init();
+
+ /* Force valid msgid responses */
+ UT_SetForceFail(UT_KEY(CFE_SB_IsValidMsgId), true);
+
+ UtPrintf("Check that all entries are set invalid");
+ count = 0;
+ for (msgidx = 0; msgidx <= CFE_PLATFORM_SB_HIGHEST_VALID_MSGID; msgidx++)
+ {
+ if (!CFE_SBR_IsValidRouteId(CFE_SBR_GetRouteId(CFE_SB_ValueToMsgId(msgidx))))
+ {
+ count++;
+ }
+ }
+ ASSERT_EQ(count, CFE_PLATFORM_SB_HIGHEST_VALID_MSGID + 1);
+
+ /* Note AddRoute required for hash logic to work since it depends on MsgId in routing table */
+ UtPrintf("Add routes and check with a rollover and a skip");
+ msgid[0] = CFE_SB_ValueToMsgId(0);
+ msgid[1] = Test_SBR_Unhash(0xFFFFFFFF);
+ msgid[2] = Test_SBR_Unhash(0x7FFFFFFF);
+ routeid[0] = CFE_SBR_AddRoute(msgid[0], &collisions);
+ ASSERT_EQ(collisions, 0);
+ routeid[1] = CFE_SBR_AddRoute(msgid[1], &collisions);
+ ASSERT_EQ(collisions, 0);
+ routeid[2] = CFE_SBR_AddRoute(msgid[2], &collisions);
+ ASSERT_EQ(collisions, 2);
+
+ ASSERT_EQ(CFE_SBR_RouteIdToValue(CFE_SBR_GetRouteId(msgid[0])), CFE_SBR_RouteIdToValue(routeid[0]));
+ ASSERT_EQ(CFE_SBR_RouteIdToValue(CFE_SBR_GetRouteId(msgid[1])), CFE_SBR_RouteIdToValue(routeid[1]));
+ ASSERT_EQ(CFE_SBR_RouteIdToValue(CFE_SBR_GetRouteId(msgid[2])), CFE_SBR_RouteIdToValue(routeid[2]));
+
+ /* Performance check, 0xFFFFFF on 3.2GHz linux box is around 8-9 seconds */
+ count = 0;
+ for (msgidx = 0; msgidx <= 0xFFFF; msgidx++)
+ {
+ if (CFE_SBR_IsValidRouteId(CFE_SBR_GetRouteId(CFE_SB_ValueToMsgId(msgidx))))
+ {
+ count++;
+ }
+ }
+ UtPrintf("Valid route id's encountered in performance loop: %u", count);
+}
+
+/* Main unit test routine */
+void UtTest_Setup(void)
+{
+ UT_Init("map_hash");
+ UtPrintf("Software Bus Routing hash map coverage test...");
+
+ UT_ADD_TEST(Test_SBR_Map_Hash);
+}
diff --git a/modules/sbr/unit-test-coverage/test_cfe_sbr_route_unsorted.c b/modules/sbr/unit-test-coverage/test_cfe_sbr_route_unsorted.c
new file mode 100644
index 000000000..ac44c2ec7
--- /dev/null
+++ b/modules/sbr/unit-test-coverage/test_cfe_sbr_route_unsorted.c
@@ -0,0 +1,198 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** 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.
+*/
+
+/*
+ * Test SBR unsorted route implementation
+ */
+
+/*
+ * Includes
+ */
+#include "utassert.h"
+#include "ut_support.h"
+#include "private/cfe_sbr.h"
+#include "cfe_sbr_priv.h"
+
+/* Callback function for testing */
+void Test_SBR_Callback(CFE_SBR_RouteId_t RouteId, void *ArgPtr)
+{
+ uint32 *count = ArgPtr;
+
+ (*count)++;
+}
+
+void Test_SBR_Route_Unsort_General(void)
+{
+
+ CFE_SBR_RouteId_t routeid;
+ CFE_SB_MsgId_t msgid;
+ uint32 collisions;
+ uint32 count;
+ CFE_SBR_Throttle_t throttle;
+
+ UtPrintf("Initialize map and route");
+ CFE_SBR_Init();
+
+ UtPrintf("Invalid msg checks");
+ ASSERT_TRUE(!CFE_SBR_IsValidRouteId(CFE_SBR_AddRoute(CFE_SB_ValueToMsgId(0), NULL)));
+ ASSERT_TRUE(!CFE_SBR_IsValidRouteId(CFE_SBR_AddRoute(CFE_SB_ValueToMsgId(0), &collisions)));
+ ASSERT_EQ(collisions, 0);
+
+ /*
+ * Force valid msgid responses
+ * Note from here on msgids must be in the valid range since validation is forced true
+ * and if the underlying map implentation is direct it needs to be a valid array index
+ */
+ UT_SetForceFail(UT_KEY(CFE_SB_IsValidMsgId), true);
+
+ UtPrintf("Callback test with no routes");
+ count = 0;
+ CFE_SBR_ForEachRouteId(Test_SBR_Callback, &count, NULL);
+ ASSERT_EQ(count, 0);
+
+ UtPrintf("Add maximum mesage id value");
+ msgid = CFE_SB_ValueToMsgId(CFE_PLATFORM_SB_HIGHEST_VALID_MSGID);
+ routeid = CFE_SBR_AddRoute(msgid, &collisions);
+ ASSERT_EQ(collisions, 0);
+ ASSERT_TRUE(CFE_SBR_IsValidRouteId(routeid));
+
+ UtPrintf("Callback test with one route");
+ count = 0;
+ CFE_SBR_ForEachRouteId(Test_SBR_Callback, &count, NULL);
+ ASSERT_EQ(count, 1);
+
+ UtPrintf("Fill routing table");
+ count = 0;
+ while (CFE_SBR_IsValidRouteId(CFE_SBR_AddRoute(CFE_SB_ValueToMsgId(count), NULL)))
+ {
+ count++;
+ }
+
+ /* Check for expected count indicating full routing table */
+ ASSERT_EQ(count + 1, CFE_PLATFORM_SB_MAX_MSG_IDS);
+
+ /* Try one more for good luck */
+ ASSERT_TRUE(!CFE_SBR_IsValidRouteId(CFE_SBR_AddRoute(CFE_SB_ValueToMsgId(count), NULL)));
+
+ /* Check that maximum msgid is still in the table */
+ ASSERT_EQ(CFE_SB_MsgIdToValue(CFE_SBR_GetMsgId(routeid)), CFE_PLATFORM_SB_HIGHEST_VALID_MSGID);
+ ASSERT_EQ(CFE_SBR_GetRouteId(msgid).RouteId, routeid.RouteId);
+
+ UtPrintf("Callback test with full route");
+ count = 0;
+ CFE_SBR_ForEachRouteId(Test_SBR_Callback, &count, NULL);
+ ASSERT_EQ(count, CFE_PLATFORM_SB_MAX_MSG_IDS);
+
+ UtPrintf("Callback test throttled");
+ throttle.MaxLoop = CFE_PLATFORM_SB_MAX_MSG_IDS - 1;
+ throttle.StartIndex = 0;
+ count = 0;
+ CFE_SBR_ForEachRouteId(Test_SBR_Callback, &count, &throttle);
+ ASSERT_EQ(count, CFE_PLATFORM_SB_MAX_MSG_IDS - 1);
+ count = 0;
+ throttle.StartIndex = throttle.NextIndex;
+ CFE_SBR_ForEachRouteId(Test_SBR_Callback, &count, &throttle);
+ ASSERT_EQ(count, 1);
+}
+
+void Test_SBR_Route_Unsort_GetSet(void)
+{
+
+ CFE_SB_RouteId_Atom_t routeidx;
+ CFE_SB_MsgId_t msgid[3];
+ CFE_SBR_RouteId_t routeid[3];
+ CFE_SB_DestinationD_t dest[2];
+ uint32 count;
+ uint32 i;
+
+ UtPrintf("Invalid route ID checks");
+ routeid[0] = CFE_SBR_INVALID_ROUTE_ID;
+ routeid[1] = CFE_SBR_ValueToRouteId(CFE_PLATFORM_SB_MAX_MSG_IDS);
+ for (i = 0; i < 2; i++)
+ {
+ ASSERT_TRUE(CFE_SB_MsgId_Equal(CFE_SBR_GetMsgId(routeid[i]), CFE_SB_INVALID_MSG_ID));
+ UtAssert_ADDRESS_EQ(CFE_SBR_GetDestListHeadPtr(routeid[i]), NULL);
+ ASSERT_EQ(CFE_SBR_GetSequenceCounter(routeid[i]), 0);
+ }
+
+ /*
+ * Force valid msgid responses
+ * Note from here on msgids must be in the valid range since validation is forced true
+ * and if the underlying map implentation is direct it needs to be a valid array index
+ */
+ UT_SetForceFail(UT_KEY(CFE_SB_IsValidMsgId), true);
+
+ UtPrintf("Initialize map and route");
+ CFE_SBR_Init();
+
+ UtPrintf("Confirm values initialized for all routes");
+ count = 0;
+ for (routeidx = 0; routeidx < CFE_PLATFORM_SB_MAX_MSG_IDS; routeidx++)
+ {
+ routeid[0] = CFE_SBR_ValueToRouteId(routeidx);
+ if (!CFE_SB_MsgId_Equal(CFE_SBR_GetMsgId(routeid[0]), CFE_SB_INVALID_MSG_ID) ||
+ (CFE_SBR_GetDestListHeadPtr(routeid[0]) != NULL) || (CFE_SBR_GetSequenceCounter(routeid[0]) != 0))
+ {
+ count++;
+ }
+ }
+ ASSERT_EQ(count, 0);
+
+ UtPrintf("Add routes and initialize values for testing");
+ msgid[0] = CFE_SB_ValueToMsgId(0);
+ msgid[1] = CFE_SB_ValueToMsgId(1);
+ msgid[2] = CFE_SB_ValueToMsgId(CFE_PLATFORM_SB_HIGHEST_VALID_MSGID);
+
+ /* Add routes */
+ for (i = 0; i < 3; i++)
+ {
+ routeid[i] = CFE_SBR_AddRoute(msgid[i], NULL);
+ }
+
+ /* Check the msgid matches and increment a sequence counter */
+ for (i = 0; i < 3; i++)
+ {
+ ASSERT_TRUE(CFE_SB_MsgId_Equal(msgid[i], CFE_SBR_GetMsgId(routeid[i])));
+ CFE_SBR_IncrementSequenceCounter(routeid[0]);
+ }
+
+ /* Increment route 1 once and set dest pointers */
+ CFE_SBR_IncrementSequenceCounter(routeid[1]);
+ CFE_SBR_SetDestListHeadPtr(routeid[1], &dest[1]);
+ CFE_SBR_SetDestListHeadPtr(routeid[2], &dest[0]);
+
+ UtPrintf("Verify remaining set values");
+ ASSERT_EQ(CFE_SBR_GetSequenceCounter(routeid[0]), 3);
+ ASSERT_EQ(CFE_SBR_GetSequenceCounter(routeid[1]), 1);
+ ASSERT_EQ(CFE_SBR_GetSequenceCounter(routeid[2]), 0);
+ UtAssert_ADDRESS_EQ(CFE_SBR_GetDestListHeadPtr(routeid[0]), NULL);
+ UtAssert_ADDRESS_EQ(CFE_SBR_GetDestListHeadPtr(routeid[1]), &dest[1]);
+ UtAssert_ADDRESS_EQ(CFE_SBR_GetDestListHeadPtr(routeid[2]), &dest[0]);
+}
+
+/* Main unit test routine */
+void UtTest_Setup(void)
+{
+ UT_Init("route_unsort");
+ UtPrintf("Software Bus Routing unsorted coverage test...");
+
+ UT_ADD_TEST(Test_SBR_Route_Unsort_General);
+ UT_ADD_TEST(Test_SBR_Route_Unsort_GetSet);
+}