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 76e45c0d9..369ef3233 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); +}