diff --git a/modules/core_api/fsw/inc/cfe_sb.h b/modules/core_api/fsw/inc/cfe_sb.h
new file mode 100644
index 000000000..ebcdc01bb
--- /dev/null
+++ b/modules/core_api/fsw/inc/cfe_sb.h
@@ -0,0 +1,834 @@
+/*
+** 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
+ *
+ * Purpose:
+ * This header file contains all definitions for the cFE Software Bus
+ * Application Programmer's Interface.
+ *
+ * Author: R.McGraw/SSI
+ *
+ */
+
+#ifndef CFE_SB_H
+#define CFE_SB_H
+
+/*
+** Includes
+*/
+#include "common_types.h"
+#include "cfe_error.h"
+#include "cfe_sb_api_typedefs.h"
+#include "cfe_es_api_typedefs.h"
+
+/*
+** Macro Definitions
+*/
+#define CFE_BIT(x) (1 << (x)) /**< \brief Places a one at bit positions 0 - 31*/
+#define CFE_SET(i, x) ((i) |= CFE_BIT(x)) /**< \brief Sets bit x of i */
+#define CFE_CLR(i, x) ((i) &= ~CFE_BIT(x)) /**< \brief Clears bit x of i */
+#define CFE_TST(i, x) (((i)&CFE_BIT(x)) != 0) /**< \brief true(non zero) if bit x of i is set */
+
+/****************** Function Prototypes **********************/
+
+/** @defgroup CFEAPISBPipe cFE Pipe Management APIs
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+** \brief Creates a new software bus pipe.
+**
+** \par Description
+** This routine creates and initializes an input pipe that the calling
+** application can use to receive software bus messages. By default, no
+** messages are routed to the new pipe. So, the application must use
+** #CFE_SB_Subscribe to specify which messages it wants to receive on
+** this pipe.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in, out] PipeIdPtr A pointer to a variable of type #CFE_SB_PipeId_t,
+** which will be filled in with the pipe ID information
+** by the #CFE_SB_CreatePipe routine. *PipeIdPtr is the identifier for the created pipe.
+**
+** \param[in] Depth The maximum number of messages that will be allowed on
+** this pipe at one time.
+**
+** \param[in] PipeName A string to be used to identify this pipe in error messages
+** and routing information telemetry. The string must be no
+** longer than #OS_MAX_API_NAME (including terminator).
+** Longer strings will be truncated.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_SB_BAD_ARGUMENT \copybrief CFE_SB_BAD_ARGUMENT
+** \retval #CFE_SB_MAX_PIPES_MET \copybrief CFE_SB_MAX_PIPES_MET
+** \retval #CFE_SB_PIPE_CR_ERR \copybrief CFE_SB_PIPE_CR_ERR
+**
+** \sa #CFE_SB_DeletePipe #CFE_SB_GetPipeOpts #CFE_SB_SetPipeOpts #CFE_SB_GetPipeIdByName
+**/
+CFE_Status_t CFE_SB_CreatePipe(CFE_SB_PipeId_t *PipeIdPtr, uint16 Depth, const char *PipeName);
+
+/*****************************************************************************/
+/**
+** \brief Delete a software bus pipe.
+**
+** \par Description
+** This routine deletes an input pipe and cleans up all data structures
+** associated with the pipe. All subscriptions made for this pipe by
+** calls to #CFE_SB_Subscribe will be automatically removed from the
+** SB routing tables. Any messages in the pipe will be discarded.
+**
+** Applications should not call this routine for all of their
+** SB pipes as part of their orderly shutdown process, as the
+** pipe will be deleted by the support framework at the
+** appropriate time.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] PipeId The pipe ID (obtained previously from #CFE_SB_CreatePipe)
+** of the pipe to be deleted.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_SB_BAD_ARGUMENT \copybrief CFE_SB_BAD_ARGUMENT
+**
+** \sa #CFE_SB_CreatePipe #CFE_SB_GetPipeOpts #CFE_SB_SetPipeOpts #CFE_SB_GetPipeIdByName
+**/
+CFE_Status_t CFE_SB_DeletePipe(CFE_SB_PipeId_t PipeId);
+
+/**
+ * @brief Obtain an index value correlating to an SB Pipe ID
+ *
+ * This calculates a zero based integer value that may be used for indexing
+ * into a local resource table/array.
+ *
+ * Index values are only guaranteed to be unique for resources of the same
+ * type. For instance, the indices corresponding to two [valid] application
+ * IDs will never overlap, but the index of a pipe ID and an app ID
+ * may be the same. Furthermore, indices may be reused if a resource is
+ * deleted and re-created.
+ *
+ * @note There is no inverse of this function - indices cannot be converted
+ * back to the original PipeID value. The caller should retain the original ID
+ * for future use.
+ *
+ * @param[in] PipeID Pipe ID to convert
+ * @param[out] Idx Buffer where the calculated index will be stored
+ *
+ * @return Execution status, see @ref CFEReturnCodes
+ * @retval #CFE_SUCCESS @copybrief CFE_SUCCESS
+ * @retval #CFE_ES_ERR_RESOURCEID_NOT_VALID @copybrief CFE_ES_ERR_RESOURCEID_NOT_VALID
+ */
+CFE_Status_t CFE_SB_PipeId_ToIndex(CFE_SB_PipeId_t PipeID, uint32 *Idx);
+
+/*****************************************************************************/
+/**
+** \brief Set options on a pipe.
+**
+** \par Description
+** This routine sets (or clears) options to alter the pipe's behavior.
+** Options are (re)set every call to this routine.
+**
+** \param[in] PipeId The pipe ID of the pipe to set options on.
+**
+** \param[in] Opts A bit field of options.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_SB_BAD_ARGUMENT \copybrief CFE_SB_BAD_ARGUMENT
+**
+** \sa #CFE_SB_CreatePipe #CFE_SB_DeletePipe #CFE_SB_GetPipeOpts #CFE_SB_GetPipeIdByName #CFE_SB_PIPEOPTS_IGNOREMINE
+**/
+CFE_Status_t CFE_SB_SetPipeOpts(CFE_SB_PipeId_t PipeId, uint8 Opts);
+
+/*****************************************************************************/
+/**
+** \brief Get options on a pipe.
+**
+** \par Description
+** This routine gets the current options on a pipe.
+**
+** \param[in] PipeId The pipe ID of the pipe to get options from.
+**
+** \param[out] *OptPtr A bit field of options.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_SB_BAD_ARGUMENT \copybrief CFE_SB_BAD_ARGUMENT
+**
+** \sa #CFE_SB_CreatePipe #CFE_SB_DeletePipe #CFE_SB_SetPipeOpts #CFE_SB_GetPipeIdByName #CFE_SB_PIPEOPTS_IGNOREMINE
+**/
+CFE_Status_t CFE_SB_GetPipeOpts(CFE_SB_PipeId_t PipeId, uint8 *OptPtr);
+
+/*****************************************************************************/
+/**
+** \brief Get the pipe name for a given id.
+**
+** \par Description
+** This routine finds the pipe name for a pipe id.
+**
+** \param[out] PipeNameBuf The buffer to receive the pipe name.
+**
+** \param[in] PipeNameSize The size (in chars) of the PipeName buffer.
+**
+** \param[in] PipeId The PipeId for that name.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_SB_BAD_ARGUMENT \copybrief CFE_SB_BAD_ARGUMENT
+**
+** \sa #CFE_SB_CreatePipe #CFE_SB_DeletePipe #CFE_SB_SetPipeOpts #CFE_SB_GetPipeIdByName
+**/
+CFE_Status_t CFE_SB_GetPipeName(char *PipeNameBuf, size_t PipeNameSize, CFE_SB_PipeId_t PipeId);
+
+/*****************************************************************************/
+/**
+** \brief Get pipe id by pipe name.
+**
+** \par Description
+** This routine finds the pipe id for a pipe name.
+**
+** \param[in] PipeName The name of the pipe.
+**
+** \param[out] PipeIdPtr The PipeId for that name.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_SB_BAD_ARGUMENT \copybrief CFE_SB_BAD_ARGUMENT
+**
+** \sa #CFE_SB_CreatePipe #CFE_SB_DeletePipe #CFE_SB_SetPipeOpts #CFE_SB_PIPEOPTS_IGNOREMINE
+**/
+CFE_Status_t CFE_SB_GetPipeIdByName(CFE_SB_PipeId_t *PipeIdPtr, const char *PipeName);
+/**@}*/
+
+/** @defgroup CFEAPISBSubscription cFE Message Subscription Control APIs
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+** \brief Subscribe to a message on the software bus
+**
+** \par Description
+** This routine adds the specified pipe to the destination list associated
+** with the specified message ID.
+**
+** \par Assumptions, External Events, and Notes:
+** Note: As subscriptions are received, the destinations are added to
+** the head of a linked list. During the sending of a message, the list
+** is traversed beginning at the head of the list. Therefore the
+** message will first be sent to the last subscriber. If an application
+** has timing constraints and needs to receive a message in the
+** shortest possible time, the developer may consider holding off its
+** subscription until other applications have subscribed to the message.
+**
+** \param[in] MsgId The message ID of the message to be subscribed to.
+**
+** \param[in] PipeId The pipe ID of the pipe the subscribed message
+** should be sent to.
+**
+** \param[in] Quality The requested Quality of Service (QoS) required of
+** the messages. Most callers will use #CFE_SB_DEFAULT_QOS
+** for this parameter.
+**
+** \param[in] MsgLim The maximum number of messages with this Message ID to
+** allow in this pipe at the same time.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_SB_MAX_MSGS_MET \copybrief CFE_SB_MAX_MSGS_MET
+** \retval #CFE_SB_MAX_DESTS_MET \copybrief CFE_SB_MAX_DESTS_MET
+** \retval #CFE_SB_BAD_ARGUMENT \copybrief CFE_SB_BAD_ARGUMENT
+** \retval #CFE_SB_BUF_ALOC_ERR \copybrief CFE_SB_BUF_ALOC_ERR
+**
+** \sa #CFE_SB_Subscribe, #CFE_SB_SubscribeLocal, #CFE_SB_Unsubscribe, #CFE_SB_UnsubscribeLocal
+**/
+CFE_Status_t CFE_SB_SubscribeEx(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId, CFE_SB_Qos_t Quality, uint16 MsgLim);
+
+/*****************************************************************************/
+/**
+** \brief Subscribe to a message on the software bus with default parameters
+**
+** \par Description
+** This routine adds the specified pipe to the destination list for
+** the specified message ID. This is the same as #CFE_SB_SubscribeEx
+** with the Quality field set to #CFE_SB_DEFAULT_QOS and MsgLim set
+** to #CFE_PLATFORM_SB_DEFAULT_MSG_LIMIT (4).
+**
+** \par Assumptions, External Events, and Notes:
+** Note: As subscriptions are received, the destinations are added to
+** the head of a linked list. During the sending of a message, the list
+** is traversed beginning at the head of the list. Therefore the
+** message will first be sent to the last subscriber. If an application
+** has timing constraints and needs to receive a message in the
+** shortest possible time, the developer may consider holding off its
+** subscription until other applications have subscribed to the message.
+**
+** \param[in] MsgId The message ID of the message to be subscribed to.
+**
+** \param[in] PipeId The pipe ID of the pipe the subscribed message
+** should be sent to.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_SB_MAX_MSGS_MET \copybrief CFE_SB_MAX_MSGS_MET
+** \retval #CFE_SB_MAX_DESTS_MET \copybrief CFE_SB_MAX_DESTS_MET
+** \retval #CFE_SB_BAD_ARGUMENT \copybrief CFE_SB_BAD_ARGUMENT
+** \retval #CFE_SB_BUF_ALOC_ERR \copybrief CFE_SB_BUF_ALOC_ERR
+**
+** \sa #CFE_SB_SubscribeEx, #CFE_SB_SubscribeLocal, #CFE_SB_Unsubscribe, #CFE_SB_UnsubscribeLocal
+**/
+CFE_Status_t CFE_SB_Subscribe(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId);
+
+/*****************************************************************************/
+/**
+** \brief Subscribe to a message while keeping the request local to a cpu
+**
+** \par Description
+** This routine adds the specified pipe to the destination list for
+** the specified message ID. This is similar to #CFE_SB_SubscribeEx
+** with the Quality field set to #CFE_SB_DEFAULT_QOS and MsgLim set
+** to #CFE_PLATFORM_SB_DEFAULT_MSG_LIMIT, but will not report the subscription.
+** Subscription Reporting is enabled for interprocessor communication
+** by way of the Software Bus Network (SBN) Application.
+**
+** \par Assumptions, External Events, and Notes:
+** - This API is typically only used by Software Bus Network (SBN) Application
+**
+** \param[in] MsgId The message ID of the message to be subscribed to.
+**
+** \param[in] PipeId The pipe ID of the pipe the subscribed message
+** should be sent to.
+**
+** \param[in] MsgLim The maximum number of messages with this Message ID to
+** allow in this pipe at the same time.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_SB_MAX_MSGS_MET \copybrief CFE_SB_MAX_MSGS_MET
+** \retval #CFE_SB_MAX_DESTS_MET \copybrief CFE_SB_MAX_DESTS_MET
+** \retval #CFE_SB_BAD_ARGUMENT \copybrief CFE_SB_BAD_ARGUMENT
+** \retval #CFE_SB_BUF_ALOC_ERR \copybrief CFE_SB_BUF_ALOC_ERR
+**
+** \sa #CFE_SB_Subscribe, #CFE_SB_SubscribeEx, #CFE_SB_Unsubscribe, #CFE_SB_UnsubscribeLocal
+**/
+CFE_Status_t CFE_SB_SubscribeLocal(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId, uint16 MsgLim);
+
+/*****************************************************************************/
+/**
+** \brief Remove a subscription to a message on the software bus
+**
+** \par Description
+** This routine removes the specified pipe from the destination
+** list for the specified message ID.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] MsgId The message ID of the message to be unsubscribed.
+**
+** \param[in] PipeId The pipe ID of the pipe the subscribed message
+** should no longer be sent to.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_SB_NO_SUBSCRIBERS \copybrief CFE_SB_NO_SUBSCRIBERS
+** \retval #CFE_SB_INTERNAL_ERR \copybrief CFE_SB_INTERNAL_ERR
+**
+** \sa #CFE_SB_Subscribe, #CFE_SB_SubscribeEx, #CFE_SB_SubscribeLocal, #CFE_SB_UnsubscribeLocal
+**/
+CFE_Status_t CFE_SB_Unsubscribe(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId);
+
+/*****************************************************************************/
+/**
+** \brief Remove a subscription to a message on the software bus on the current CPU
+**
+** \par Description
+** This routine removes the specified pipe from the destination
+** list for the specified message ID on the current CPU.
+**
+** \par Assumptions, External Events, and Notes:
+** - This API is typically only used by Software Bus Network (SBN) Application
+**
+** \param[in] MsgId The message ID of the message to be unsubscribed.
+**
+** \param[in] PipeId The pipe ID of the pipe the subscribed message
+** should no longer be sent to.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_SB_NO_SUBSCRIBERS \copybrief CFE_SB_NO_SUBSCRIBERS
+** \retval #CFE_SB_INTERNAL_ERR \copybrief CFE_SB_INTERNAL_ERR
+**
+** \sa #CFE_SB_Subscribe, #CFE_SB_SubscribeEx, #CFE_SB_SubscribeLocal, #CFE_SB_Unsubscribe
+**/
+CFE_Status_t CFE_SB_UnsubscribeLocal(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId);
+/**@}*/
+
+/** @defgroup CFEAPISBMessage cFE Send/Receive Message APIs
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+** \brief Transmit a message
+**
+** \par Description
+** This routine copies the specified message into a software bus
+** buffer which is then transmitted to all subscribers. The
+** software bus will read the message ID from the message header to
+** determine which pipes should receive the message.
+**
+** \par Assumptions, External Events, and Notes:
+** - This routine will not normally wait for the receiver tasks to
+** process the message before returning control to the caller's task.
+** - However, if a higher priority task is pending and subscribed to
+** this message, that task may get to run before returning
+** control to the caller.
+**
+** \param[in] MsgPtr A pointer to the message to be sent. This must point
+** to the first byte of the message header.
+** \param[in] IncrementSequenceCount Boolean to increment the internally tracked
+** sequence count and update the message if the
+** buffer contains a telemetry message
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_SB_BAD_ARGUMENT \copybrief CFE_SB_BAD_ARGUMENT
+** \retval #CFE_SB_MSG_TOO_BIG \copybrief CFE_SB_MSG_TOO_BIG
+** \retval #CFE_SB_BUF_ALOC_ERR \copybrief CFE_SB_BUF_ALOC_ERR
+**/
+CFE_Status_t CFE_SB_TransmitMsg(CFE_MSG_Message_t *MsgPtr, bool IncrementSequenceCount);
+
+/*****************************************************************************/
+/**
+** \brief Receive a message from a software bus pipe
+**
+** \par Description
+** This routine retrieves the next message from the specified pipe.
+** If the pipe is empty, this routine will block until either a new
+** message comes in or the timeout value is reached.
+**
+** \par Assumptions, External Events, and Notes:
+** Note - If an error occurs in this API, the *BufPtr value may be NULL or
+** random. Therefore, it is recommended that the return code be tested
+** for CFE_SUCCESS before processing the message.
+**
+** \param[in, out] BufPtr A pointer to the software bus buffer to receive to.
+** Typically a caller declares a ptr of type CFE_SB_Buffer_t
+** (i.e. CFE_SB_Buffer_t *Ptr) then gives the address of that
+** pointer (&Ptr) as this parmeter. After a successful
+** receipt of a message, *BufPtr will point to the first
+** byte of the software bus buffer. This should be
+** used as a read-only pointer (in systems with an MMU,
+** writes to this pointer may cause a memory protection fault).
+** The *BufPtr is valid only until the next call to
+** CFE_SB_ReceiveBuffer for the same pipe.
+**
+** \param[in] PipeId The pipe ID of the pipe containing the message to be obtained.
+**
+** \param[in] TimeOut The number of milliseconds to wait for a new message if the
+** pipe is empty at the time of the call. This can also be set
+** to #CFE_SB_POLL for a non-blocking receive or
+** #CFE_SB_PEND_FOREVER to wait forever for a message to arrive.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_SB_BAD_ARGUMENT \copybrief CFE_SB_BAD_ARGUMENT
+** \retval #CFE_SB_TIME_OUT \copybrief CFE_SB_TIME_OUT
+** \retval #CFE_SB_PIPE_RD_ERR \copybrief CFE_SB_PIPE_RD_ERR
+** \retval #CFE_SB_NO_MESSAGE \copybrief CFE_SB_NO_MESSAGE
+**/
+CFE_Status_t CFE_SB_ReceiveBuffer(CFE_SB_Buffer_t **BufPtr, CFE_SB_PipeId_t PipeId, int32 TimeOut);
+/** @} */
+
+/** @defgroup CFEAPISBZeroCopy cFE Zero Copy APIs
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+** \brief Get a buffer pointer to use for "zero copy" SB sends.
+**
+** \par Description
+** This routine can be used to get a pointer to one of the software bus'
+** internal memory buffers that are used for sending messages. The caller
+** can use this memory buffer to build an SB message, then send it using
+** the CFE_SB_TransmitBuffer() function. This interface avoids an extra
+** copy of the message from the user's memory buffer to the software bus
+** internal buffer.
+**
+** \par Assumptions, External Events, and Notes:
+** -# The pointer returned by CFE_SB_AllocateMessageBuffer() is only good for one
+** call to CFE_SB_TransmitBuffer().
+** -# Once a buffer has been successfully transmitted (as indicated by a successful
+** return from CFE_SB_TransmitBuffer()) the buffer becomes owned by the SB application.
+** It will automatically be freed by SB once all recipients have finished reading it.
+** -# Applications must not de-reference the message pointer (for reading
+** or writing) after the call to CFE_SB_TransmitBuffer().
+**
+** \param[in] MsgSize The size of the SB message buffer the caller wants
+** (including the SB message header).
+**
+** \return A pointer to a memory buffer that message data can be written to
+** for use with CFE_SB_TransmitBuffer().
+**/
+CFE_SB_Buffer_t *CFE_SB_AllocateMessageBuffer(size_t MsgSize);
+
+/*****************************************************************************/
+/**
+** \brief Release an unused "zero copy" buffer pointer.
+**
+** \par Description
+** This routine can be used to release a pointer to one of the software
+** bus' internal memory buffers.
+**
+** \par Assumptions, External Events, and Notes:
+** -# This function is not needed for normal "zero copy" transfers. It
+** is needed only for cleanup when an application gets a pointer using
+** CFE_SB_AllocateMessageBuffer(), but (due to some error condition) never
+** uses that pointer in a call to CFE_SB_TransmitBuffer().
+**
+** \param[in] BufPtr A pointer to the SB internal buffer. This must be a
+** pointer returned by a call to CFE_SB_AllocateMessageBuffer(),
+** but never used in a call to CFE_SB_TransmitBuffer().
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_SB_BUFFER_INVALID \copybrief CFE_SB_BUFFER_INVALID
+**/
+CFE_Status_t CFE_SB_ReleaseMessageBuffer(CFE_SB_Buffer_t *BufPtr);
+
+/*****************************************************************************/
+/**
+** \brief Transmit a buffer
+**
+** \par Description
+** This routine sends a message that has been created directly in an
+** internal SB message buffer by an application (after a call to
+** #CFE_SB_AllocateMessageBuffer). This interface is more complicated than
+** the normal #CFE_SB_TransmitMsg interface, but it avoids an extra copy of
+** the message from the user's memory buffer to the software bus
+** internal buffer. The "zero copy" interface can be used to improve
+** performance in high-rate, high-volume software bus traffic.
+**
+** \par Assumptions, External Events, and Notes:
+** -# A handle returned by #CFE_SB_AllocateMessageBuffer is "consumed" by
+** a _successful_ call to #CFE_SB_TransmitBuffer.
+** -# If this function returns CFE_SUCCESS, this indicates the zero copy handle is
+** now owned by software bus, and is no longer owned by the calling application,
+** and should not be re-used.
+** -# Howver if this function fails (returns any error status) it does not change
+** the state of the buffer at all, meaning the calling application still owns it.
+** (a failure means the buffer is left in the same state it was before the call).
+** -# Applications should be written as if #CFE_SB_AllocateMessageBuffer is
+** equivalent to a \c malloc() and a successful call to #CFE_SB_TransmitBuffer
+** is equivalent to a \c free().
+** -# Applications must not de-reference the message pointer (for reading
+** or writing) after a successful call to #CFE_SB_TransmitBuffer.
+** -# This function will increment and apply the internally tracked
+** sequence counter if set to do so.
+**
+** \param[in] BufPtr A pointer to the buffer to be sent.
+** \param[in] IncrementSequenceCount Boolean to increment the internally tracked
+** sequence count and update the message if the
+** buffer contains a telemetry message
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_SB_BAD_ARGUMENT \copybrief CFE_SB_BAD_ARGUMENT
+** \retval #CFE_SB_MSG_TOO_BIG \copybrief CFE_SB_MSG_TOO_BIG
+**/
+CFE_Status_t CFE_SB_TransmitBuffer(CFE_SB_Buffer_t *BufPtr, bool IncrementSequenceCount);
+
+/** @} */
+
+/** @defgroup CFEAPISBSetMessage cFE Setting Message Characteristics APIs
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+** \brief Sets the length of user data in a software bus message.
+**
+** \par Description
+** This routine sets the field in the SB message header that determines
+** the size of the user data in a software bus message. SB message header
+** formats can be different for each deployment of the cFE. So, applications
+** should use this function rather than trying to poke a length value directly
+** into their SB message buffers.
+**
+** \par Assumptions, External Events, and Notes:
+** - You must set a valid message ID in the SB message header before
+** calling this function.
+**
+** \param[in] MsgPtr A pointer to the buffer that contains the software bus message.
+** This must point to the first byte of the message header.
+**
+** \param[in] DataLength The length to set (size of the user data, in bytes).
+**/
+void CFE_SB_SetUserDataLength(CFE_MSG_Message_t *MsgPtr, size_t DataLength);
+
+/*****************************************************************************/
+/**
+** \brief Sets the time field in a software bus message with the current spacecraft time.
+**
+** \par Description
+** This routine sets the time of a software bus message with the current
+** spacecraft time. This will be the same time that is returned by the
+** function #CFE_TIME_GetTime.
+**
+** \par Assumptions, External Events, and Notes:
+** - If the underlying implementation of software bus messages does not
+** include a time field, then this routine will do nothing.
+**
+** \param[in] MsgPtr A pointer to the buffer that contains the software bus message.
+** This must point to the first byte of the message header.
+**/
+void CFE_SB_TimeStampMsg(CFE_MSG_Message_t *MsgPtr);
+
+/******************************************************************************/
+/**
+** \brief Copies a string into a software bus message
+**
+** \par Description
+** Strings within software bus messages have a defined/fixed maximum length, and
+** may not necessarily be null terminated within the message. This presents a possible
+** issue when using the C library functions to copy strings out of a message.
+**
+** This performs a very similar function to "strncpy()" except that the sizes
+** of _both_ buffers are passed in. Neither buffer is required to be null-terminated,
+** but copying will stop after the first termination character is encountered.
+**
+** If the destination buffer is not completely filled by the source data (such as if
+** the supplied string was shorter than the allotted length) the destination buffer
+** will be padded with NUL characters up to the size of the buffer, similar to what
+** strncpy() does. This ensures that the entire destination buffer is set.
+**
+** \note
+** If the source string buffer is already guaranteed to be null terminated,
+** then there is no difference between the C library "strncpy()" function and this
+** implementation. It is only necessary to use this when termination of the source
+** buffer is not guaranteed.
+**
+** \param[out] DestStringPtr Pointer to destination buffer (component of SB message definition)
+** \param[in] SourceStringPtr Pointer to source buffer
+** \param[in] DestMaxSize Size of destination buffer as defined by the message definition
+** \param[in] SourceMaxSize Size of source buffer
+**
+** \return Number of characters copied or error code, see \ref CFEReturnCodes
+**
+*/
+int32 CFE_SB_MessageStringSet(char *DestStringPtr, const char *SourceStringPtr, size_t DestMaxSize,
+ size_t SourceMaxSize);
+/** @} */
+
+/** @defgroup CFEAPIGetMessage cFE Getting Message Characteristics APIs
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+** \brief Get a pointer to the user data portion of a software bus message.
+**
+** \par Description
+** This routine returns a pointer to the user data portion of a software
+** bus message. SB message header formats can be different for each
+** deployment of the cFE. So, applications should use this function and
+** avoid hard coding offsets into their SB message buffers.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] MsgPtr A pointer to the buffer that contains the software bus message.
+**
+** \return A pointer to the first byte of user data within the software bus message.
+**/
+void *CFE_SB_GetUserData(CFE_MSG_Message_t *MsgPtr);
+
+/*****************************************************************************/
+/**
+** \brief Gets the length of user data in a software bus message.
+**
+** \par Description
+** This routine returns the size of the user data in a software bus message.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] MsgPtr A pointer to the buffer that contains the software bus message.
+** This must point to the first byte of the message header.
+**
+** \return The size (in bytes) of the user data in the software bus message.
+**/
+size_t CFE_SB_GetUserDataLength(const CFE_MSG_Message_t *MsgPtr);
+
+/******************************************************************************/
+/**
+** \brief Copies a string out of a software bus message
+**
+** \par Description
+** Strings within software bus messages have a defined/fixed maximum length, and
+** may not necessarily be null terminated within the message. This presents a possible
+** issue when using the C library functions to copy strings out of a message.
+**
+** This function should replace use of C library functions such as strcpy/strncpy
+** when copying strings out of software bus messages to local storage buffers.
+**
+** Up to [SourceMaxSize] or [DestMaxSize-1] (whichever is smaller) characters will be
+** coped from the source buffer to the destination buffer, and a NUL termination
+** character will be written to the destination buffer as the last character.
+**
+** If the DefaultString pointer is non-NULL, it will be used in place of the source
+** string if the source is an empty string. This is typically a string constant that
+** comes from the platform configuration, allowing default values to be assumed for
+** fields that are unspecified.
+**
+** IMPORTANT - the default string, if specified, must be null terminated. This will
+** be the case if a string literal is passed in (the typical/expected use case).
+**
+** If the default is NULL, then only the source string will be copied, and the result
+** will be an empty string if the source was empty.
+**
+** If the destination buffer is too small to store the entire string, it will be
+** truncated, but it will still be null terminated.
+**
+** \param[out] DestStringPtr Pointer to destination buffer
+** \param[in] SourceStringPtr Pointer to source buffer (component of SB message definition)
+** \param[in] DefaultString Default string to use if source is empty
+** \param[in] DestMaxSize Size of destination storage buffer (must be at least 2)
+** \param[in] SourceMaxSize Size of source buffer as defined by the message definition
+**
+** \return Number of characters copied or error code, see \ref CFEReturnCodes
+**
+*/
+int32 CFE_SB_MessageStringGet(char *DestStringPtr, const char *SourceStringPtr, const char *DefaultString,
+ size_t DestMaxSize, size_t SourceMaxSize);
+/** @} */
+
+/** @defgroup CFEAPISBMessageID cFE Message ID APIs
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+ * \brief Identifies whether a given CFE_SB_MsgId_t is valid
+ *
+ * \par Description
+ * Implements a basic sanity check on the value provided
+ *
+ * \return Boolean message ID validity indicator
+ * \retval true Message ID is within the valid range
+ * \retval false Message ID is not within the valid range
+ */
+bool CFE_SB_IsValidMsgId(CFE_SB_MsgId_t MsgId);
+
+/*****************************************************************************/
+/**
+ * \brief Identifies whether two #CFE_SB_MsgId_t values are equal
+ *
+ * \par Description
+ * In cases where the #CFE_SB_MsgId_t type is not a simple integer
+ * type, it may not be possible to do a direct equality check.
+ * This inline function provides an abstraction for the equality
+ * check between two #CFE_SB_MsgId_t values.
+ *
+ * Applications should transition to using this function to compare
+ * MsgId values for equality to remain compatible with future versions
+ * of cFE.
+ *
+ * \return Boolean message ID equality indicator
+ * \retval true Message IDs are Equal
+ * \retval false Message IDs are not Equal
+ */
+static inline bool CFE_SB_MsgId_Equal(CFE_SB_MsgId_t MsgId1, CFE_SB_MsgId_t MsgId2)
+{
+ return CFE_SB_MSGID_UNWRAP_VALUE(MsgId1) == CFE_SB_MSGID_UNWRAP_VALUE(MsgId2);
+}
+
+/*****************************************************************************/
+/**
+ * \brief Converts a #CFE_SB_MsgId_t to a normal integer
+ *
+ * \par Description
+ * In cases where the #CFE_SB_MsgId_t type is not a simple integer
+ * type, it is not possible to directly display the value in a
+ * printf-style statement, use it in a switch() statement, or other
+ * similar use cases.
+ *
+ * This inline function provides the ability to map a #CFE_SB_MsgId_t
+ * type back into a simple integer value.
+ *
+ * Applications should transition to using this function wherever a
+ * #CFE_SB_MsgId_t type needs to be used as an integer.
+ *
+ * \par Assumptions and Notes:
+ * This negates the type safety that was gained by using a non-
+ * integer type for the #CFE_SB_MsgId_t value. This should only be used
+ * in specific cases such as UI display (printf, events, etc) where the
+ * value is being sent externally. Any internal API calls should be
+ * updated to use the #CFE_SB_MsgId_t type directly, rather than an
+ * integer type.
+ *
+ * \return Integer representation of the #CFE_SB_MsgId_t
+ */
+static inline CFE_SB_MsgId_Atom_t CFE_SB_MsgIdToValue(CFE_SB_MsgId_t MsgId)
+{
+ return CFE_SB_MSGID_UNWRAP_VALUE(MsgId);
+}
+
+/*****************************************************************************/
+/**
+ * \brief Converts a normal integer into a #CFE_SB_MsgId_t
+ *
+ * \par Description
+ * In cases where the #CFE_SB_MsgId_t type is not a simple integer
+ * type, it is not possible to directly use an integer value
+ * supplied via a define or similar method.
+ *
+ * This inline function provides the ability to map an integer value
+ * into a corresponding #CFE_SB_MsgId_t value.
+ *
+ * Applications should transition to using this function wherever an
+ * integer needs to be used for a #CFE_SB_MsgId_t.
+ *
+ * \par Assumptions and Notes:
+ * This negates the type safety that was gained by using a non-
+ * integer type for the #CFE_SB_MsgId_t value. This should only be
+ * used in specific cases where the value is coming from an external
+ * source. Any internal API calls should be updated to return the
+ * #CFE_SB_MsgId_t type directly, rather than an integer type.
+ *
+ * \return #CFE_SB_MsgId_t representation of the integer
+ */
+static inline CFE_SB_MsgId_t CFE_SB_ValueToMsgId(CFE_SB_MsgId_Atom_t MsgIdValue)
+{
+ CFE_SB_MsgId_t Result = CFE_SB_MSGID_WRAP_VALUE(MsgIdValue);
+ return Result;
+}
+/** @} */
+
+#endif /* CFE_SB_H */
diff --git a/modules/core_api/fsw/inc/cfe_sb_api_typedefs.h b/modules/core_api/fsw/inc/cfe_sb_api_typedefs.h
new file mode 100644
index 000000000..5cc2e9366
--- /dev/null
+++ b/modules/core_api/fsw/inc/cfe_sb_api_typedefs.h
@@ -0,0 +1,160 @@
+/*
+** 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
+ *
+ * Purpose:
+ * This header file contains all definitions for the cFE Software Bus
+ * Application Programmer's Interface.
+ *
+ * Author: R.McGraw/SSI
+ *
+ */
+
+#ifndef CFE_SB_API_TYPEDEFS_H
+#define CFE_SB_API_TYPEDEFS_H
+
+/*
+** Includes
+*/
+#include "common_types.h"
+#include "cfe_sb_extern_typedefs.h"
+#include "cfe_msg_api_typedefs.h"
+#include "cfe_resourceid_api_typedefs.h"
+#include "cfe_msg_hdr.h"
+
+/*
+** Defines
+*/
+#define CFE_SB_POLL 0 /**< \brief Option used with #CFE_SB_ReceiveBuffer to request immediate pipe status */
+#define CFE_SB_PEND_FOREVER -1 /**< \brief Option used with #CFE_SB_ReceiveBuffer to force a wait for next message */
+#define CFE_SB_SUBSCRIPTION 0 /**< \brief Subtype specifier used in #CFE_SB_SingleSubscriptionTlm_t by SBN App */
+#define CFE_SB_UNSUBSCRIPTION 1 /**< \brief Subtype specified used in #CFE_SB_SingleSubscriptionTlm_t by SBN App */
+
+/* ------------------------------------------------------ */
+/* Macro Constants for use with the CFE_SB_MsgId_t type */
+/* ------------------------------------------------------ */
+
+/**
+ * \brief Translation macro to convert from MsgId integer values to opaque/abstract API values
+ *
+ * This conversion exists in macro form to allow compile-time evaluation for constants, and
+ * should not be used directly in application code.
+ *
+ * For applications, use the CFE_SB_ValueToMsgId() inline function instead.
+ *
+ * \sa CFE_SB_ValueToMsgId()
+ */
+#define CFE_SB_MSGID_WRAP_VALUE(val) ((CFE_SB_MsgId_t)(val))
+
+/**
+ * \brief Translation macro to convert to MsgId integer values from opaque/abstract API values
+ *
+ * This conversion exists in macro form to allow compile-time evaluation for constants, and
+ * should not be used directly in application code.
+ *
+ * For applications, use the CFE_SB_MsgIdToValue() inline function instead.
+ *
+ * \sa CFE_SB_MsgIdToValue()
+ */
+#define CFE_SB_MSGID_UNWRAP_VALUE(mid) ((CFE_SB_MsgId_Atom_t)(mid))
+
+/**
+ * \brief Reserved value for CFE_SB_MsgId_t that will not match any valid MsgId
+ *
+ * This rvalue macro can be used for static/compile-time data initialization to ensure that
+ * the initialized value does not alias to a valid MsgId object.
+ */
+#define CFE_SB_MSGID_RESERVED CFE_SB_MSGID_WRAP_VALUE(-1)
+
+/**
+ * \brief A literal of the CFE_SB_MsgId_t type representing an invalid ID
+ *
+ * This value should be used for runtime initialization of CFE_SB_MsgId_t values.
+ *
+ * \note This may be a compound literal in a future revision. Per C99, compound
+ * literals are lvalues, not rvalues, so this value should not be used in
+ * static/compile-time data initialization. For static data initialization
+ * purposes (rvalue), #CFE_SB_MSGID_RESERVED should be used instead.
+ * However, in the current implementation, they are equivalent.
+ */
+#define CFE_SB_INVALID_MSG_ID CFE_SB_MSGID_RESERVED
+
+/**
+ * \brief Cast/Convert a generic CFE_ResourceId_t to a CFE_SB_PipeId_t
+ */
+#define CFE_SB_PIPEID_C(val) ((CFE_SB_PipeId_t)CFE_RESOURCEID_WRAP(val))
+
+/**
+ * \brief A CFE_SB_PipeId_t value which is always invalid
+ *
+ * This may be used as a safe initializer for CFE_SB_PipeId_t values
+ */
+#define CFE_SB_INVALID_PIPE CFE_SB_PIPEID_C(CFE_RESOURCEID_UNDEFINED)
+
+/*
+** Pipe option bit fields.
+*/
+#define CFE_SB_PIPEOPTS_IGNOREMINE \
+ 0x00000001 /**< \brief Messages sent by the app that owns this pipe will not be sent to this pipe. */
+
+#define CFE_SB_DEFAULT_QOS ((CFE_SB_Qos_t) {0}) /**< \brief Default Qos macro */
+
+/*
+** Type Definitions
+*/
+
+/** \brief Software Bus generic message */
+typedef union CFE_SB_Msg
+{
+ CFE_MSG_Message_t Msg; /**< \brief Base message type without enforced alignment */
+ long long int LongInt; /**< \brief Align to support Long Integer */
+ long double LongDouble; /**< \brief Align to support Long Double */
+} CFE_SB_Buffer_t;
+
+#ifndef CFE_OMIT_DEPRECATED_6_8
+
+/** \brief Deperecated type to minimize required changes */
+typedef CFE_SB_Buffer_t CFE_SB_Msg_t;
+
+/** \brief Deperecated type to minimize required changes */
+typedef CFE_MSG_CommandHeader_t CFE_SB_CmdHdr_t;
+
+/** \brief Deperecated type to minimize required changes */
+typedef CFE_MSG_TelemetryHeader_t CFE_SB_TlmHdr_t;
+
+#define CFE_SB_CMD_HDR_SIZE (sizeof(CFE_MSG_CommandHeader_t)) /**< \brief Size of command header */
+#define CFE_SB_TLM_HDR_SIZE (sizeof(CFE_MSG_TelemetryHeader_t)) /**< \brief Size of telemetry header */
+
+/** \brief Pointer to an SB Message */
+typedef CFE_MSG_Message_t *CFE_SB_MsgPtr_t;
+
+/** \brief CFE_SB_MsgPayloadPtr_t defined as an opaque pointer to a message Payload portion */
+typedef uint8 *CFE_SB_MsgPayloadPtr_t;
+
+#define CFE_SB_Default_Qos CFE_SB_DEFAULT_QOS /**< \deprecated use CFE_SB_DEFAULT_QOS */
+
+#define CFE_SB_CMD_HDR_SIZE (sizeof(CFE_MSG_CommandHeader_t)) /**< \brief Size of command header */
+#define CFE_SB_TLM_HDR_SIZE (sizeof(CFE_MSG_TelemetryHeader_t)) /**< \brief Size of telemetry header */
+
+#endif /* CFE_OMIT_DEPRECATED_6_8 */
+
+#endif /* CFE_SB_API_TYPEDEFS_H */
diff --git a/modules/core_api/fsw/inc/cfe_sb_core_internal.h b/modules/core_api/fsw/inc/cfe_sb_core_internal.h
new file mode 100644
index 000000000..25ee96929
--- /dev/null
+++ b/modules/core_api/fsw/inc/cfe_sb_core_internal.h
@@ -0,0 +1,88 @@
+/*
+** 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
+ *
+ * Purpose:
+ * This header file contains all definitions for the cFE Software Bus
+ * Application Programmer's Interface.
+ *
+ * Author: R.McGraw/SSI
+ *
+ */
+
+#ifndef CFE_SB_CORE_INTERNAL_H
+#define CFE_SB_CORE_INTERNAL_H
+
+#include "common_types.h"
+#include "cfe_es_extern_typedefs.h"
+
+/*
+ * The internal APIs prototyped within this block are only intended to be invoked from
+ * other CFE core apps. They still need to be prototyped in the shared header such that
+ * they can be called from other core modules, but applications should not call these.
+ */
+
+/** @defgroup CFEAPISBCoreInternal cFE Internal Software Bus APIs, internal to CFE core
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+** \brief Entry Point for cFE Core Application
+**
+** \par Description
+** This is the entry point to the cFE SB Core Application.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+******************************************************************************/
+extern void CFE_SB_TaskMain(void);
+
+/*****************************************************************************/
+/**
+** \brief Initializes the cFE core module API Library
+**
+** \par Description
+** Initializes the cFE core module API Library
+**
+** \par Assumptions, External Events, and Notes:
+** -# This function MUST be called before any module API's are called.
+**
+******************************************************************************/
+extern int32 CFE_SB_EarlyInit(void);
+
+/*****************************************************************************/
+/**
+** \brief Removes SB resources associated with specified Application
+**
+** \par Description
+** This function is called by cFE Executive Services to cleanup after
+** an Application has been terminated. It frees resources
+** that have been allocated to the specified Application.
+**
+******************************************************************************/
+extern int32 CFE_SB_CleanUpApp(CFE_ES_AppId_t AppId);
+
+/**@}*/
+
+#endif /* CFE_SB_CORE_INTERNAL_H */
diff --git a/modules/core_api/fsw/inc/cfe_sb_extern_typedefs.h b/modules/core_api/fsw/inc/cfe_sb_extern_typedefs.h
new file mode 100644
index 000000000..ae115a7ca
--- /dev/null
+++ b/modules/core_api/fsw/inc/cfe_sb_extern_typedefs.h
@@ -0,0 +1,141 @@
+/*
+** 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
+ *
+ * Declarations and prototypes for cfe_sb_extern_typedefs module
+ */
+
+#ifndef CFE_SB_EXTERN_TYPEDEFS_H
+#define CFE_SB_EXTERN_TYPEDEFS_H
+
+/* This header may be generated from an EDS file,
+ * tools are available and the feature is enabled */
+#ifdef CFE_EDS_ENABLED_BUILD
+
+/* Use the EDS generated version of these types */
+#include "cfe_sb_eds_typedefs.h"
+
+#else
+/* Use the local definitions of these types */
+
+#include "common_types.h"
+#include "cfe_mission_cfg.h"
+#include "cfe_resourceid_typedef.h"
+
+#define CFE_SB_SUB_ENTRIES_PER_PKT 20 /**< \brief Configuration parameter used by SBN App */
+
+/**
+ * @brief Label definitions associated with CFE_SB_QosPriority_Enum_t
+ */
+enum CFE_SB_QosPriority
+{
+
+ /**
+ * @brief Normal priority level
+ */
+ CFE_SB_QosPriority_LOW = 0,
+
+ /**
+ * @brief High priority
+ */
+ CFE_SB_QosPriority_HIGH = 1
+};
+
+/**
+ * @brief Selects the priorty level for message routing
+ *
+ * @sa enum CFE_SB_QosPriority
+ */
+typedef uint8 CFE_SB_QosPriority_Enum_t;
+
+/**
+ * @brief Label definitions associated with CFE_SB_QosReliability_Enum_t
+ */
+enum CFE_SB_QosReliability
+{
+
+ /**
+ * @brief Normal (best-effort) reliability
+ */
+ CFE_SB_QosReliability_LOW = 0,
+
+ /**
+ * @brief High reliability
+ */
+ CFE_SB_QosReliability_HIGH = 1
+};
+
+/**
+ * @brief Selects the reliability level for message routing
+ *
+ * @sa enum CFE_SB_QosReliability
+ */
+typedef uint8 CFE_SB_QosReliability_Enum_t;
+
+/**
+ * @brief An integer type that should be used for indexing into the Routing Table
+ */
+typedef uint16 CFE_SB_RouteId_Atom_t;
+
+/**
+ * @brief CFE_SB_MsgId_Atom_t primitive type definition
+ *
+ * This is an integer type capable of holding any Message ID value
+ * Note: This value is limited via #CFE_PLATFORM_SB_HIGHEST_VALID_MSGID
+ */
+typedef uint32 CFE_SB_MsgId_Atom_t;
+
+/**
+ * @brief CFE_SB_MsgId_t type definition
+ *
+ * Software Bus message identifier used in many SB APIs
+ *
+ * Currently this is directly mapped to the underlying holding type (not wrapped) for
+ * compatibility with existing usage semantics in apps (mainly switch/case statements)
+ *
+ * @note In a future version it could become a type-safe wrapper similar to the route index,
+ * to avoid message IDs getting mixed between other integer values.
+ */
+typedef CFE_SB_MsgId_Atom_t CFE_SB_MsgId_t;
+
+/** \brief CFE_SB_PipeId_t to primitive type definition
+ *
+ * Software Bus pipe identifier used in many SB APIs, as well as SB Telemetry messages
+ * and data files.
+ */
+typedef CFE_RESOURCEID_BASE_TYPE CFE_SB_PipeId_t;
+
+/** \brief Quality Of Service Type Definition
+**
+** Currently an unused parameter in #CFE_SB_SubscribeEx
+** Intended to be used for interprocessor communication only
+**/
+typedef struct
+{
+ uint8 Priority; /**< \brief Specify high(1) or low(0) message priority for off-board routing, currently unused */
+ uint8 Reliability; /**< \brief Specify high(1) or low(0) message transfer reliability for off-board routing,
+ currently unused */
+} CFE_SB_Qos_t;
+
+#endif /* CFE_EDS_ENABLED_BUILD */
+
+#endif /* CFE_SB_EXTERN_TYPEDEFS_H */
diff --git a/modules/core_private/fsw/inc/cfe_sb_destination_typedef.h b/modules/core_private/fsw/inc/cfe_sb_destination_typedef.h
new file mode 100644
index 000000000..daaf9f95c
--- /dev/null
+++ b/modules/core_private/fsw/inc/cfe_sb_destination_typedef.h
@@ -0,0 +1,54 @@
+/*
+** 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
+ *
+ * Definition of the CFE_SB_DestinationD_t structure 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_extern_typedefs.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/modules/core_private/fsw/inc/cfe_sbr.h b/modules/core_private/fsw/inc/cfe_sbr.h
new file mode 100644
index 000000000..a35d5f4c2
--- /dev/null
+++ b/modules/core_private/fsw/inc/cfe_sbr.h
@@ -0,0 +1,175 @@
+/*
+** 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
+ *
+ * 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 "cfe_sbr_api_typedefs.h"
+#include "cfe_msg_api_typedefs.h"
+#include "cfe_sb_destination_typedef.h"
+
+#include "cfe_platform_cfg.h"
+
+/******************************************************************************
+ * 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/modules/core_private/fsw/inc/cfe_sbr_api_typedefs.h b/modules/core_private/fsw/inc/cfe_sbr_api_typedefs.h
new file mode 100644
index 000000000..8175e14b8
--- /dev/null
+++ b/modules/core_private/fsw/inc/cfe_sbr_api_typedefs.h
@@ -0,0 +1,76 @@
+/*
+** 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
+ *
+ * Purpose:
+ * Prototypes for private functions and type definitions for SB
+ * routing internal use.
+ */
+
+#ifndef CFE_SBR_API_TYPEDEFS_H
+#define CFE_SBR_API_TYPEDEFS_H
+
+/*
+ * Includes
+ */
+#include "common_types.h"
+#include "cfe_sb_extern_typedefs.h"
+
+/*
+ * Macro Definitions
+ */
+
+/** \brief Invalid route id */
+#define CFE_SBR_INVALID_ROUTE_ID ((CFE_SBR_RouteId_t) {.RouteId = 0})
+
+/******************************************************************************
+ * 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);
+
+#endif /* CFE_SBR_API_TYPEDEFS_H */
diff --git a/modules/sb/CMakeLists.txt b/modules/sb/CMakeLists.txt
new file mode 100644
index 000000000..4362a2774
--- /dev/null
+++ b/modules/sb/CMakeLists.txt
@@ -0,0 +1,39 @@
+##################################################################
+#
+# cFE Software Bus (SB) module CMake build recipe
+#
+##################################################################
+
+project(CFE_SB C)
+
+# Software Bus source files
+set(sb_SOURCES
+ fsw/src/cfe_sb_api.c
+ fsw/src/cfe_sb_buf.c
+ fsw/src/cfe_sb_init.c
+ fsw/src/cfe_sb_msg_id_util.c
+ fsw/src/cfe_sb_priv.c
+ fsw/src/cfe_sb_task.c
+ fsw/src/cfe_sb_util.c
+ fsw/src/cfe_sb_api.c
+ fsw/src/cfe_sb_buf.c
+ fsw/src/cfe_sb_init.c
+ fsw/src/cfe_sb_msg_id_util.c
+ fsw/src/cfe_sb_priv.c
+ fsw/src/cfe_sb_task.c
+ fsw/src/cfe_sb_util.c
+)
+add_library(sb STATIC ${sb_SOURCES})
+
+target_include_directories(sb PUBLIC fsw/inc)
+target_link_libraries(sb PRIVATE core_private)
+
+# Add unit test coverage subdirectory
+if(ENABLE_UNIT_TESTS)
+ add_subdirectory(ut-coverage)
+endif(ENABLE_UNIT_TESTS)
+
+cfs_app_check_intf(${DEP}
+ cfe_sb_msg.h
+ cfe_sb_events.h
+)
diff --git a/modules/sb/fsw/inc/cfe_sb_events.h b/modules/sb/fsw/inc/cfe_sb_events.h
new file mode 100644
index 000000000..682b3fe35
--- /dev/null
+++ b/modules/sb/fsw/inc/cfe_sb_events.h
@@ -0,0 +1,906 @@
+/*
+** 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
+ *
+ * Purpose:
+ * cFE Software Bus (SB) Event IDs
+ *
+ * References:
+ * Flight Software Branch C Coding Standard Version 1.0a
+ * cFE Flight Software Application Developers Guide
+ *
+ */
+
+#ifndef CFE_SB_EVENTS_H
+#define CFE_SB_EVENTS_H
+
+/* **************************
+** ****** Maximum EID. ******
+** **************************
+** The EID's below are not necessarily in order, so it can be difficult to
+** determine what the next EID is to use. When you add EID's, start with MAX_EID + 1
+** and when you're done adding, set this to the highest EID you used. It may
+** be worthwhile to, on occasion, re-number the EID's to put them back in order.
+*/
+#define CFE_SB_MAX_EID 67
+
+/*
+** SB task event message ID's.
+*/
+/*
+** Event ID's
+*/
+
+/** \brief 'cFE SB Initialized'
+** \event 'cFE SB Initialized'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is issued when the Software Bus Task completes its
+** initialization.
+**/
+#define CFE_SB_INIT_EID 1
+
+/** \brief 'CreatePipeErr:Bad Input Arg:app=\%s,ptr=0x\%x,depth=\%d,maxdepth=\%d'
+** \event 'CreatePipeErr:Bad Input Arg:app=\%s,ptr=0x\%x,depth=\%d,maxdepth=\%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when the #CFE_SB_CreatePipe API receives a bad
+** argument. In this case, a bad argument is defined by the following:
+** A NULL PipeIdPtr, PipeDepth = 0 and PipeDepth > maximum pipe depth
+**/
+#define CFE_SB_CR_PIPE_BAD_ARG_EID 2
+
+/** \brief 'CreatePipeErr:Max Pipes(\%d)In Use.app \%s'
+** \event 'CreatePipeErr:Max Pipes(\%d)In Use.app \%s'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when the #CFE_SB_CreatePipe API is called and
+** the maximum number of pipes (defined by cfg param #CFE_PLATFORM_SB_MAX_PIPES) are in use.
+**/
+#define CFE_SB_MAX_PIPES_MET_EID 3
+
+/** \brief 'CreatePipeErr:OS_QueueCreate returned \%d,app \%s'
+** \event 'CreatePipeErr:OS_QueueCreate returned \%d,app \%s'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when the #CFE_SB_CreatePipe API is called and
+** the OS returns an error when the OS returns an error from the OS_QueueCreate API.
+** The error status returned by the OS is displayed in the event. Most commonly,
+** this event is displayed as a result of trying to create pipes with the same name.
+**/
+#define CFE_SB_CR_PIPE_ERR_EID 4
+
+/** \brief 'Pipe Created:name \%s,id \%d,app \%s'
+** \event 'Pipe Created:name \%s,id \%d,app \%s'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This debug event message is issued when a pipe was successfully created in the
+** #CFE_SB_CreatePipe API.
+**/
+#define CFE_SB_PIPE_ADDED_EID 5
+
+/** \brief 'SetPipeOptsErr:Invalid pipe id (\%d).app \%s'
+** \event 'SetPipeOptsErr:Invalid pipe id (\%d).app \%s'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when the #CFE_SB_SetPipeOpts API is called and
+** the PipeID is invalid.
+**/
+#define CFE_SB_SETPIPEOPTS_ID_ERR_EID 55
+
+/** \brief 'SetPipeOptsErr:Caller not owner (\%d).app \%s'
+** \event 'SetPipeOptsErr:Caller not owner (\%d).app \%s'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when the #CFE_SB_SetPipeOpts API is called and
+** the pipe is owned by another app ID.
+**/
+#define CFE_SB_SETPIPEOPTS_OWNER_ERR_EID 56
+
+/** \brief 'SetPipeOpts: Options set (\%d). app \%s'
+** \event 'SetPipeOpts: Options set (\%d). app \%s'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This debug event is generated when options are set.
+**/
+#define CFE_SB_SETPIPEOPTS_EID 57
+
+/** \brief 'GetPipeOptsErr:Invalid pipe id (\%d).app \%s'
+** \event 'GetPipeOptsErr:Invalid pipe id (\%d).app \%s'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when the #CFE_SB_GetPipeOpts API is called and
+** the PipeID is invalid.
+**/
+#define CFE_SB_GETPIPEOPTS_ID_ERR_EID 58
+
+/** \brief 'GetPipeOptsErr:Invalid opts ptr.app \%s'
+** \event 'GetPipeOptsErr:Invalid opts ptr.app \%s'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when the #CFE_SB_GetPipeOpts API is called and
+** the pointer is invalid.
+**/
+#define CFE_SB_GETPIPEOPTS_PTR_ERR_EID 59
+
+/** \brief 'GetPipeOpts: Options retrieved. app \%s'
+** \event 'GetPipeOpts: Options retrieved. app \%s'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This debug event is generated when options are retrieved.
+**/
+#define CFE_SB_GETPIPEOPTS_EID 60
+
+/** \brief 'GetPipeName: Name retrieved. NameOut \%s,Id \%d, app \%s'
+** \event 'GetPipeName: Name retrieved. NameOut \%s,Id \%d, app \%s'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This debug event is generated when name is retrieved by id.
+**/
+#define CFE_SB_GETPIPENAME_EID 62
+
+/** \brief 'GetPipeName: Null ptr error. Id \%d, app \%s'
+** \event 'GetPipeName: Null ptr error. Id \%d, app \%s'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This debug event is generated when the name buffer ptr is null.
+**/
+#define CFE_SB_GETPIPENAME_NULL_PTR_EID 63
+
+/** \brief 'GetPipeName: Id error. NameOut \%s,Id \%d, app \%s'
+** \event 'GetPipeName: Id error. NameOut \%s,Id \%d, app \%s'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This debug event is generated when name is retrieved by id.
+**/
+#define CFE_SB_GETPIPENAME_ID_ERR_EID 64
+
+/** \brief 'GetPipeIdByName: ID retrieved. Name \%s,IdOut 0x\%x, app \%s'
+** \event 'GetPipeIdByName: ID retrieved. Name \%s,IdOut 0x\%x, app \%s'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This debug event is generated when id is retrieved by name.
+**/
+#define CFE_SB_GETPIPEIDBYNAME_EID 65
+
+/** \brief 'GetPipeIdByName Err:Bad input argument,Name 0x\%x,IdOut 0x%x,App \%s'
+** \event 'GetPipeIdByName Err:Bad input argument,Name 0x\%x,IdOut 0x%x,App \%s'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when the #CFE_SB_GetPipeIdByName API receives a
+** NULL ptr as an argument.
+**/
+#define CFE_SB_GETPIPEIDBYNAME_NULL_ERR_EID 66
+
+/** \brief 'GetPipeIdByName Err:Name not found,Name \%s,IdOut 0x%x,App \%s'
+** \event 'GetPipeIdByName Err:Name not found,Name \%s,IdOut 0x%x,App \%s'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when the #CFE_SB_GetPipeIdByName API receives an
+** invalid name.
+**/
+#define CFE_SB_GETPIPEIDBYNAME_NAME_ERR_EID 67
+
+/** \brief 'Subscribe Err:Bad Arg,MsgId 0x\%x,PipeId \%d,app \%s,scope \%d'
+** \event 'Subscribe Err:Bad Arg,MsgId 0x\%x,PipeId \%d,app \%s,scope \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when one of the Subscribe API's are called
+** with an invalid MsgId. An invalid MsgId is defined as being greater than the
+** cfg param #CFE_PLATFORM_SB_HIGHEST_VALID_MSGID.
+**
+**/
+#define CFE_SB_SUB_ARG_ERR_EID 6
+
+/** \brief 'Duplicate Subscription,MsgId 0x\%x on \%s pipe,app \%s'
+** \event 'Duplicate Subscription,MsgId 0x\%x on \%s pipe,app \%s'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This info event message is issued when a subscription request is received that
+** already exists in the routing table. A duplicate subscription is defined by a
+** matching MsgId and PipeId. No other parameters are used in detecting a duplicate
+** subscription.
+** NOTE: By default, SB filters this event. The EVS filter algorithm allows the
+** first event to pass through the filter, but all subsequent events with this
+** event id will be filtered. A command must be sent to unfilter this event if
+** the user desires to see it.
+**/
+#define CFE_SB_DUP_SUBSCRIP_EID 7
+
+/** \brief 'Subscribe Err:Max Msgs(\%d)In Use,MsgId 0x\%x,pipe \%s,app \%s'
+** \event 'Subscribe Err:Max Msgs(\%d)In Use,MsgId 0x\%x,pipe \%s,app \%s'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when one of the SB subscribe APIs are called
+** with a new MsgId, and SB cannot accommodate the new MsgId because the maximum
+** number of MsgIds are in use. The maximum number of MsgIds is defined by cfg param
+** #CFE_PLATFORM_SB_MAX_MSG_IDS. This cfg param dictates the number of elements in the SB
+** routing table. There is one element per MsgId. The user may monitor the routing
+** table utilization figures (msgids currently in use, high water mark and max
+** allowed) by sending the SB cmd to dump the SB statistics data.
+**/
+#define CFE_SB_MAX_MSGS_MET_EID 8
+
+/** \brief 'Subscribe Err:Max Dests(\%d)In Use For Msg 0x\%x,pipe \%s,app \%s'
+** \event 'Subscribe Err:Max Dests(\%d)In Use For Msg 0x\%x,pipe \%s,app \%s'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when a subscription request is received and
+** all destinations for that MsgId are in use. The number of destinations per msgid
+** is a configuration parameter named #CFE_PLATFORM_SB_MAX_DEST_PER_PKT. A destination is
+** defined as a pipe.
+**/
+#define CFE_SB_MAX_DESTS_MET_EID 9
+
+/** \brief 'Subscription Rcvd:MsgId 0x\%x on \%s(\%d),app \%s'
+** \event 'Subscription Rcvd:MsgId 0x\%x on \%s(\%d),app \%s'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This debug event message is issued when a subscription is successfully made
+** through one of the SB Subscribe API's
+**/
+#define CFE_SB_SUBSCRIPTION_RCVD_EID 10
+
+/** \brief 'UnSubscribe Err:Bad Arg,MsgId 0x\%x,PipeId \%d,app \%s,scope \%d'
+** \event 'UnSubscribe Err:Bad Arg,MsgId 0x\%x,PipeId \%d,app \%s,scope \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when a request to unsubscribe fails due to
+** an invalid msgid or an invalid pipeid in one of SB's unsubscribe API's. The msgid
+** must be less than cfg param #CFE_PLATFORM_SB_HIGHEST_VALID_MSGID and the pipeid must have
+** been created and have a value less than cfg param #CFE_PLATFORM_SB_MAX_PIPES. The SB pipe
+** table may be viewed to verify its value or existence.
+**/
+#define CFE_SB_UNSUB_ARG_ERR_EID 11
+
+/** \brief 'Unsubscribe Err:No subs for Msg 0x\%x on \%s,app \%s'
+** \event 'Unsubscribe Err:No subs for Msg 0x\%x on \%s,app \%s'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This info event message is issued when a request to unsubscribe fails due to
+** a non existent msgid/pipeid combination in the SB routing table. The SB routing
+** table may be viewed to see a list of valid msgid/pipeid combinations.
+**/
+#define CFE_SB_UNSUB_NO_SUBS_EID 12
+
+/** \brief 'Send Err:Bad input argument,Arg 0x\%x,App \%s'
+** \event 'Send Err:Bad input argument,Arg 0x\%x,App \%s'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when a transmit API receives an
+** invalid (possibly NULL) ptr as an argument.
+**/
+#define CFE_SB_SEND_BAD_ARG_EID 13
+
+/** \brief 'No subscribers for MsgId 0x\%x,sender \%s'
+** \event 'No subscribers for MsgId 0x\%x,sender \%s'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This info event message is issued when a transmit API is called and there
+** are no subscribers (therefore no destinations) for the message to be sent. Each
+** time the SB detects this situation, the corresponding SB telemetry point is
+** incremented..
+** NOTE: By default, SB filters this event. The EVS filter algorithm allows the
+** first event to pass through the filter, but all subsequent events with this
+** event id will be filtered. A command must be sent to unfilter this event if
+** the user desires to see it.
+**/
+#define CFE_SB_SEND_NO_SUBS_EID 14
+
+/** \brief 'Send Err:Msg Too Big MsgId=0x\%x,app=\%s,size=\%d,MaxSz=\%d'
+** \event 'Send Err:Msg Too Big MsgId=0x\%x,app=\%s,size=\%d,MaxSz=\%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when a transmit API is called and the
+** packet length field in the message header implies that the message size exceeds
+** the max size defined by mission cfg param #CFE_MISSION_SB_MAX_SB_MSG_SIZE. The request to
+** send the message is denied, there is no partial packet sent.
+**/
+#define CFE_SB_MSG_TOO_BIG_EID 15
+
+/** \brief 'Send Err:Request for Buffer Failed. MsgId 0x\%x,app \%s,size \%d'
+** \event 'Send Err:Request for Buffer Failed. MsgId 0x\%x,app \%s,size \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when a transmit API fails to receive
+** the necessary buffer memory from the ES memory pool. This could be an indication
+** that the cfg param #CFE_PLATFORM_SB_BUF_MEMORY_BYTES is set too low. To check this, send SB
+** cmd to dump the SB statistics pkt and view the buffer memory parameters.
+**/
+#define CFE_SB_GET_BUF_ERR_EID 16
+
+/** \brief 'Send Err:Msg Limit Err MsgId 0x\%x,pipe \%s,sender \%s'
+** \event 'Send Err:Msg Limit Err MsgId 0x\%x,pipe \%s,sender \%s'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when a transmit API cannot route the
+** MsgId (displayed in event) to the pipe (displayed in the event) because the pipe
+** currently contains the maximum number of messages of this type (MsgId). This is
+** typically an indication that the receiver is not reading its pipe fast enough, or
+** at all. A less typical scenerio is that the sender is sending a burst of pkts of
+** this type (or MsgId) and the receiver (owner of 'pipe') cannot keep up. The
+** subscriber of the message dictates this limit count in the 'MsgLim' parameter of
+** the #CFE_SB_SubscribeEx API or uses the default value of 4 if using the
+** #CFE_SB_Subscribe API.
+**/
+#define CFE_SB_MSGID_LIM_ERR_EID 17
+
+/** \brief 'Rcv Err:Bad Input Arg:BufPtr 0x\%x,pipe \%d,t/o \%d,app \%s'
+** \event 'Rcv Err:Bad Input Arg:BufPtr 0x\%x,pipe \%d,t/o \%d,app \%s'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when an invalid paramter is passed into the
+** #CFE_SB_ReceiveBuffer API. Two possibile problems would be the first parameter (*BufPtr)
+** being NULL or the third paramter (TimeOut) being less than -1.
+**/
+#define CFE_SB_RCV_BAD_ARG_EID 18
+
+/** \brief 'Rcv Err:PipeId \%d does not exist,app \%s'
+** \event 'Rcv Err:PipeId \%d does not exist,app \%s'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when an invalid PipeId is passed into the
+** #CFE_SB_ReceiveBuffer API. The SB Pipe Table shows all valid PipeIds and may be viewed
+** for verification.
+**/
+#define CFE_SB_BAD_PIPEID_EID 19
+
+/** \brief 'Subscribe Err:Request for Destination Blk failed for Msg 0x\%x,Pipe \%s'
+** \event 'Subscribe Err:Request for Destination Blk failed for Msg 0x\%x,Pipe \%s'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when the SB receives an error from the memory
+** pool in the attempt to obtain a new destination block. Then memory pool statistics
+** may be viewed by sending the related ES command.
+**/
+#define CFE_SB_DEST_BLK_ERR_EID 20
+
+/** \brief 'Send Err:Invalid msgid in msg,MsgId 0x\%x,App \%s'
+** \event 'Send Err:Invalid msgid in msg,MsgId 0x\%x,App \%s'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when a transmit API is called and
+** the SB discovers that the message to send has a msg id that is invalid. It may be
+** due to a msg id that is greater than cfg parameter #CFE_PLATFORM_SB_HIGHEST_VALID_MSGID
+**/
+#define CFE_SB_SEND_INV_MSGID_EID 21
+
+/** \brief 'Sending Subscription Report Msg=0x\%x,Pipe=\%d,Stat=0x\%x'
+** \event 'Sending Subscription Report Msg=0x\%x,Pipe=\%d,Stat=0x\%x'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This debug event message is issued when SB subscription reporting is enabled,
+** (which is disabled by default) and a subscription is successfully received.
+**/
+#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'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when a transmit API is called and
+** encounters an error when attempting to write the msg to the destination pipe
+** (which is an underlying queue). This could indicate that the owner of the pipe is
+** not readings its messages fast enough or at all. It may also mean that the
+** pipe depth is not deep enough. The pipe depth is an input parameter to the
+** #CFE_SB_CreatePipe API.
+**/
+#define CFE_SB_Q_FULL_ERR_EID 25
+
+/** \brief 'Pipe Write Err,MsgId 0x\%x,pipe \%s,stat 0x\%x,app \%s'
+** \event 'Pipe Write Err,MsgId 0x\%x,pipe \%s,stat 0x\%x,app \%s'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when a transmit API is called and
+** encounters an error when attempting to write the msg to the destination pipe
+** (which is an underlying queue). More precisely, the OS API #OS_QueuePut has
+** returned an unexpected error. The return code is displayed in the event. For
+** more information, the user may look up the return code in the OSAL documention or
+** source code.
+**/
+#define CFE_SB_Q_WR_ERR_EID 26
+
+/** \brief 'Pipe Read Err,pipe \%s,app \%s,stat 0x\%x'
+** \event 'Pipe Read Err,pipe \%s,app \%s,stat 0x\%x'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when a transmit API is called and
+** encounters an error when attempting to read the msg from the destination pipe
+** (which is an underlying queue). More precisely, the OS API #OS_QueueGet has
+** returned an unexpected error. The return code is displayed in the event. For
+** more information, the user may look up the return code in the OSAL documention or
+** source code.
+**/
+#define CFE_SB_Q_RD_ERR_EID 27
+
+/** \brief 'No-op Cmd Rcvd'
+** \event 'No-op Cmd Rcvd'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This info event message is issued in response an SB NO-OP command
+**/
+#define CFE_SB_CMD0_RCVD_EID 28
+
+/** \brief 'Reset Counters Cmd Rcvd'
+** \event 'Reset Counters Cmd Rcvd'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This debug event message is issued in response an SB Reset Counters command
+**/
+#define CFE_SB_CMD1_RCVD_EID 29
+
+/** \brief 'Software Bus Statistics packet sent'
+** \event 'Software Bus Statistics packet sent'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This debug event message is issued when SB receives a cmd to send the SB
+** statistics pkt.
+**/
+#define CFE_SB_SND_STATS_EID 32
+
+/** \brief 'Enbl Route Cmd:Route does not exist.Msg 0x\%x,Pipe \%d'
+** \event 'Enbl Route Cmd:Route does not exist.Msg 0x\%x,Pipe \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when SB receives a cmd to enable a route that
+** does not exist in the routing table. A route is defined by a MsgId, PipeId pair.
+**/
+#define CFE_SB_ENBL_RTE1_EID 33
+
+/** \brief 'Enabling Route,Msg 0x\%x,Pipe \%d'
+** \event 'Enabling Route,Msg 0x\%x,Pipe \%d'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This debug event message is issued when SB receives a cmd to enable a route and
+** the request is successfully executed.
+**/
+#define CFE_SB_ENBL_RTE2_EID 34
+
+/** \brief 'Enbl Route Cmd:Invalid Param.Msg 0x\%x,Pipe \%d'
+** \event 'Enbl Route Cmd:Invalid Param.Msg 0x\%x,Pipe \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when SB receives a cmd to enable a route and
+** the MsgId or PipeId does not pass the validation checks. The MsgId must be less
+** than cfg param #CFE_PLATFORM_SB_HIGHEST_VALID_MSGID. The PipeId must exist and be less than
+** cfg param #CFE_PLATFORM_SB_MAX_PIPES. The SB pipe table may be viewed to verify the PipeId
+** existence.
+**/
+#define CFE_SB_ENBL_RTE3_EID 35
+
+/** \brief 'Disable Route Cmd:Route does not exist,Msg 0x\%x,Pipe \%d'
+** \event 'Disable Route Cmd:Route does not exist,Msg 0x\%x,Pipe \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when SB receives a cmd to disable a route that
+** does not exist in the routing table. A route is defined by a MsgId, PipeId pair.
+**/
+#define CFE_SB_DSBL_RTE1_EID 36
+
+/** \brief 'Route Disabled,Msg 0x\%x,Pipe \%d'
+** \event 'Route Disabled,Msg 0x\%x,Pipe \%d'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This debug event message is issued when SB receives a cmd to disable a route and
+** the request is successfully executed.
+**/
+#define CFE_SB_DSBL_RTE2_EID 37
+
+/** \brief 'Disable Route Cmd:Invalid Param.Msg 0x\%x,Pipe \%d'
+** \event 'Disable Route Cmd:Invalid Param.Msg 0x\%x,Pipe \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when SB receives a cmd to disable a route and
+** the MsgId or PipeId does not pass the validation checks. The MsgId must be less
+** than cfg param #CFE_PLATFORM_SB_HIGHEST_VALID_MSGID. The PipeId must exist and be less than
+** cfg param #CFE_PLATFORM_SB_MAX_PIPES. The SB pipe table may be viewed to verify the PipeId
+** existence.
+**/
+#define CFE_SB_DSBL_RTE3_EID 38
+
+/** \brief '\%s written:Size=\%d,Entries=\%d'
+** \event '\%s written:Size=\%d,Entries=\%d'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This debug event message is issued after the SB routing info file, pipe info
+** file or the map info file is written and closed. This is done is response to
+** the SB 'Send Routing Info' cmd, the SB 'Send pipe Info' cmd or the SB 'Send
+** Map Info' cmd, respectively.
+**/
+#define CFE_SB_SND_RTG_EID 39
+
+/** \brief 'Error creating file \%s, stat=0x\%x'
+** \event 'Error creating file \%s, stat=0x\%x'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when the SB 'Send Routing Info' cmd is
+** received and the file create fails. The event displays the status received from
+** the OS.
+**/
+#define CFE_SB_SND_RTG_ERR1_EID 40
+
+/** \brief 'Invalid Cmd, Unexpected Command Code \%d'
+** \event 'Invalid Cmd, Unexpected Command Code \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when the SB receives a cmd that has an
+** unexpected cmd code.
+**/
+#define CFE_SB_BAD_CMD_CODE_EID 42
+
+/** \brief 'Invalid Cmd, Unexpected Msg Id: 0x\%x'
+** \event 'Invalid Cmd, Unexpected Msg Id: 0x\%x'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when the SB receives a msg that has an
+** unexpected msg id.
+**/
+#define CFE_SB_BAD_MSGID_EID 43
+
+/** \brief 'Full Sub Pkt \%d Sent,Entries=\%d,Stat=0x\%x\n'
+** \event 'Full Sub Pkt \%d Sent,Entries=\%d,Stat=0x\%x\n'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This debug event message is issued in response to the
+** 'Send Previous Subscriptions' command and a full pkt segment is sent.
+**/
+#define CFE_SB_FULL_SUB_PKT_EID 44
+
+/** \brief 'Partial Sub Pkt \%d Sent,Entries=\%d,Stat=0x\%x'
+** \event 'Partial Sub Pkt \%d Sent,Entries=\%d,Stat=0x\%x'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This debug event message is issued in response to the
+** 'Send Previous Subscriptions' command and a partial pkt segment is sent.
+**/
+#define CFE_SB_PART_SUB_PKT_EID 45
+
+/** \brief 'Pipe Delete Error:Bad Argument,PipedId \%d,Requestor \%s,Idx \%d,Stat \%d'
+** \event 'Pipe Delete Error:Bad Argument,PipedId \%d,Requestor \%s,Idx \%d,Stat \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued from CFE_SB_DeletePipeFull when an
+** invalid pipe ID is passed in
+**/
+#define CFE_SB_DEL_PIPE_ERR1_EID 46
+
+/** \brief 'Pipe Deleted:id \%d,owner \%s'
+** \event 'Pipe Deleted:id \%d,owner \%s'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This debug event message is issued when the #CFE_SB_DeletePipe API is called and
+** the request is successfully completed.
+**/
+#define CFE_SB_PIPE_DELETED_EID 47
+
+/** \brief 'Subscription Removed:Msg 0x\%x on pipe \%d,app \%s'
+** \event 'Subscription Removed:Msg 0x\%x on pipe \%d,app \%s'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This debug event message is issued when #CFE_SB_Unsubscribe API is called
+** and the request is successfully completed.
+**/
+#define CFE_SB_SUBSCRIPTION_REMOVED_EID 48
+
+/** \brief 'File write,byte cnt err,file \%s,request=\%d,actual=\%d'
+** \event 'File write,byte cnt err,file \%s,request=\%d,actual=\%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when one of many SB's file write operations
+** is unsuccessful. This event is a result of #CFE_FS_WriteHeader or OS_write
+** returning something other than the number of bytes requested to be written.
+** The requested value and the return value are displayed in the event.
+**/
+#define CFE_SB_FILEWRITE_ERR_EID 49
+
+/** \brief 'Subscribe Err:Invalid Pipe Id,Msg=0x\%x,PipeId=\%d,App \%s'
+** \event 'Subscribe Err:Invalid Pipe Id,Msg=0x\%x,PipeId=\%d,App \%s'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when the input PipeId has a value that is not
+** listed in the pipe table. This typically means that the pipe does not exist.
+** The pipe table may be viewed for verification.
+**/
+#define CFE_SB_SUB_INV_PIPE_EID 50
+
+/** \brief 'Subscribe Err:Caller(\%s) is not the owner of pipe \%d, Msg=0x\%x'
+** \event 'Subscribe Err:Caller(\%s) is not the owner of pipe \%d, Msg=0x\%x'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when one of the SB subscribe API's are called
+** and the requestor is not the owner of the pipe. Only the owner of the pipe may
+** subscribe to messages on the pipe.
+**/
+#define CFE_SB_SUB_INV_CALLER_EID 51
+
+/** \brief 'Unsubscribe Err:Invalid Pipe Id Msg=0x\%x,Pipe=\%d,app=\%s'
+** \event 'Unsubscribe Err:Invalid Pipe Id Msg=0x\%x,Pipe=\%d,app=\%s'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when one of the SB unsubscribe API's are
+** called and the input parameter PipeId is not listed in the pipe table.
+** This typically means that the pipe does not exist. The pipe table may be viewed
+** for verification.
+**/
+#define CFE_SB_UNSUB_INV_PIPE_EID 52
+
+/** \brief 'Unsubscribe Err:Caller(\%s) is not the owner of pipe \%d,Msg=0x\%x'
+** \event 'Unsubscribe Err:Caller(\%s) is not the owner of pipe \%d,Msg=0x\%x'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when one of the SB unsubscribe API's are
+** called and the requestor is not the owner of the pipe (or ES). Only the owner of
+** the pipe(or ES for cleanup purposes)may unsubscribe messages from a pipe.
+**/
+#define CFE_SB_UNSUB_INV_CALLER_EID 53
+
+/** \brief 'Pipe Delete Error:Caller(\%s) is not the owner of pipe \%d'
+** \event 'Pipe Delete Error:Caller(\%s) is not the owner of pipe \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when the #CFE_SB_DeletePipe API is called by a
+** task that is not the owner of the pipe. Pipes may be deleted only by the task
+** that created the pipe or ES(for cleanup purposes).
+**/
+#define CFE_SB_DEL_PIPE_ERR2_EID 54
+
+/** \brief 'Invalid cmd length: ID = 0x\%X, CC = \%d, Exp Len = \%d, Len = \%d'
+** \event 'Invalid cmd length: ID = 0x\%X, CC = \%d, Exp Len = \%d, Len = \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when a message with the #CFE_SB_CMD_MID
+** message ID has arrived but whose packet length does not match the expected
+** length for the specified command code.
+**
+** The \c ID field in the event message specifies the Message ID (in hex), the \c CC field
+** specifies the Command Code (in decimal), the \c Exp Len field specified the Expected
+** Length (in decimal ), and \c Len specifies the message Length (in decimal)
+** found in the message.
+**/
+#define CFE_SB_LEN_ERR_EID 61
+
+/** \brief 'CreatePipeErr:Name Taken:app=\%s,ptr=0x\%x,depth=\%d,maxdepth=\%d'
+** \event 'CreatePipeErr:Name Taken:app=\%s,ptr=0x\%x,depth=\%d,maxdepth=\%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when the #CFE_SB_CreatePipe API tries to create
+** a pipe with a name that is in use.
+**/
+#define CFE_SB_CR_PIPE_NAME_TAKEN_EID 62
+
+/** \brief 'CreatePipeErr:No Free:app=\%s,ptr=0x\%x,depth=\%d,maxdepth=\%d'
+** \event 'CreatePipeErr:No Free:app=\%s,ptr=0x\%x,depth=\%d,maxdepth=\%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This error event message is issued when the #CFE_SB_CreatePipe API is unable to
+** create a queue because there are no queues free.
+**/
+#define CFE_SB_CR_PIPE_NO_FREE_EID 63
+
+#endif /* CFE_SB_EVENTS_H */
diff --git a/modules/sb/fsw/inc/cfe_sb_msg.h b/modules/sb/fsw/inc/cfe_sb_msg.h
new file mode 100644
index 000000000..93a9de958
--- /dev/null
+++ b/modules/sb/fsw/inc/cfe_sb_msg.h
@@ -0,0 +1,787 @@
+/*
+** 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
+ *
+ * Purpose:
+ * This header file contains structure definitions for all SB command and
+ * telemetry packets
+ *
+ * Author: R.McGraw/SSI
+ *
+ */
+
+#ifndef CFE_SB_MSG_H
+#define CFE_SB_MSG_H
+
+/*
+** Includes
+*/
+#include "common_types.h" /* Basic data types */
+#include "cfe_msg_hdr.h" /* for header definitions */
+#include "cfe_sb_extern_typedefs.h"
+#include "cfe_es_extern_typedefs.h"
+
+/****************************************
+** SB task command packet command codes
+****************************************/
+
+/** \cfesbcmd Software Bus No-Op
+**
+** \par Description
+** This command performs no other function than to increment the
+** command execution counter. The command may be used to verify
+** general aliveness of the Software Bus task.
+**
+** \cfecmdmnemonic \SB_NOOP
+**
+** \par Command Structure
+** #CFE_SB_NoopCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with the
+** following telemetry:
+** - \b \c \SB_CMDPC - command execution counter will
+** increment
+** - The #CFE_SB_CMD0_RCVD_EID informational event message will
+** be generated
+**
+** \par Error Conditions
+** There are no error conditions for this command. If the Software
+** Bus receives the command, the event is sent (although it
+** may be filtered by EVS) and the counter is incremented
+** unconditionally.
+**
+** \par Criticality
+** None
+**
+** \sa
+*/
+#define CFE_SB_NOOP_CC 0
+
+/** \cfesbcmd Software Bus Reset Counters
+**
+** \par Description
+** This command resets the following counters within the Software
+** Bus housekeeping telemetry:
+** - Command Execution Counter (\SB_CMDPC)
+** - Command Error Counter (\SB_CMDEC)
+**
+** \cfecmdmnemonic \SB_RESETCTRS
+**
+** \par Command Structure
+** #CFE_SB_ResetCountersCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with the
+** following telemetry:
+** - \b \c \SB_CMDPC - command execution counter will
+** increment
+** - The #CFE_SB_CMD1_RCVD_EID informational event message will
+** be generated
+**
+** \par Error Conditions
+** There are no error conditions for this command. If the Software
+** Bus receives the command, the event is sent (although it
+** may be filtered by EVS) and the counter is incremented
+** unconditionally.
+**
+** \par Criticality
+** This command is not inherently dangerous. However, it is
+** possible for ground systems and on-board safing procedures
+** to be designed such that they react to changes in the counter
+** values that are reset by this command.
+**
+** \sa
+*/
+#define CFE_SB_RESET_COUNTERS_CC 1
+
+/** \cfesbcmd Send Software Bus Statistics
+**
+** \par Description
+** This command will cause the SB task to send a statistics packet
+** containing current utilization figures and high water marks which
+** may be useful for checking the margin of the SB platform configuration
+** settings.
+**
+** \cfecmdmnemonic \SB_DUMPSTATS
+**
+** \par Command Structure
+** #CFE_SB_SendSbStatsCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with the
+** following telemetry:
+** - \b \c \SB_CMDPC - command execution counter will increment
+** - Receipt of statistics packet with MsgId #CFE_SB_STATS_TLM_MID
+** - The #CFE_SB_SND_STATS_EID debug event message will be generated. All
+** debug events are filtered by default.
+**
+** \par Error Conditions
+** There are no error conditions for this command. If the Software
+** Bus receives the command, the debug event is sent and the counter
+** is incremented unconditionally.
+**
+** \par Criticality
+** This command is not inherently dangerous. It will create and send
+** a message on the software bus. If performed repeatedly, it is
+** possible that receiver pipes may overflow.
+**
+** \sa
+*/
+#define CFE_SB_SEND_SB_STATS_CC 2
+
+/** \cfesbcmd Write Software Bus Routing Info to a File
+**
+** \par Description
+** This command will create a file containing the software bus routing
+** information. The routing information contains information about every
+** subscription that has been received through the SB subscription APIs.
+** An abosulte path and filename may be specified in the command.
+** If this command field contains an empty string (NULL terminator as
+** the first character) the default file path and name is used.
+** The default file path and name is defined in the platform
+** configuration file as #CFE_PLATFORM_SB_DEFAULT_ROUTING_FILENAME.
+**
+** \cfecmdmnemonic \SB_WRITEROUTING2FILE
+**
+** \par Command Structure
+** #CFE_SB_WriteRoutingInfoCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with the
+** following telemetry:
+** - \b \c \SB_CMDPC - command execution counter will increment.
+** - Specified filename created at specified location. See description.
+** - The #CFE_SB_SND_RTG_EID debug event message will be generated. All
+** debug events are filtered by default.
+**
+** \par Error Conditions
+** - Errors may occur during write operations to the file. Possible
+** causes might be insufficient space in the file system or the
+** filename or file path is improperly specified.
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \SB_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases. See #CFE_SB_SND_RTG_ERR1_EID and #CFE_SB_FILEWRITE_ERR_EID
+**
+** \par Criticality
+** This command is not inherently dangerous. It will create a new
+** file in the file system and could, if performed repeatedly without
+** sufficient file management by the operator, fill the file system.
+*/
+#define CFE_SB_WRITE_ROUTING_INFO_CC 3
+
+/** \cfesbcmd Enable Software Bus Route
+**
+** \par Description
+** This command will enable a particular destination. The destination
+** is specified in terms of MsgID and PipeID. The MsgId and PipeID are
+** parmaters in the command. All destinations are enabled by default.
+** This command is needed only after a #CFE_SB_DISABLE_ROUTE_CC command
+** is used.
+**
+** \cfecmdmnemonic \SB_ENAROUTE
+**
+** \par Command Structure
+** #CFE_SB_EnableRouteCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with the
+** following telemetry:
+** - \b \c \SB_CMDPC - command execution counter will increment
+** - View routing information #CFE_SB_WRITE_ROUTING_INFO_CC to verify
+** enable/disable state change
+** - The #CFE_SB_ENBL_RTE2_EID debug event message will be generated. All
+** debug events are filtered by default.
+** - Destination will begin receiving messages.
+**
+** \par Error Conditions
+** An Error may occur if the MsgId or PipeId parmaters do not pass
+** validation or the destination does not exist.
+
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \SB_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases. See #CFE_SB_ENBL_RTE1_EID or #CFE_SB_ENBL_RTE3_EID
+**
+** \par Criticality
+** This command is not inherently dangerous.
+*/
+#define CFE_SB_ENABLE_ROUTE_CC 4
+
+/** \cfesbcmd Disable Software Bus Route
+**
+** \par Description
+** This command will disable a particular destination. The destination
+** is specified in terms of MsgID and PipeID. The MsgId and PipeID are
+** parmaters in the command. All destinations are enabled by default.
+**
+** \cfecmdmnemonic \SB_DISROUTE
+**
+** \par Command Structure
+** #CFE_SB_DisableRouteCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with the
+** following telemetry:
+** - \b \c \SB_CMDPC - command execution counter will increment
+** - View routing information #CFE_SB_WRITE_ROUTING_INFO_CC to verify
+** enable/disable state change
+** - The #CFE_SB_DSBL_RTE2_EID debug event message will be generated. All
+** debug events are filtered by default.
+** - Destination will stop receiving messages.
+**
+** \par Error Conditions
+** An Error may occur if the MsgId or PipeId parmaters do not pass
+** validation or the destination does not exist.
+
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \SB_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases. See #CFE_SB_DSBL_RTE1_EID or #CFE_SB_DSBL_RTE3_EID
+**
+** \par Criticality
+** This command is not intended to be used in nominal conditions. It is
+** possible to get into a state where a destination cannot be re-enabled
+** without reseting the processor. For instance, sending this command
+** with #CFE_SB_CMD_MID and the SB_Cmd_Pipe would inhibit any ground
+** commanding to the software bus until the processor was reset. There
+** are similar problems that may occur when using this command.
+*/
+#define CFE_SB_DISABLE_ROUTE_CC 5
+
+/** \cfesbcmd Write Pipe Info to a File
+**
+** \par Description
+** This command will create a file containing the software bus pipe
+** information. The pipe information contains information about every
+** pipe that has been created through the #CFE_SB_CreatePipe API. An
+** abosulte path and filename may be specified in the command.
+** If this command field contains an empty string (NULL terminator as
+** the first character) the default file path and name is used.
+** The default file path and name is defined in the platform
+** configuration file as #CFE_PLATFORM_SB_DEFAULT_PIPE_FILENAME.
+**
+** \cfecmdmnemonic \SB_WRITEPIPE2FILE
+**
+** \par Command Structure
+** #CFE_SB_WritePipeInfoCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with the
+** following telemetry:
+** - \b \c \SB_CMDPC - command execution counter will increment.
+** - Specified filename created at specified location. See description.
+** - The #CFE_SB_SND_RTG_EID debug event message will be generated. All
+** debug events are filtered by default.
+**
+** \par Error Conditions
+** - Errors may occur during write operations to the file. Possible
+** causes might be insufficient space in the file system or the
+** filename or file path is improperly specified.
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \SB_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases. See #CFE_SB_SND_RTG_ERR1_EID and #CFE_SB_FILEWRITE_ERR_EID
+**
+** \par Criticality
+** This command is not inherently dangerous. It will create a new
+** file in the file system and could, if performed repeatedly without
+** sufficient file management by the operator, fill the file system.
+*/
+#define CFE_SB_WRITE_PIPE_INFO_CC 7
+
+/** \cfesbcmd Write Map Info to a File
+**
+** \par This command will create a file containing the software bus message
+** map information. The message map is a lookup table (an array of
+** uint16s)that allows fast access to the correct routing table element
+** during a softeware bus send operation. This is diasgnostic
+** information that may be needed due to the dynamic nature of the
+** cFE software bus. An abosulte path and filename may be specified
+** in the command. If this command field contains an empty string
+** (NULL terminator as the first character) the default file path and
+** name is used. The default file path and name is defined in the
+** platform configuration file as #CFE_PLATFORM_SB_DEFAULT_MAP_FILENAME.
+**
+** \cfecmdmnemonic \SB_WRITEMAP2FILE
+**
+** \par Command Structure
+** #CFE_SB_WriteMapInfoCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with the
+** following telemetry:
+** - \b \c \SB_CMDPC - command execution counter will increment.
+** - Specified filename created at specified location. See description.
+** - The #CFE_SB_SND_RTG_EID debug event message will be generated. All
+** debug events are filtered by default.
+**
+** \par Error Conditions
+** - Errors may occur during write operations to the file. Possible
+** causes might be insufficient space in the file system or the
+** filename or file path is improperly specified.
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \SB_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases. See #CFE_SB_SND_RTG_ERR1_EID and #CFE_SB_FILEWRITE_ERR_EID
+**
+** \par Criticality
+** This command is not inherently dangerous. It will create a new
+** file in the file system and could, if performed repeatedly without
+** sufficient file management by the operator, fill the file system.
+*/
+#define CFE_SB_WRITE_MAP_INFO_CC 8
+
+/** \cfesbcmd Enable Subscription Reporting Command
+**
+** \par Description
+** This command will enable subscription reporting and is intended to
+** be used only by the CFS SBN (Software Bus Networking) Application.
+** It is not intended to be sent from the ground or used by operations.
+** When subscription reporting is enabled, SB will generate
+** and send a software bus packet for each subscription received.
+** The software bus packet that is sent contains the information
+** received in the subscription API. This subscription report is
+** neeeded by SBN if offboard routing is required.
+*
+** \cfecmdmnemonic \SB_ENASUBRPTG
+**
+** \par Command Structure
+** #CFE_SB_EnableSubReportingCmd_t
+**
+** \par Command Verification
+** Successful execution of this command will result in the sending
+** of a packet (with the #CFE_SB_ONESUB_TLM_MID MsgId) for each
+** subscription received by SB through the subscription APIs.
+**
+** \par Error Conditions
+** None
+**
+** \par Criticality
+** None
+**
+** \sa #CFE_SB_SingleSubscriptionTlm_t, #CFE_SB_DISABLE_SUB_REPORTING_CC,
+** #CFE_SB_SEND_PREV_SUBS_CC
+*/
+#define CFE_SB_ENABLE_SUB_REPORTING_CC 9
+
+/** \cfesbcmd Disable Subscription Reporting Command
+**
+** \par Description
+** This command will disable subscription reporting and is intended to
+** be used only by the CFS SBN (Software Bus Networking) Application.
+** It is not intended to be sent from the ground or used by operations.
+** When subscription reporting is enabled, SB will generate
+** and send a software bus packet for each subscription received.
+** The software bus packet that is sent contains the information
+** received in the subscription API. This subscription report is
+** neeeded by SBN if offboard routing is required.
+**
+** \cfecmdmnemonic \SB_DISSUBRPTG
+**
+** \par Command Structure
+** #CFE_SB_DisableSubReportingCmd_t
+**
+** \par Command Verification
+** Successful execution of this command will result in the suppression
+** of packets (with the #CFE_SB_ONESUB_TLM_MID MsgId) for each
+** subscription received by SB through the subscription APIs.
+**
+** \par Error Conditions
+** None
+**
+** \par Criticality
+** None
+**
+** \sa #CFE_SB_SingleSubscriptionTlm_t, #CFE_SB_ENABLE_SUB_REPORTING_CC,
+** #CFE_SB_SEND_PREV_SUBS_CC
+*/
+#define CFE_SB_DISABLE_SUB_REPORTING_CC 10
+
+/** \cfesbcmd Send Previous Subscriptions Command
+**
+** \par This command generates a series of packets that contain information
+** regarding all subscriptions previously received by SB.
+** This command is intended to be used only by the CFS SBN(Software Bus
+** Networking) Application.
+** It is not intended to be sent from the ground or used by operations.
+** When this command is received the software bus will generate and
+** send a series of packets containing information about all subscription
+** previously received.
+**
+** \cfecmdmnemonic \SB_SENDPREVSUBS
+**
+** \par Command Structure
+** #CFE_SB_SendPrevSubsCmd_t
+**
+** \par Command Verification
+** Successful execution of this command will result in a series
+** of packets (with the #CFE_SB_ALLSUBS_TLM_MID MsgId) being sent
+** on the software bus.
+**
+** \par Error Conditions
+** None
+**
+** \par Criticality
+** None
+**
+** \sa #CFE_SB_AllSubscriptionsTlm_t, #CFE_SB_ENABLE_SUB_REPORTING_CC,
+** #CFE_SB_DISABLE_SUB_REPORTING_CC
+*/
+#define CFE_SB_SEND_PREV_SUBS_CC 11
+
+/****************************
+** SB Command Formats **
+*****************************/
+
+/*
+ * SB Messages which have no payload are each
+ * given unique typedefs to follow the command handler convention
+ *
+ * For the SB application these is mapped to the CFE_MSG_CommandHeader_t type,
+ * as they contain only a primary + command header.
+ */
+typedef CFE_MSG_CommandHeader_t CFE_SB_NoopCmd_t;
+typedef CFE_MSG_CommandHeader_t CFE_SB_ResetCountersCmd_t;
+typedef CFE_MSG_CommandHeader_t CFE_SB_EnableSubReportingCmd_t;
+typedef CFE_MSG_CommandHeader_t CFE_SB_DisableSubReportingCmd_t;
+typedef CFE_MSG_CommandHeader_t CFE_SB_SendSbStatsCmd_t;
+typedef CFE_MSG_CommandHeader_t CFE_SB_SendPrevSubsCmd_t;
+
+/**
+** \brief Write File Info Command Payload
+**
+** This structure contains a generic definition used by SB commands that write to a file
+*/
+typedef struct CFE_SB_WriteFileInfoCmd_Payload
+{
+ char Filename[CFE_MISSION_MAX_PATH_LEN]; /**< \brief Path and Filename of data to be loaded */
+} CFE_SB_WriteFileInfoCmd_Payload_t;
+
+/**
+ * \brief Write File Info Command
+ */
+typedef struct CFE_SB_WriteFileInfoCmd
+{
+ CFE_MSG_CommandHeader_t Hdr; /**< \brief Command header */
+ CFE_SB_WriteFileInfoCmd_Payload_t Payload; /**< \brief Command payload */
+} CFE_SB_WriteFileInfoCmd_t;
+
+/*
+ * Create a unique typedef for each of the commands that share this format.
+ */
+typedef CFE_SB_WriteFileInfoCmd_t CFE_SB_WriteRoutingInfoCmd_t;
+typedef CFE_SB_WriteFileInfoCmd_t CFE_SB_WritePipeInfoCmd_t;
+typedef CFE_SB_WriteFileInfoCmd_t CFE_SB_WriteMapInfoCmd_t;
+
+/**
+** \brief Enable/Disable Route Command Payload
+**
+** This structure contains a definition used by two SB commands,
+** 'Enable Route' #CFE_SB_ENABLE_ROUTE_CC and 'Disable Route' #CFE_SB_DISABLE_ROUTE_CC.
+** A route is the destination pipe for a particular message and is therefore defined
+** as a MsgId and PipeId combination.
+*/
+typedef struct CFE_SB_RouteCmd_Payload
+{
+
+ CFE_SB_MsgId_t MsgId; /**< \brief Message ID of route to be enabled or disabled #CFE_SB_MsgId_t */
+ CFE_SB_PipeId_t Pipe; /**< \brief Pipe ID of route to be enabled or disabled #CFE_SB_PipeId_t */
+ uint8 Spare; /**<\brief Spare byte to make command even number of bytes */
+} CFE_SB_RouteCmd_Payload_t;
+
+/**
+ * \brief Enable/Disable Route Command
+ */
+typedef struct CFE_SB_RouteCmd
+{
+ CFE_MSG_CommandHeader_t Hdr; /**< \brief Command header */
+ CFE_SB_RouteCmd_Payload_t Payload; /**< \brief Command payload */
+} CFE_SB_RouteCmd_t;
+
+/*
+ * Create a unique typedef for each of the commands that share this format.
+ */
+typedef CFE_SB_RouteCmd_t CFE_SB_EnableRouteCmd_t;
+typedef CFE_SB_RouteCmd_t CFE_SB_DisableRouteCmd_t;
+
+/****************************
+** SB Telemetry Formats **
+*****************************/
+
+/**
+** \cfesbtlm Software Bus task housekeeping Packet
+*/
+typedef struct CFE_SB_HousekeepingTlm_Payload
+{
+
+ uint8 CommandCounter; /**< \cfetlmmnemonic \SB_CMDPC
+ \brief Count of valid commands received */
+ uint8 CommandErrorCounter; /**< \cfetlmmnemonic \SB_CMDEC
+ \brief Count of invalid commands received */
+ uint8 NoSubscribersCounter; /**< \cfetlmmnemonic \SB_NOSUBEC
+ \brief Count pkts sent with no subscribers */
+ uint8 MsgSendErrorCounter; /**< \cfetlmmnemonic \SB_MSGSNDEC
+ \brief Count of message send errors */
+
+ uint8 MsgReceiveErrorCounter; /**< \cfetlmmnemonic \SB_MSGRECEC
+ \brief Count of message receive errors */
+ uint8 InternalErrorCounter; /**< \cfetlmmnemonic \SB_INTERNALEC
+ \brief Count of queue read or write errors */
+ uint8 CreatePipeErrorCounter; /**< \cfetlmmnemonic \SB_NEWPIPEEC
+ \brief Count of errors in create pipe API */
+ uint8 SubscribeErrorCounter; /**< \cfetlmmnemonic \SB_SUBSCREC
+ \brief Count of errors in subscribe API */
+ uint8 PipeOptsErrorCounter; /**< \cfetlmmnemonic \SB_PIPEOPTSEC
+ \brief Count of errors in set/get pipe options API */
+ uint8 DuplicateSubscriptionsCounter; /**< \cfetlmmnemonic \SB_DUPSUBCNT
+ \brief Count of duplicate subscriptions */
+ uint8 GetPipeIdByNameErrorCounter; /**< \cfetlmmnemonic \SB_GETPIPEIDBYNAMEEC
+ \brief Count of errors in get pipe id by name API */
+ uint8 Spare2Align[1]; /**< \cfetlmmnemonic \SB_SPARE2ALIGN
+ \brief Spare bytes to ensure alignment */
+
+ uint16 PipeOverflowErrorCounter; /**< \cfetlmmnemonic \SB_PIPEOVREC
+ \brief Count of pipe overflow errors */
+ uint16 MsgLimitErrorCounter; /**< \cfetlmmnemonic \SB_MSGLIMEC
+ \brief Count of msg id to pipe errors */
+
+ CFE_ES_MemHandle_t MemPoolHandle; /**< \cfetlmmnemonic \SB_MEMPOOLHANDLE
+ \brief Handle to SB's Memory Pool */
+
+ uint32 MemInUse; /**< \cfetlmmnemonic \SB_MEMINUSE
+ \brief Memory in use */
+
+ uint32 UnmarkedMem; /**< \cfetlmmnemonic \SB_UNMARKEDMEM
+ \brief cfg param CFE_PLATFORM_SB_BUF_MEMORY_BYTES minus Peak Memory in use */
+} CFE_SB_HousekeepingTlm_Payload_t;
+
+typedef struct CFE_SB_HousekeepingTlm
+{
+ CFE_MSG_TelemetryHeader_t Hdr; /**< \brief Telemetry header */
+ CFE_SB_HousekeepingTlm_Payload_t Payload; /**< \brief Telemetry payload */
+} CFE_SB_HousekeepingTlm_t;
+
+/**
+** \brief SB Pipe Depth Statistics
+**
+** Used in SB Statistics Telemetry Packet #CFE_SB_StatsTlm_t
+*/
+typedef struct CFE_SB_PipeDepthStats
+{
+
+ CFE_SB_PipeId_t PipeId; /**< \cfetlmmnemonic \SB_PDPIPEID
+ \brief Pipe Id associated with the stats below */
+ uint16 MaxQueueDepth; /**< \cfetlmmnemonic \SB_PDDEPTH
+ \brief Number of messages the pipe can hold */
+ uint16 CurrentQueueDepth; /**< \cfetlmmnemonic \SB_PDINUSE
+ \brief Number of messages currently on the pipe */
+ uint16 PeakQueueDepth; /**< \cfetlmmnemonic \SB_PDPKINUSE
+ \brief Peak number of messages that have been on the pipe */
+ uint16 Spare; /**< \cfetlmmnemonic \SB_PDSPARE
+ \brief Spare word to ensure alignment */
+
+} CFE_SB_PipeDepthStats_t;
+
+/**
+** \brief SB Pipe Information File Entry
+**
+** This statistics structure is output as part of the CFE SB
+** "Send Pipe Info" command (CFE_SB_SEND_PIPE_INFO_CC).
+**
+** Previous versions of CFE simply wrote the internal CFE_SB_PipeD_t object
+** to the file, but this also contains information such as pointers which are
+** not relevant outside the running CFE process.
+**
+** By defining the pipe info structure separately, it also provides some
+** independence, such that the internal CFE_SB_PipeD_t definition
+** can evolve without changing the binary format of the information
+** file.
+*/
+typedef struct CFE_SB_PipeInfoEntry
+{
+ CFE_SB_PipeId_t PipeId; /**< The runtime ID of the pipe */
+ CFE_ES_AppId_t AppId; /**< The runtime ID of the application that owns the pipe */
+ char PipeName[CFE_MISSION_MAX_API_LEN]; /**< The Name of the pipe */
+ char AppName[CFE_MISSION_MAX_API_LEN]; /**< The Name of the application that owns the pipe */
+ uint16 MaxQueueDepth; /**< The allocated depth of the pipe (max capacity) */
+ uint16 CurrentQueueDepth; /**< The current depth of the pipe */
+ uint16 PeakQueueDepth; /**< The peak depth of the pipe (high watermark) */
+ uint16 SendErrors; /**< Number of errors when writing to this pipe */
+ uint8 Opts; /**< Pipe options set (bitmask) */
+ uint8 Spare[3]; /**< Padding to make this structure a multiple of 4 bytes */
+
+} CFE_SB_PipeInfoEntry_t;
+
+/**
+** \cfesbtlm SB Statistics Telemetry Packet
+**
+** SB Statistics packet sent in response to #CFE_SB_SEND_SB_STATS_CC
+*/
+typedef struct CFE_SB_StatsTlm_Payload
+{
+
+ uint32 MsgIdsInUse; /**< \cfetlmmnemonic \SB_SMMIDIU
+ \brief Current number of MsgIds with a destination */
+ uint32 PeakMsgIdsInUse; /**< \cfetlmmnemonic \SB_SMPMIDIU
+ \brief Peak number of MsgIds with a destination */
+ uint32 MaxMsgIdsAllowed; /**< \cfetlmmnemonic \SB_SMMMIDALW
+ \brief cFE Cfg Param \link #CFE_PLATFORM_SB_MAX_MSG_IDS \endlink */
+
+ uint32 PipesInUse; /**< \cfetlmmnemonic \SB_SMPIU
+ \brief Number of pipes currently in use */
+ uint32 PeakPipesInUse; /**< \cfetlmmnemonic \SB_SMPPIU
+ \brief Peak number of pipes since last reboot */
+ uint32 MaxPipesAllowed; /**< \cfetlmmnemonic \SB_SMMPALW
+ \brief cFE Cfg Param \link #CFE_PLATFORM_SB_MAX_PIPES \endlink */
+
+ uint32 MemInUse; /**< \cfetlmmnemonic \SB_SMBMIU
+ \brief Memory bytes currently in use for SB msg transfers */
+ uint32 PeakMemInUse; /**< \cfetlmmnemonic \SB_SMPBMIU
+ \brief Peak memory bytes in use for SB msg transfers */
+ uint32 MaxMemAllowed; /**< \cfetlmmnemonic \SB_SMMBMALW
+ \brief cFE Cfg Param \link #CFE_PLATFORM_SB_BUF_MEMORY_BYTES \endlink */
+
+ uint32 SubscriptionsInUse; /**< \cfetlmmnemonic \SB_SMSIU
+ \brief Number of current subscriptions */
+ uint32 PeakSubscriptionsInUse; /**< \cfetlmmnemonic \SB_SMPSIU
+ \brief Peak number of subscriptions */
+ uint32 MaxSubscriptionsAllowed; /**< \cfetlmmnemonic \SB_SMMSALW
+ \brief product of \link #CFE_PLATFORM_SB_MAX_MSG_IDS \endlink
+ and \link #CFE_PLATFORM_SB_MAX_DEST_PER_PKT \endlink */
+
+ uint32 SBBuffersInUse; /**< \cfetlmmnemonic \SB_SMSBBIU
+ \brief Number of SB message buffers currently in use */
+ uint32 PeakSBBuffersInUse; /**< \cfetlmmnemonic \SB_SMPSBBIU
+ \brief Max number of SB message buffers in use */
+
+ uint32 MaxPipeDepthAllowed; /**< \cfetlmmnemonic \SB_SMMPDALW
+ \brief Maximum allowed pipe depth */
+ CFE_SB_PipeDepthStats_t
+ PipeDepthStats[CFE_MISSION_SB_MAX_PIPES]; /**< \cfetlmmnemonic \SB_SMPDS
+ \brief Pipe Depth Statistics #CFE_SB_PipeDepthStats_t*/
+} CFE_SB_StatsTlm_Payload_t;
+
+typedef struct CFE_SB_StatsTlm
+{
+ CFE_MSG_TelemetryHeader_t Hdr; /**< \brief Telemetry header */
+ CFE_SB_StatsTlm_Payload_t Payload; /**< \brief Telemetry payload */
+} CFE_SB_StatsTlm_t;
+
+/**
+** \brief SB Routing File Entry
+**
+** Structure of one element of the routing information in response to #CFE_SB_WRITE_ROUTING_INFO_CC
+*/
+typedef struct CFE_SB_RoutingFileEntry
+{
+ CFE_SB_MsgId_t MsgId; /**< \brief Message Id portion of the route */
+ CFE_SB_PipeId_t PipeId; /**< \brief Pipe Id portion of the route */
+ uint8 State; /**< \brief Route Enabled or Disabled */
+ uint16 MsgCnt; /**< \brief Number of msgs with this MsgId sent to this PipeId */
+ char AppName[CFE_MISSION_MAX_API_LEN]; /**< \brief Pipe Depth Statistics */
+ char PipeName[CFE_MISSION_MAX_API_LEN]; /**< \brief Pipe Depth Statistics */
+} CFE_SB_RoutingFileEntry_t;
+
+/**
+** \brief SB Map File Entry
+**
+** Structure of one element of the map information in response to #CFE_SB_WRITE_MAP_INFO_CC
+*/
+typedef struct CFE_SB_MsgMapFileEntry
+{
+ 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;
+
+/**
+** \cfesbtlm SB Subscription Report Packet
+**
+** This structure defines the pkt sent by SB when a subscription or
+** a request to unsubscribe is received while subscription reporting is enabled.
+** By default subscription reporting is disabled. This feature is intended to be
+** used primarily by Software Bus Networking Application (SBN)
+**
+** \sa #CFE_SB_ENABLE_SUB_REPORTING_CC, #CFE_SB_DISABLE_SUB_REPORTING_CC
+*/
+typedef struct CFE_SB_SingleSubscriptionTlm_Payload
+{
+
+ uint8 SubType; /**< \brief Subscription or Unsubscription */
+ CFE_SB_MsgId_t MsgId; /**< \brief MsgId subscribed or unsubscribe to */
+ CFE_SB_Qos_t Qos; /**< \brief Quality of Service, used only for interprocessor communication */
+ CFE_SB_PipeId_t Pipe; /**< \brief Destination pipe id to send above msg id */
+
+} CFE_SB_SingleSubscriptionTlm_Payload_t;
+
+typedef struct CFE_SB_SingleSubscriptionTlm
+{
+ CFE_MSG_TelemetryHeader_t Hdr; /**< \brief Telemetry header */
+ CFE_SB_SingleSubscriptionTlm_Payload_t Payload; /**< \brief Telemetry payload */
+} CFE_SB_SingleSubscriptionTlm_t;
+
+/**
+** \brief SB Previous Subscriptions Entry
+**
+** This structure defines an entry used in the CFE_SB_PrevSubsPkt_t
+** Intended to be used primarily by Software Bus Networking Application (SBN)
+**
+** Used in structure definition #CFE_SB_AllSubscriptionsTlm_t
+*/
+typedef struct CFE_SB_SubEntries
+{
+
+ CFE_SB_MsgId_t MsgId; /**< \brief MsgId portion of the subscription */
+ CFE_SB_Qos_t Qos; /**< \brief Qos portion of the subscription */
+ CFE_SB_PipeId_t Pipe; /**< \brief PipeId portion of the subscription */
+
+} CFE_SB_SubEntries_t;
+
+/**
+** \cfesbtlm SB Previous Subscriptions Packet
+**
+** This structure defines the pkt(s) sent by SB that contains a list of all current
+** subscriptions. This pkt is generated on cmd and intended to be used primarily by
+** the Software Bus Networking Application (SBN). Typically, when the cmd is received
+** there are more subscriptions than can fit in one pkt. The complete list of
+** subscriptions is sent via a series of segmented pkts.
+*/
+typedef struct CFE_SB_AllSubscriptionsTlm_Payload
+{
+
+ uint32 PktSegment; /**< \brief Pkt number(starts at 1) in the series */
+ uint32 TotalSegments; /**< \brief Total number of pkts needed to complete the request */
+ uint32 Entries; /**< \brief Number of entries in the pkt */
+ CFE_SB_SubEntries_t Entry[CFE_SB_SUB_ENTRIES_PER_PKT]; /**< \brief Array of #CFE_SB_SubEntries_t entries */
+} CFE_SB_AllSubscriptionsTlm_Payload_t;
+
+typedef struct CFE_SB_AllSubscriptionsTlm
+{
+ CFE_MSG_TelemetryHeader_t Hdr; /**< \brief Telemetry header */
+ CFE_SB_AllSubscriptionsTlm_Payload_t Payload; /**< \brief Telemetry payload */
+} CFE_SB_AllSubscriptionsTlm_t;
+
+#endif /* CFE_SB_MSG_H */
diff --git a/modules/sb/fsw/src/cfe_sb_api.c b/modules/sb/fsw/src/cfe_sb_api.c
new file mode 100644
index 000000000..764f189cc
--- /dev/null
+++ b/modules/sb/fsw/src/cfe_sb_api.c
@@ -0,0 +1,2195 @@
+/*
+** 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_sb_api.c
+**
+** Purpose:
+** This file contains the source code for the SB API's.
+**
+** Notes: The following 4 terms have been, or are used in the cFS architecture and implementation
+**
+** StreamId - First 16 bits of CCSDS Space Packet Protocol (SPP) 133.0-B.1c2 Blue Book
+** packet primary header. It contains the 3 bit Version Number, 1 bit Packet Type ID,
+** 1 bit Secondary Header flag, and 11 bit Application Process ID
+** It was used in earlier cFS implementaions and is defined here for historical reference
+** It is NOT exposed to user applications.
+**
+** MsgId - Unique numeric message identifier within a mission namespace. It is used by cFS
+** applications to the identify messages for publishing and subscribing
+** It is used by the SB API and encoded in a mission defended way in the header of
+** all cFS messages.
+** It is exposed to all cFS applications
+**
+** ApId - CCSDS Application Process Id field in the primary header.
+** It has default bit mask of 0x07FF and is part of the cFS message Id
+** It should not be confused with the cFE Executive Services (ES) term appId which
+** identifies the software application/component
+** It is NOT exposed to user applications.
+**
+** MsgIdkey - This is a unique numeric key within a mission namespace that is used with
+** cFS software bus internal structures.
+** It is algorithmically created in a mission defined way from the MsgId to support
+** efficient lookup and mapping implementations
+** It is NOT exposed to user applications.
+**
+** Author: R.McGraw/SSI
+** J.Wilmot/NASA
+**
+******************************************************************************/
+
+/*
+** Include Files
+*/
+#include "cfe_sb_module_all.h"
+
+#include
+
+/*
+ * Macro to reflect size of PipeDepthStats Telemetry array -
+ * this may or may not be the same as CFE_SB_MSG_MAX_PIPES
+ */
+#define CFE_SB_TLM_PIPEDEPTHSTATS_SIZE \
+ (sizeof(CFE_SB_Global.StatTlmMsg.Payload.PipeDepthStats) / \
+ sizeof(CFE_SB_Global.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_PipeId_ToIndex - See API and header file for details
+ */
+CFE_Status_t CFE_SB_PipeId_ToIndex(CFE_SB_PipeId_t PipeID, uint32 *Idx)
+{
+ return CFE_ResourceId_ToIndex(CFE_RESOURCEID_UNWRAP(PipeID), CFE_SB_PIPEID_BASE, CFE_PLATFORM_SB_MAX_PIPES, Idx);
+}
+
+/*
+ * Function: CFE_SB_CreatePipe - See API and header file for details
+ */
+int32 CFE_SB_CreatePipe(CFE_SB_PipeId_t *PipeIdPtr, uint16 Depth, const char *PipeName)
+{
+ CFE_ES_AppId_t AppId;
+ CFE_ES_TaskId_t TskId;
+ osal_id_t SysQueueId;
+ int32 Status;
+ CFE_SB_PipeD_t * PipeDscPtr;
+ CFE_ResourceId_t PendingPipeId = CFE_RESOURCEID_UNDEFINED;
+ uint16 PendingEventId;
+ char FullName[(OS_MAX_API_NAME * 2)];
+
+ Status = CFE_SUCCESS;
+ SysQueueId = OS_OBJECT_ID_UNDEFINED;
+ PendingEventId = 0;
+ PipeDscPtr = NULL;
+
+ /*
+ * Get caller AppId.
+ *
+ * This is needed for both success and failure cases,
+ * as it is stored in the Pipe Descriptor on success,
+ * and used for events on failure, so get it now.
+ */
+ CFE_ES_GetAppID(&AppId);
+
+ /* get callers TaskId */
+ CFE_ES_GetTaskID(&TskId);
+
+ /* check input parameters */
+ if ((PipeIdPtr == NULL) || (Depth > OS_QUEUE_MAX_DEPTH) || (Depth == 0))
+ {
+ PendingEventId = CFE_SB_CR_PIPE_BAD_ARG_EID;
+ Status = CFE_SB_BAD_ARGUMENT;
+ }
+ else
+ {
+ /* Get an available Pipe Descriptor which must be done while locked */
+ CFE_SB_LockSharedData(__func__, __LINE__);
+
+ /* get first available entry in pipe table */
+ PendingPipeId =
+ CFE_ResourceId_FindNext(CFE_SB_Global.LastPipeId, CFE_PLATFORM_SB_MAX_PIPES, CFE_SB_CheckPipeDescSlotUsed);
+ PipeDscPtr = CFE_SB_LocatePipeDescByID(CFE_SB_PIPEID_C(PendingPipeId));
+
+ /* if pipe table is full, send event and return error */
+ if (PipeDscPtr == NULL)
+ {
+ PendingEventId = CFE_SB_MAX_PIPES_MET_EID;
+ Status = CFE_SB_MAX_PIPES_MET;
+ }
+ else
+ {
+ /* Fully clear the entry, just in case of stale data */
+ memset(PipeDscPtr, 0, sizeof(*PipeDscPtr));
+
+ CFE_SB_PipeDescSetUsed(PipeDscPtr, CFE_RESOURCEID_RESERVED);
+ CFE_SB_Global.LastPipeId = PendingPipeId;
+ }
+
+ CFE_SB_UnlockSharedData(__func__, __LINE__);
+ }
+
+ if (Status == CFE_SUCCESS)
+ {
+ /* create the queue */
+ Status = OS_QueueCreate(&SysQueueId, PipeName, Depth, sizeof(CFE_SB_BufferD_t *), 0);
+ if (Status == OS_SUCCESS)
+ {
+ /* just translate the RC to CFE */
+ Status = CFE_SUCCESS;
+ }
+ else
+ {
+ if (Status == OS_ERR_NAME_TAKEN)
+ {
+ PendingEventId = CFE_SB_CR_PIPE_NAME_TAKEN_EID;
+ }
+ else if (Status == OS_ERR_NO_FREE_IDS)
+ {
+ PendingEventId = CFE_SB_CR_PIPE_NO_FREE_EID;
+ }
+ else
+ {
+ /* some other unexpected error */
+ PendingEventId = CFE_SB_CR_PIPE_ERR_EID;
+ }
+
+ /* translate OSAL error to CFE error code */
+ Status = CFE_SB_PIPE_CR_ERR;
+ }
+ }
+
+ CFE_SB_LockSharedData(__func__, __LINE__);
+
+ if (Status == CFE_SUCCESS)
+ {
+ /* fill in the pipe table fields */
+ PipeDscPtr->SysQueueId = SysQueueId;
+ PipeDscPtr->MaxQueueDepth = Depth;
+ PipeDscPtr->AppId = AppId;
+
+ CFE_SB_PipeDescSetUsed(PipeDscPtr, PendingPipeId);
+
+ /* Increment the Pipes in use ctr and if it's > the high water mark,*/
+ /* adjust the high water mark */
+ CFE_SB_Global.StatTlmMsg.Payload.PipesInUse++;
+ if (CFE_SB_Global.StatTlmMsg.Payload.PipesInUse > CFE_SB_Global.StatTlmMsg.Payload.PeakPipesInUse)
+ {
+ CFE_SB_Global.StatTlmMsg.Payload.PeakPipesInUse = CFE_SB_Global.StatTlmMsg.Payload.PipesInUse;
+ } /* end if */
+ }
+ else
+ {
+ /*
+ * If a descriptor had been allocated, then free it.
+ */
+ if (PipeDscPtr != NULL)
+ {
+ CFE_SB_PipeDescSetFree(PipeDscPtr);
+ PipeDscPtr = NULL;
+ }
+ PendingPipeId = CFE_RESOURCEID_UNDEFINED;
+
+ /* Increment error counter for all errors */
+ CFE_SB_Global.HKTlmMsg.Payload.CreatePipeErrorCounter++;
+ }
+
+ CFE_SB_UnlockSharedData(__func__, __LINE__);
+
+ /* Send any pending events now, after final unlock */
+ if (Status == CFE_SUCCESS)
+ {
+ /* send debug event */
+ CFE_EVS_SendEventWithAppID(CFE_SB_PIPE_ADDED_EID, CFE_EVS_EventType_DEBUG, CFE_SB_Global.AppId,
+ "Pipe Created:name %s,id %d,app %s", PipeName,
+ (int)CFE_ResourceId_ToInteger(PendingPipeId), CFE_SB_GetAppTskName(TskId, FullName));
+
+ /* give the pipe handle to the caller */
+ *PipeIdPtr = CFE_SB_PIPEID_C(PendingPipeId);
+ }
+ else
+ {
+ switch (PendingEventId)
+ {
+ case CFE_SB_CR_PIPE_BAD_ARG_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_CR_PIPE_BAD_ARG_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "CreatePipeErr:Bad Input Arg:app=%s,ptr=0x%lx,depth=%d,maxdepth=%d",
+ CFE_SB_GetAppTskName(TskId, FullName), (unsigned long)PipeIdPtr, (int)Depth,
+ OS_QUEUE_MAX_DEPTH);
+ break;
+
+ case CFE_SB_MAX_PIPES_MET_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_MAX_PIPES_MET_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "CreatePipeErr:Max Pipes(%d)In Use.app %s", CFE_PLATFORM_SB_MAX_PIPES,
+ CFE_SB_GetAppTskName(TskId, FullName));
+ break;
+ case CFE_SB_CR_PIPE_NAME_TAKEN_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_CR_PIPE_NAME_TAKEN_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "CreatePipeErr:OS_QueueCreate failed, name taken (app=%s, name=%s)",
+ CFE_SB_GetAppTskName(TskId, FullName), PipeName);
+ break;
+ case CFE_SB_CR_PIPE_NO_FREE_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_CR_PIPE_NO_FREE_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "CreatePipeErr:OS_QueueCreate failed, no free id's (app=%s)",
+ CFE_SB_GetAppTskName(TskId, FullName));
+ break;
+ case CFE_SB_CR_PIPE_ERR_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_CR_PIPE_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "CreatePipeErr:OS_QueueCreate returned %d,app %s", (int)Status,
+ CFE_SB_GetAppTskName(TskId, FullName));
+ break;
+ }
+ }
+
+ return Status;
+
+} /* end CFE_SB_CreatePipe */
+
+/*
+ * Function: CFE_SB_DeletePipe - See API and header file for details
+ */
+int32 CFE_SB_DeletePipe(CFE_SB_PipeId_t PipeId)
+{
+ CFE_ES_AppId_t CallerId;
+ int32 Status = 0;
+
+ /* get the callers Application Id */
+ CFE_ES_GetAppID(&CallerId);
+
+ Status = CFE_SB_DeletePipeFull(PipeId, CallerId);
+
+ return Status;
+
+} /* end CFE_SB_DeletePipe */
+
+/******************************************************************************
+** Function: CFE_SB_DeletePipeWithAppId()
+**
+** Purpose:
+**
+**
+** Arguments:
+** PipeId - The ID of the pipe to delete.
+**
+** Return:
+** CFE_SUCCESS or cFE Error Code
+*/
+int32 CFE_SB_DeletePipeWithAppId(CFE_SB_PipeId_t PipeId, CFE_ES_AppId_t AppId)
+{
+ int32 Status = 0;
+
+ Status = CFE_SB_DeletePipeFull(PipeId, AppId);
+
+ return Status;
+
+} /* 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()
+**
+** Purpose:
+** Will unsubscribe to all routes associated with the given pipe id, then remove
+** pipe from the pipe table.
+**
+** NOTE:This function cannot be called directly, it would not be semaphore protected
+**
+** Arguments:
+** PipeId - The ID of the pipe to delete.
+**
+** Return:
+** CFE_SUCCESS or cFE Error Code
+*/
+int32 CFE_SB_DeletePipeFull(CFE_SB_PipeId_t PipeId, CFE_ES_AppId_t AppId)
+{
+ CFE_SB_PipeD_t * PipeDscPtr;
+ int32 Status;
+ CFE_ES_TaskId_t TskId;
+ CFE_SB_BufferD_t * BufDscPtr;
+ osal_id_t SysQueueId;
+ char FullName[(OS_MAX_API_NAME * 2)];
+ size_t BufDscSize;
+ CFE_SB_RemovePipeCallback_t Args;
+ uint16 PendingEventID;
+
+ Status = CFE_SUCCESS;
+ PendingEventID = 0;
+ SysQueueId = OS_OBJECT_ID_UNDEFINED;
+ BufDscPtr = NULL;
+
+ /* take semaphore to prevent a task switch during this call */
+ CFE_SB_LockSharedData(__func__, __LINE__);
+
+ /* check input parameter */
+ PipeDscPtr = CFE_SB_LocatePipeDescByID(PipeId);
+ if (!CFE_SB_PipeDescIsMatch(PipeDscPtr, PipeId))
+ {
+ PendingEventID = CFE_SB_DEL_PIPE_ERR1_EID;
+ Status = CFE_SB_BAD_ARGUMENT;
+ }
+ /* check that the given AppId is the owner of the pipe */
+ else if (!CFE_RESOURCEID_TEST_EQUAL(AppId, PipeDscPtr->AppId))
+ {
+ PendingEventID = CFE_SB_DEL_PIPE_ERR2_EID;
+ Status = CFE_SB_BAD_ARGUMENT;
+ }
+ else
+ {
+ /* Remove the pipe from all routes */
+ Args.PipeId = PipeId;
+ Args.FullName = FullName;
+ CFE_SBR_ForEachRouteId(CFE_SB_RemovePipeFromRoute, &Args, NULL);
+
+ /*
+ * With the route removed there should be no new messages written to this pipe,
+ *
+ * but the pipe ID itself also needs to be invalidated now (before releasing lock) to make
+ * sure that no no subscriptions/routes can be added either.
+ *
+ * However we must first save certain state data for later deletion.
+ */
+ SysQueueId = PipeDscPtr->SysQueueId;
+ BufDscPtr = PipeDscPtr->LastBuffer;
+
+ /*
+ * Mark entry as "reserved" so other resources can be deleted
+ * while the SB global is unlocked. This prevents other tasks
+ * from trying to use this Pipe Desc slot, and also should prevents
+ * any task from re-subscribing to this pipe.
+ */
+ CFE_SB_PipeDescSetUsed(PipeDscPtr, CFE_RESOURCEID_RESERVED);
+ }
+
+ CFE_SB_UnlockSharedData(__func__, __LINE__);
+
+ /* remove any messages that might be on the pipe */
+ if (Status == CFE_SUCCESS)
+ {
+ while (true)
+ {
+ /* decrement refcount of any previous buffer */
+ if (BufDscPtr != NULL)
+ {
+ CFE_SB_LockSharedData(__func__, __LINE__);
+ CFE_SB_DecrBufUseCnt(BufDscPtr);
+ CFE_SB_UnlockSharedData(__func__, __LINE__);
+ BufDscPtr = NULL;
+ }
+
+ if (OS_QueueGet(SysQueueId, &BufDscPtr, sizeof(BufDscPtr), &BufDscSize, OS_CHECK) != OS_SUCCESS)
+ {
+ /* no more messages */
+ break;
+ }
+ }
+
+ /* Delete the underlying OS queue */
+ OS_QueueDelete(SysQueueId);
+ }
+
+ /*
+ * Final cleanup with global data locked
+ */
+ CFE_SB_LockSharedData(__func__, __LINE__);
+
+ if (Status == CFE_SUCCESS)
+ {
+ CFE_SB_PipeDescSetFree(PipeDscPtr);
+ --CFE_SB_Global.StatTlmMsg.Payload.PipesInUse;
+ }
+ else if (PendingEventID != 0)
+ {
+ CFE_SB_Global.HKTlmMsg.Payload.CreatePipeErrorCounter++;
+ }
+
+ CFE_SB_UnlockSharedData(__func__, __LINE__);
+
+ if (Status == CFE_SUCCESS)
+ {
+ /*
+ * Get the app name of the actual pipe owner for the event string
+ * as this may be different than the task doing the deletion.
+ *
+ * Note: If this fails (e.g. bad AppID, it returns an empty string
+ */
+ CFE_ES_GetAppName(FullName, AppId, sizeof(FullName));
+
+ CFE_EVS_SendEventWithAppID(CFE_SB_PIPE_DELETED_EID, CFE_EVS_EventType_DEBUG, CFE_SB_Global.AppId,
+ "Pipe Deleted:id %d,owner %s", (int)CFE_RESOURCEID_TO_ULONG(PipeId), FullName);
+ }
+ else
+ {
+ /* get TaskId and name of caller for events */
+ CFE_ES_GetTaskID(&TskId);
+ CFE_SB_GetAppTskName(TskId, FullName);
+
+ switch (PendingEventID)
+ {
+ case CFE_SB_DEL_PIPE_ERR1_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_DEL_PIPE_ERR1_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "Pipe Delete Error:Bad Argument,PipedId %ld,Requestor %s",
+ CFE_RESOURCEID_TO_ULONG(PipeId), FullName);
+ break;
+ case CFE_SB_DEL_PIPE_ERR2_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_DEL_PIPE_ERR2_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "Pipe Delete Error:Caller(%s) is not the owner of pipe %ld", FullName,
+ CFE_RESOURCEID_TO_ULONG(PipeId));
+ break;
+ }
+ }
+
+ return Status;
+
+} /* end CFE_SB_DeletePipeFull */
+
+/*
+ * Function: CFE_SB_SetPipeOpts - See API and header file for details
+ */
+int32 CFE_SB_SetPipeOpts(CFE_SB_PipeId_t PipeId, uint8 Opts)
+{
+ CFE_SB_PipeD_t *PipeDscPtr;
+ CFE_ES_AppId_t AppID;
+ CFE_ES_TaskId_t TskId;
+ uint16 PendingEventID;
+ int32 Status;
+ char FullName[(OS_MAX_API_NAME * 2)];
+
+ PendingEventID = 0;
+
+ Status = CFE_ES_GetAppID(&AppID);
+ if (Status != CFE_SUCCESS)
+ {
+ /* shouldn't happen... */
+ return Status;
+ }
+
+ /* take semaphore to prevent a task switch during this call */
+ CFE_SB_LockSharedData(__func__, __LINE__);
+
+ /* check input parameter */
+ PipeDscPtr = CFE_SB_LocatePipeDescByID(PipeId);
+ if (!CFE_SB_PipeDescIsMatch(PipeDscPtr, PipeId))
+ {
+ PendingEventID = CFE_SB_SETPIPEOPTS_ID_ERR_EID;
+ Status = CFE_SB_BAD_ARGUMENT;
+ }
+ /* check that the caller AppId is the owner of the pipe */
+ else if (!CFE_RESOURCEID_TEST_EQUAL(AppID, PipeDscPtr->AppId))
+ {
+ PendingEventID = CFE_SB_SETPIPEOPTS_OWNER_ERR_EID;
+ Status = CFE_SB_BAD_ARGUMENT;
+ }
+ else
+ {
+ PipeDscPtr->Opts = Opts;
+ }
+
+ /* If anything went wrong, increment the error counter before unlock */
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_SB_Global.HKTlmMsg.Payload.PipeOptsErrorCounter++;
+ }
+
+ CFE_SB_UnlockSharedData(__func__, __LINE__);
+
+ /* Send events after unlocking SB */
+ if (Status == CFE_SUCCESS)
+ {
+ /* get AppID of caller for events */
+ CFE_ES_GetAppName(FullName, AppID, sizeof(FullName));
+
+ CFE_EVS_SendEventWithAppID(CFE_SB_SETPIPEOPTS_EID, CFE_EVS_EventType_DEBUG, CFE_SB_Global.AppId,
+ "Pipe opts set:id %lu,owner %s, opts=0x%02x", CFE_RESOURCEID_TO_ULONG(PipeId),
+ FullName, (unsigned int)Opts);
+ }
+ else
+ {
+ /* get TaskId of caller for events */
+ CFE_ES_GetTaskID(&TskId);
+
+ switch (PendingEventID)
+ {
+ case CFE_SB_SETPIPEOPTS_ID_ERR_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_SETPIPEOPTS_ID_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "Pipe Opts Error:Bad Argument,PipedId %lu,Requestor %s",
+ CFE_RESOURCEID_TO_ULONG(PipeId), CFE_SB_GetAppTskName(TskId, FullName));
+ break;
+ case CFE_SB_SETPIPEOPTS_OWNER_ERR_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_SETPIPEOPTS_OWNER_ERR_EID, CFE_EVS_EventType_ERROR,
+ CFE_SB_Global.AppId,
+ "Pipe Opts Set Error: Caller(%s) is not the owner of pipe %lu",
+ CFE_SB_GetAppTskName(TskId, FullName), CFE_RESOURCEID_TO_ULONG(PipeId));
+ break;
+ }
+ }
+
+ return Status;
+} /* end CFE_SB_SetPipeOpts */
+
+/*
+ * Function: CFE_SB_GetPipeOpts - See API and header file for details
+ */
+int32 CFE_SB_GetPipeOpts(CFE_SB_PipeId_t PipeId, uint8 *OptsPtr)
+{
+ int32 Status;
+ CFE_ES_TaskId_t TskId;
+ char FullName[(OS_MAX_API_NAME * 2)];
+ uint16 PendingEventID;
+ CFE_SB_PipeD_t *PipeDscPtr;
+
+ PendingEventID = 0;
+ Status = CFE_SUCCESS;
+
+ /* take semaphore to prevent a task switch during this call */
+ CFE_SB_LockSharedData(__func__, __LINE__);
+
+ /* check input parameter */
+ PipeDscPtr = CFE_SB_LocatePipeDescByID(PipeId);
+ if (!CFE_SB_PipeDescIsMatch(PipeDscPtr, PipeId))
+ {
+ PendingEventID = CFE_SB_GETPIPEOPTS_ID_ERR_EID;
+ Status = CFE_SB_BAD_ARGUMENT;
+ }
+ else if (OptsPtr == NULL)
+ {
+ PendingEventID = CFE_SB_GETPIPEOPTS_PTR_ERR_EID;
+ Status = CFE_SB_BAD_ARGUMENT;
+ }
+ else
+ {
+ *OptsPtr = PipeDscPtr->Opts;
+ }
+
+ /* If anything went wrong, increment the error counter before unlock */
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_SB_Global.HKTlmMsg.Payload.PipeOptsErrorCounter++;
+ }
+
+ CFE_SB_UnlockSharedData(__func__, __LINE__);
+
+ /* Send events after unlocking SB */
+ if (Status == CFE_SUCCESS)
+ {
+ CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPEOPTS_EID, CFE_EVS_EventType_DEBUG, CFE_SB_Global.AppId,
+ "Pipe opts get:id %lu, opts=0x%02x", CFE_RESOURCEID_TO_ULONG(PipeId),
+ (unsigned int)*OptsPtr);
+ }
+ else
+ {
+ /* get TaskId of caller for events */
+ CFE_ES_GetTaskID(&TskId);
+
+ switch (PendingEventID)
+ {
+ case CFE_SB_GETPIPEOPTS_PTR_ERR_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPEOPTS_PTR_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "Pipe Opts Error:Bad Argument,Requestor %s",
+ CFE_SB_GetAppTskName(TskId, FullName));
+ break;
+ case CFE_SB_GETPIPEOPTS_ID_ERR_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPEOPTS_ID_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "Pipe Opts Error:Bad Argument,PipedId %lu,Requestor %s",
+ CFE_RESOURCEID_TO_ULONG(PipeId), CFE_SB_GetAppTskName(TskId, FullName));
+ break;
+ }
+ }
+
+ return Status;
+} /* end CFE_SB_GetPipeOpts */
+
+/*
+ * Function: CFE_SB_GetPipeName - See API and header file for details
+ */
+int32 CFE_SB_GetPipeName(char *PipeNameBuf, size_t PipeNameSize, CFE_SB_PipeId_t PipeId)
+{
+ int32 Status;
+ CFE_ES_TaskId_t TskId;
+ char FullName[(OS_MAX_API_NAME * 2)];
+ uint16 PendingEventID;
+ CFE_SB_PipeD_t *PipeDscPtr;
+ osal_id_t SysQueueId;
+
+ PendingEventID = 0;
+ Status = CFE_SUCCESS;
+ SysQueueId = OS_OBJECT_ID_UNDEFINED;
+
+ /* take semaphore to prevent a task switch during this call */
+ CFE_SB_LockSharedData(__func__, __LINE__);
+
+ /* check input parameter */
+ PipeDscPtr = CFE_SB_LocatePipeDescByID(PipeId);
+ if (!CFE_SB_PipeDescIsMatch(PipeDscPtr, PipeId))
+ {
+ PendingEventID = CFE_SB_GETPIPENAME_ID_ERR_EID;
+ Status = CFE_SB_BAD_ARGUMENT;
+ }
+ else
+ {
+ SysQueueId = PipeDscPtr->SysQueueId;
+ }
+
+ CFE_SB_UnlockSharedData(__func__, __LINE__);
+
+ if (Status == CFE_SUCCESS)
+ {
+ if (PipeNameBuf == NULL || PipeNameSize == 0)
+ {
+ PendingEventID = CFE_SB_GETPIPENAME_NULL_PTR_EID;
+ Status = CFE_SB_BAD_ARGUMENT;
+ }
+ else
+ {
+ Status = OS_GetResourceName(SysQueueId, PipeNameBuf, PipeNameSize);
+
+ if (Status == OS_SUCCESS)
+ {
+ Status = CFE_SUCCESS;
+ }
+ else
+ {
+ PendingEventID = CFE_SB_GETPIPENAME_ID_ERR_EID;
+ Status = CFE_SB_BAD_ARGUMENT;
+ }
+ }
+ }
+
+ /* Send Events */
+ if (Status == CFE_SUCCESS)
+ {
+ CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPENAME_EID, CFE_EVS_EventType_DEBUG, CFE_SB_Global.AppId,
+ "GetPipeName name=%s id=%lu", PipeNameBuf, CFE_RESOURCEID_TO_ULONG(PipeId));
+ }
+ else
+ {
+ CFE_ES_GetTaskID(&TskId);
+
+ switch (PendingEventID)
+ {
+ case CFE_SB_GETPIPENAME_NULL_PTR_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPENAME_NULL_PTR_EID, CFE_EVS_EventType_ERROR,
+ CFE_SB_Global.AppId, "Pipe Name Error:NullPtr,Requestor %s",
+ CFE_SB_GetAppTskName(TskId, FullName));
+ break;
+ case CFE_SB_GETPIPENAME_ID_ERR_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPENAME_ID_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "Pipe Id Error:Bad Argument,Id=%lu,Requestor %s",
+ CFE_RESOURCEID_TO_ULONG(PipeId), CFE_SB_GetAppTskName(TskId, FullName));
+ break;
+ }
+
+ if (PipeNameBuf != NULL && PipeNameSize > 0)
+ {
+ memset(PipeNameBuf, 0, PipeNameSize);
+ }
+ }
+
+ return Status;
+
+} /* end CFE_SB_GetPipeName */
+
+/*
+ * Function: CFE_SB_GetPipeIdByName - See API and header file for details
+ */
+int32 CFE_SB_GetPipeIdByName(CFE_SB_PipeId_t *PipeIdPtr, const char *PipeName)
+{
+ int32 Status;
+ CFE_ES_TaskId_t TskId;
+ uint32 Idx;
+ char FullName[(OS_MAX_API_NAME * 2)];
+ uint16 PendingEventID;
+ CFE_SB_PipeD_t *PipeDscPtr;
+ osal_id_t SysQueueId;
+
+ PendingEventID = 0;
+ SysQueueId = OS_OBJECT_ID_UNDEFINED;
+
+ if (PipeName == NULL || PipeIdPtr == NULL)
+ {
+ PendingEventID = CFE_SB_GETPIPEIDBYNAME_NULL_ERR_EID;
+ Status = CFE_SB_BAD_ARGUMENT;
+ }
+ else
+ {
+ /* Get QueueID from OSAL */
+ Status = OS_QueueGetIdByName(&SysQueueId, PipeName);
+ if (Status == OS_SUCCESS)
+ {
+ Status = CFE_SUCCESS;
+ }
+ else
+ {
+ PendingEventID = CFE_SB_GETPIPEIDBYNAME_NAME_ERR_EID;
+ Status = CFE_SB_BAD_ARGUMENT;
+ }
+ }
+
+ CFE_SB_LockSharedData(__func__, __LINE__);
+
+ if (Status == CFE_SUCCESS)
+ {
+ Idx = CFE_PLATFORM_SB_MAX_PIPES;
+ PipeDscPtr = CFE_SB_Global.PipeTbl;
+ while (true)
+ {
+ if (Idx == 0)
+ {
+ PendingEventID = CFE_SB_GETPIPEIDBYNAME_NAME_ERR_EID;
+ Status = CFE_SB_BAD_ARGUMENT;
+ break;
+ }
+
+ if (OS_ObjectIdEqual(PipeDscPtr->SysQueueId, SysQueueId))
+ {
+ /* grab the ID before we release the lock */
+ *PipeIdPtr = CFE_SB_PipeDescGetID(PipeDscPtr);
+ break;
+ } /* end if */
+
+ --Idx;
+ ++PipeDscPtr;
+ }
+ }
+
+ if (Status != CFE_SUCCESS)
+ {
+ ++CFE_SB_Global.HKTlmMsg.Payload.GetPipeIdByNameErrorCounter;
+ }
+
+ CFE_SB_UnlockSharedData(__func__, __LINE__);
+
+ /* Send Events */
+ if (Status == CFE_SUCCESS)
+ {
+ CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPEIDBYNAME_EID, CFE_EVS_EventType_DEBUG, CFE_SB_Global.AppId,
+ "PipeIdByName name=%s id=%lu", PipeName, CFE_RESOURCEID_TO_ULONG(*PipeIdPtr));
+ }
+ else
+ {
+ /* get TaskId of caller for events */
+ CFE_ES_GetTaskID(&TskId);
+
+ switch (PendingEventID)
+ {
+ case CFE_SB_GETPIPEIDBYNAME_NULL_ERR_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPEIDBYNAME_NULL_ERR_EID, CFE_EVS_EventType_ERROR,
+ CFE_SB_Global.AppId, "Pipe ID By Name Error:Bad Argument,Requestor %s",
+ CFE_SB_GetAppTskName(TskId, FullName));
+ break;
+
+ case CFE_SB_GETPIPEIDBYNAME_NAME_ERR_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_GETPIPEIDBYNAME_NAME_ERR_EID, CFE_EVS_EventType_ERROR,
+ CFE_SB_Global.AppId, "Pipe ID By Name Error:Bad Argument,Requestor %s",
+ CFE_SB_GetAppTskName(TskId, FullName));
+ break;
+ }
+ }
+
+ return Status;
+
+} /* end CFE_SB_GetPipeIdByName */
+
+/*
+ * Function: CFE_SB_SubscribeEx - See API and header file for details
+ */
+int32 CFE_SB_SubscribeEx(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId, CFE_SB_Qos_t Quality, uint16 MsgLim)
+{
+ return CFE_SB_SubscribeFull(MsgId, PipeId, Quality, MsgLim, (uint8)CFE_SB_MSG_GLOBAL);
+
+} /* end CFE_SB_SubscribeEx */
+
+/*
+ * Function: CFE_SB_SubscribeLocal - See API and header file for details
+ */
+int32 CFE_SB_SubscribeLocal(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId, uint16 MsgLim)
+{
+ return CFE_SB_SubscribeFull(MsgId, PipeId, CFE_SB_DEFAULT_QOS, MsgLim, (uint8)CFE_SB_MSG_LOCAL);
+
+} /* end CFE_SB_SubscribeLocal */
+
+/*
+ * Function: CFE_SB_Subscribe - See API and header file for details
+ */
+int32 CFE_SB_Subscribe(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId)
+{
+ return CFE_SB_SubscribeFull(MsgId, PipeId, CFE_SB_DEFAULT_QOS, (uint16)CFE_PLATFORM_SB_DEFAULT_MSG_LIMIT,
+ (uint8)CFE_SB_MSG_GLOBAL);
+
+} /* end CFE_SB_Subscribe */
+
+/******************************************************************************
+** Name: CFE_SB_SubscribeFull
+**
+** Purpose: CFE Internal API used to subscribe to a message. Contains an input
+** parameter for all possible subscription choices. This function is
+** called by CFE_SB_SubscribeEx, CFE_SB_Subscribe and
+** CFE_SB_SubscribeLocal.
+**
+** Assumptions, External Events, and Notes:
+** Has the same typedef as the message Id
+**
+** Date Written:
+** 04/25/2005
+**
+** Input Arguments:
+** MsgId - Mission unique identifier for the message being requested
+** PipeId - The Pipe ID to send the message to
+** Quality - Quality of Service (Qos) - priority and reliability
+** MsgLim - Max number of messages, with this MsgId, allowed on the
+** pipe at any time.
+** Scope - Local subscription or broadcasted to peers
+**
+** Output Arguments:
+** None
+**
+** Return Values:
+** Status
+**
+******************************************************************************/
+int32 CFE_SB_SubscribeFull(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId, CFE_SB_Qos_t Quality, uint16 MsgLim,
+ uint8 Scope)
+{
+ CFE_SBR_RouteId_t RouteId;
+ CFE_SB_PipeD_t * PipeDscPtr;
+ int32 Status;
+ CFE_ES_TaskId_t TskId;
+ CFE_ES_AppId_t AppId;
+ CFE_SB_DestinationD_t *DestPtr;
+ uint32 DestCount;
+ char FullName[(OS_MAX_API_NAME * 2)];
+ char PipeName[OS_MAX_API_NAME];
+ uint32 Collisions;
+ uint16 PendingEventID;
+
+ PendingEventID = 0;
+ Status = CFE_SUCCESS;
+ DestPtr = NULL;
+ Collisions = 0;
+
+ /* get the callers Application Id */
+ CFE_ES_GetAppID(&AppId);
+
+ /* get TaskId of caller for events */
+ CFE_ES_GetTaskID(&TskId);
+
+ /* take semaphore to prevent a task switch during this call */
+ CFE_SB_LockSharedData(__func__, __LINE__);
+
+ /* check that the pipe has been created */
+ PipeDscPtr = CFE_SB_LocatePipeDescByID(PipeId);
+ if (!CFE_SB_PipeDescIsMatch(PipeDscPtr, PipeId))
+ {
+ PendingEventID = CFE_SB_SUB_INV_PIPE_EID;
+ Status = CFE_SB_BAD_ARGUMENT;
+ }
+ else if (!CFE_RESOURCEID_TEST_EQUAL(PipeDscPtr->AppId, AppId))
+ {
+ PendingEventID = CFE_SB_SUB_INV_CALLER_EID;
+ Status = CFE_SB_BAD_ARGUMENT;
+ }
+ /* check message id key and scope */
+ else if (!CFE_SB_IsValidMsgId(MsgId) || (Scope > 1))
+ {
+ PendingEventID = CFE_SB_SUB_ARG_ERR_EID;
+ Status = CFE_SB_BAD_ARGUMENT;
+ }
+ else
+ {
+ /* Get the route, adding one if it does not exist already */
+ RouteId = CFE_SBR_GetRouteId(MsgId);
+
+ if (!CFE_SBR_IsValidRouteId(RouteId))
+ {
+ /* Add the route */
+ RouteId = CFE_SBR_AddRoute(MsgId, &Collisions);
+
+ /* if all routing table elements are used, send event */
+ if (!CFE_SBR_IsValidRouteId(RouteId))
+ {
+ PendingEventID = CFE_SB_MAX_MSGS_MET_EID;
+ Status = CFE_SB_MAX_MSGS_MET;
+ }
+ else
+ {
+ /* Increment the MsgIds in use ctr and if it's > the high water mark,*/
+ /* adjust the high water mark */
+ CFE_SB_Global.StatTlmMsg.Payload.MsgIdsInUse++;
+ if (CFE_SB_Global.StatTlmMsg.Payload.MsgIdsInUse > CFE_SB_Global.StatTlmMsg.Payload.PeakMsgIdsInUse)
+ {
+ CFE_SB_Global.StatTlmMsg.Payload.PeakMsgIdsInUse = CFE_SB_Global.StatTlmMsg.Payload.MsgIdsInUse;
+ } /* end if */
+ }
+ }
+ }
+
+ /* If successful up to this point, check if new dest should be added to this route */
+ if (Status == CFE_SUCCESS)
+ {
+ DestCount = 0;
+ for (DestPtr = CFE_SBR_GetDestListHeadPtr(RouteId); DestPtr != NULL; DestPtr = DestPtr->Next)
+ {
+ ++DestCount;
+
+ /* Check if duplicate (status stays as CFE_SUCCESS) */
+ if (CFE_RESOURCEID_TEST_EQUAL(DestPtr->PipeId, PipeId))
+ {
+ PendingEventID = CFE_SB_DUP_SUBSCRIP_EID;
+ break;
+ }
+
+ /* Check if limit reached */
+ if (DestCount >= CFE_PLATFORM_SB_MAX_DEST_PER_PKT)
+ {
+ PendingEventID = CFE_SB_MAX_DESTS_MET_EID;
+ Status = CFE_SB_MAX_DESTS_MET;
+ break;
+ }
+ }
+
+ /* If no existing dest found, add one now */
+ if (DestPtr == NULL)
+ {
+ DestPtr = CFE_SB_GetDestinationBlk();
+ if (DestPtr == NULL)
+ {
+ PendingEventID = CFE_SB_DEST_BLK_ERR_EID;
+ Status = CFE_SB_BUF_ALOC_ERR;
+ }
+ else
+ {
+ /* initialize destination block */
+ DestPtr->PipeId = PipeId;
+ DestPtr->MsgId2PipeLim = 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_Global.StatTlmMsg.Payload.SubscriptionsInUse++;
+ if (CFE_SB_Global.StatTlmMsg.Payload.SubscriptionsInUse >
+ CFE_SB_Global.StatTlmMsg.Payload.PeakSubscriptionsInUse)
+ {
+ CFE_SB_Global.StatTlmMsg.Payload.PeakSubscriptionsInUse =
+ CFE_SB_Global.StatTlmMsg.Payload.SubscriptionsInUse;
+ }
+ }
+ }
+ }
+
+ /* Increment counter before unlock */
+ switch (PendingEventID)
+ {
+ case CFE_SB_SUB_INV_PIPE_EID:
+ case CFE_SB_SUB_INV_CALLER_EID:
+ case CFE_SB_SUB_ARG_ERR_EID:
+ case CFE_SB_MAX_MSGS_MET_EID:
+ case CFE_SB_DEST_BLK_ERR_EID:
+ case CFE_SB_MAX_DESTS_MET_EID:
+ CFE_SB_Global.HKTlmMsg.Payload.SubscribeErrorCounter++;
+ break;
+ case CFE_SB_DUP_SUBSCRIP_EID:
+ CFE_SB_Global.HKTlmMsg.Payload.DuplicateSubscriptionsCounter++;
+ break;
+ }
+
+ CFE_SB_UnlockSharedData(__func__, __LINE__);
+
+ /* Send events now */
+ if (PendingEventID != 0)
+ {
+ CFE_SB_GetPipeName(PipeName, sizeof(PipeName), PipeId);
+
+ switch (PendingEventID)
+ {
+ case CFE_SB_DUP_SUBSCRIP_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_DUP_SUBSCRIP_EID, CFE_EVS_EventType_INFORMATION, CFE_SB_Global.AppId,
+ "Duplicate Subscription,MsgId 0x%x on %s pipe,app %s",
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId), PipeName,
+ CFE_SB_GetAppTskName(TskId, FullName));
+ break;
+
+ case CFE_SB_SUB_INV_CALLER_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_SUB_INV_CALLER_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "Subscribe Err:Caller(%s) is not the owner of pipe %lu,Msg=0x%x",
+ CFE_SB_GetAppTskName(TskId, FullName), CFE_RESOURCEID_TO_ULONG(PipeId),
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId));
+ break;
+
+ case CFE_SB_SUB_INV_PIPE_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_SUB_INV_PIPE_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "Subscribe Err:Invalid Pipe Id,Msg=0x%x,PipeId=%lu,App %s",
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId), CFE_RESOURCEID_TO_ULONG(PipeId),
+ CFE_SB_GetAppTskName(TskId, FullName));
+ break;
+
+ case CFE_SB_DEST_BLK_ERR_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_DEST_BLK_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "Subscribe Err:Request for Destination Blk failed for Msg 0x%x",
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId));
+ break;
+
+ case CFE_SB_MAX_DESTS_MET_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_MAX_DESTS_MET_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "Subscribe Err:Max Dests(%d)In Use For Msg 0x%x,pipe %s,app %s",
+ CFE_PLATFORM_SB_MAX_DEST_PER_PKT, (unsigned int)CFE_SB_MsgIdToValue(MsgId),
+ PipeName, CFE_SB_GetAppTskName(TskId, FullName));
+ break;
+
+ case CFE_SB_MAX_MSGS_MET_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_MAX_MSGS_MET_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "Subscribe Err:Max Msgs(%d)In Use,MsgId 0x%x,pipe %s,app %s",
+ CFE_PLATFORM_SB_MAX_MSG_IDS, (unsigned int)CFE_SB_MsgIdToValue(MsgId),
+ PipeName, CFE_SB_GetAppTskName(TskId, FullName));
+ break;
+
+ case CFE_SB_SUB_ARG_ERR_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_SUB_ARG_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "Subscribe Err:Bad Arg,MsgId 0x%x,PipeId %lu,app %s,scope %d",
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId), CFE_RESOURCEID_TO_ULONG(PipeId),
+ CFE_SB_GetAppTskName(TskId, FullName), Scope);
+ break;
+ }
+ }
+ else if (Status == CFE_SUCCESS)
+ {
+ /* If no other event pending, send a debug event indicating success */
+ CFE_EVS_SendEventWithAppID(CFE_SB_SUBSCRIPTION_RCVD_EID, CFE_EVS_EventType_DEBUG, CFE_SB_Global.AppId,
+ "Subscription Rcvd:MsgId 0x%x on PipeId %lu,app %s",
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId), CFE_RESOURCEID_TO_ULONG(PipeId),
+ CFE_SB_GetAppTskName(TskId, FullName));
+ }
+
+ if (Status == CFE_SUCCESS && Scope == CFE_SB_MSG_GLOBAL)
+ {
+ CFE_SB_SendSubscriptionReport(MsgId, PipeId, Quality);
+ }
+
+ if (Collisions != 0)
+ {
+ CFE_EVS_SendEventWithAppID(CFE_SB_HASHCOLLISION_EID, CFE_EVS_EventType_DEBUG, CFE_SB_Global.AppId,
+ "Msg hash collision: MsgId = 0x%x, collisions = %u",
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId), (unsigned int)Collisions);
+ }
+
+ return Status;
+
+} /* end CFE_SB_SubscribeFull */
+
+/*
+ * Function: CFE_SB_Unsubscribe - See API and header file for details
+ */
+int32 CFE_SB_Unsubscribe(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId)
+{
+ CFE_ES_AppId_t CallerId;
+ int32 Status = 0;
+
+ /* get the callers Application Id */
+ CFE_ES_GetAppID(&CallerId);
+
+ Status = CFE_SB_UnsubscribeFull(MsgId, PipeId, (uint8)CFE_SB_MSG_GLOBAL, CallerId);
+
+ return Status;
+
+} /* end CFE_SB_Unsubscribe */
+
+/*
+ * Function: CFE_SB_UnsubscribeLocal - See API and header file for details
+ */
+int32 CFE_SB_UnsubscribeLocal(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId)
+{
+ CFE_ES_AppId_t CallerId;
+ int32 Status = 0;
+
+ /* get the callers Application Id */
+ CFE_ES_GetAppID(&CallerId);
+
+ Status = CFE_SB_UnsubscribeFull(MsgId, PipeId, (uint8)CFE_SB_MSG_LOCAL, CallerId);
+
+ return Status;
+
+} /* end CFE_SB_UnsubscribeLocal */
+
+/******************************************************************************
+** Name: CFE_SB_UnsubscribeAppId
+**
+** Purpose: CFE Internal API intented to be called by CFE_ES when an applications
+** SB resources need to be freed. The regular unsibscribe api won't work
+** because it does a check to ensure the caller is the owner of the pipe.
+**
+** Date Written:
+** 03/15/2007
+**
+** Input Arguments:
+** MsgId
+** PipeId
+** AppId
+**
+** Output Arguments:
+** None
+**
+** Return Values:
+** Status
+**
+******************************************************************************/
+int32 CFE_SB_UnsubscribeWithAppId(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId, CFE_ES_AppId_t AppId)
+{
+ int32 Status = 0;
+
+ Status = CFE_SB_UnsubscribeFull(MsgId, PipeId, (uint8)CFE_SB_MSG_LOCAL, AppId);
+
+ return Status;
+
+} /* end CFE_SB_UnsubscribeWithAppId */
+
+/******************************************************************************
+** Name: CFE_SB_UnsubscribeFull
+**
+** Purpose: CFE Internal API used to unsubscribe to a message.
+**
+** Assumptions, External Events, and Notes:
+**
+**
+** Notes:This function cannot be called directly,it would not be semaphore protected.
+** Also,if more than one subscription is found, this function will remove all
+** entries that match.
+**
+** Date Written:
+** 04/25/2005
+**
+** Input Arguments:
+** MsgId
+** PipeId
+** Scope
+** AppId
+**
+** Output Arguments:
+** None
+**
+** Return Values:
+** Status
+**
+******************************************************************************/
+int32 CFE_SB_UnsubscribeFull(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId, uint8 Scope, CFE_ES_AppId_t AppId)
+{
+ int32 Status;
+ CFE_SBR_RouteId_t RouteId;
+ CFE_ES_TaskId_t TskId;
+ CFE_SB_DestinationD_t *DestPtr;
+ char FullName[(OS_MAX_API_NAME * 2)];
+ char PipeName[OS_MAX_API_NAME];
+ CFE_SB_PipeD_t * PipeDscPtr;
+ uint16 PendingEventID;
+
+ PendingEventID = 0;
+ Status = CFE_SUCCESS;
+ DestPtr = NULL;
+
+ /* get TaskId of caller for events */
+ CFE_ES_GetTaskID(&TskId);
+
+ /* take semaphore to prevent a task switch during this call */
+ CFE_SB_LockSharedData(__func__, __LINE__);
+
+ /* check that the pipe has been created */
+ PipeDscPtr = CFE_SB_LocatePipeDescByID(PipeId);
+ if (!CFE_SB_PipeDescIsMatch(PipeDscPtr, PipeId))
+ {
+ PendingEventID = CFE_SB_UNSUB_INV_PIPE_EID;
+ Status = CFE_SB_BAD_ARGUMENT;
+ }
+ /* if given 'AppId' is not the owner of the pipe, send error event and return */
+ else if (!CFE_RESOURCEID_TEST_EQUAL(PipeDscPtr->AppId, AppId))
+ {
+ PendingEventID = CFE_SB_UNSUB_INV_CALLER_EID;
+ Status = CFE_SB_BAD_ARGUMENT;
+ }
+ /* check input parameters */
+ else if (!CFE_SB_IsValidMsgId(MsgId) || (Scope > 1))
+ {
+ PendingEventID = CFE_SB_UNSUB_ARG_ERR_EID;
+ Status = CFE_SB_BAD_ARGUMENT;
+ }
+ else
+ {
+ /* get routing id */
+ RouteId = CFE_SBR_GetRouteId(MsgId);
+
+ /* if there have never been subscriptions for this message id... */
+ if (!CFE_SBR_IsValidRouteId(RouteId))
+ {
+ PendingEventID = CFE_SB_UNSUB_NO_SUBS_EID;
+ /* Status stays CFE_SUCCESS here */
+ }
+ else
+ {
+ /* Get the destination pointer */
+ DestPtr = CFE_SB_GetDestPtr(RouteId, PipeId);
+
+ if (DestPtr != NULL)
+ {
+ /* match found, remove destination */
+ CFE_SB_RemoveDest(RouteId, DestPtr);
+ }
+ else
+ {
+ PendingEventID = CFE_SB_UNSUB_NO_SUBS_EID;
+ }
+ }
+ } /* end if */
+
+ CFE_SB_UnlockSharedData(__func__, __LINE__);
+
+ if (PendingEventID != 0)
+ {
+ switch (PendingEventID)
+ {
+ case CFE_SB_UNSUB_NO_SUBS_EID:
+ CFE_SB_GetPipeName(PipeName, sizeof(PipeName), PipeId);
+ CFE_EVS_SendEventWithAppID(CFE_SB_UNSUB_NO_SUBS_EID, CFE_EVS_EventType_INFORMATION, CFE_SB_Global.AppId,
+ "Unsubscribe Err:No subs for Msg 0x%x on %s,app %s",
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId), PipeName,
+ CFE_SB_GetAppTskName(TskId, FullName));
+ break;
+
+ case CFE_SB_UNSUB_INV_PIPE_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_UNSUB_INV_PIPE_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "Unsubscribe Err:Invalid Pipe Id Msg=0x%x,Pipe=%lu,app=%s",
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId), CFE_RESOURCEID_TO_ULONG(PipeId),
+ CFE_SB_GetAppTskName(TskId, FullName));
+ break;
+
+ case CFE_SB_UNSUB_INV_CALLER_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_UNSUB_INV_CALLER_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "Unsubscribe Err:Caller(%s) is not the owner of pipe %lu,Msg=0x%x",
+ CFE_SB_GetAppTskName(TskId, FullName), CFE_RESOURCEID_TO_ULONG(PipeId),
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId));
+ break;
+
+ case CFE_SB_UNSUB_ARG_ERR_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_UNSUB_ARG_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "UnSubscribe Err:Bad Arg,MsgId 0x%x,PipeId %lu,app %s,scope %d",
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId), CFE_RESOURCEID_TO_ULONG(PipeId),
+ CFE_SB_GetAppTskName(TskId, FullName), (int)Scope);
+ break;
+ }
+ }
+ else if (Status == CFE_SUCCESS)
+ {
+ /* if no other event pending, send a debug event for successful unsubscribe */
+ CFE_EVS_SendEventWithAppID(CFE_SB_SUBSCRIPTION_REMOVED_EID, CFE_EVS_EventType_DEBUG, CFE_SB_Global.AppId,
+ "Subscription Removed:Msg 0x%x on pipe %lu,app %s",
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId), CFE_RESOURCEID_TO_ULONG(PipeId),
+ CFE_SB_GetAppTskName(TskId, FullName));
+ }
+
+ return Status;
+} /* end CFE_SB_UnsubscribeFull */
+
+/*
+ * Function CFE_SB_TransmitMsg - See API and header file for details
+ */
+int32 CFE_SB_TransmitMsg(CFE_MSG_Message_t *MsgPtr, bool IncrementSequenceCount)
+{
+ int32 Status;
+ CFE_MSG_Size_t Size = 0;
+ CFE_SB_MsgId_t MsgId = CFE_SB_INVALID_MSG_ID;
+ CFE_ES_TaskId_t TskId;
+ char FullName[(OS_MAX_API_NAME * 2)];
+ CFE_SB_BufferD_t *BufDscPtr;
+ CFE_SBR_RouteId_t RouteId;
+ uint16 PendingEventID;
+
+ PendingEventID = 0;
+ BufDscPtr = NULL;
+ RouteId = CFE_SBR_INVALID_ROUTE_ID;
+
+ Status = CFE_SB_TransmitMsgValidate(MsgPtr, &MsgId, &Size, &RouteId);
+
+ CFE_SB_LockSharedData(__func__, __LINE__);
+
+ if (Status == CFE_SUCCESS && CFE_SBR_IsValidRouteId(RouteId))
+ {
+ /* Get buffer - note this pre-initializes the returned buffer with
+ * a use count of 1, which refers to this task as it fills the buffer. */
+ BufDscPtr = CFE_SB_GetBufferFromPool(Size);
+ if (BufDscPtr == NULL)
+ {
+ PendingEventID = CFE_SB_GET_BUF_ERR_EID;
+ Status = CFE_SB_BUF_ALOC_ERR;
+ }
+ }
+
+ /*
+ * Increment the MsgSendErrorCounter only if there was a real error,
+ * such as a validation issue or failure to allocate a buffer.
+ *
+ * (This should NOT be done if simply no route)
+ */
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_SB_Global.HKTlmMsg.Payload.MsgSendErrorCounter++;
+ }
+
+ CFE_SB_UnlockSharedData(__func__, __LINE__);
+
+ /*
+ * If a buffer was obtained above, then copy the content into it
+ * and broadcast it to all subscribers in the route.
+ *
+ * Note - if there is no route / no subscribers, the "Status" will
+ * be CFE_SUCCESS because CFE_SB_TransmitMsgValidate() succeeded,
+ * but there will be no buffer because CFE_SBR_IsValidRouteId() returned
+ * false.
+ *
+ * But if the desciptor is non-null it means the message is valid and
+ * there is a route to send it to.
+ */
+ if (BufDscPtr != NULL)
+ {
+ /* Copy actual message content into buffer and set its metadata */
+ memcpy(&BufDscPtr->Content, MsgPtr, Size);
+ BufDscPtr->MsgId = MsgId;
+ BufDscPtr->ContentSize = Size;
+ BufDscPtr->AutoSequence = IncrementSequenceCount;
+ CFE_MSG_GetType(MsgPtr, &BufDscPtr->ContentType);
+
+ /*
+ * This routine will use best-effort to send to all subscribers,
+ * increment the buffer use count for every successful delivery,
+ * and send an event/increment counter for any unsucessful delivery.
+ */
+ CFE_SB_BroadcastBufferToRoute(BufDscPtr, RouteId);
+
+ /*
+ * The broadcast function consumes the buffer, so it should not be
+ * accessed in this function anymore
+ */
+ BufDscPtr = NULL;
+ }
+
+ if (PendingEventID == CFE_SB_GET_BUF_ERR_EID)
+ {
+ /* Get task id for events and Sender Info*/
+ CFE_ES_GetTaskID(&TskId);
+
+ if (CFE_SB_RequestToSendEvent(TskId, CFE_SB_GET_BUF_ERR_EID_BIT) == CFE_SB_GRANTED)
+ {
+ CFE_EVS_SendEventWithAppID(CFE_SB_GET_BUF_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "Send Err:Request for Buffer Failed. MsgId 0x%x,app %s,size %d",
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId), CFE_SB_GetAppTskName(TskId, FullName),
+ (int)Size);
+
+ /* clear the bit so the task may send this event again */
+ CFE_SB_FinishSendEvent(TskId, CFE_SB_GET_BUF_ERR_EID_BIT);
+ }
+ }
+
+ return Status;
+}
+
+/*****************************************************************************/
+/**
+ * \brief Internal routine to validate a transmit message before sending
+ *
+ * \param[in] MsgPtr Pointer to the message to validate
+ * \param[out] MsgIdPtr Message Id of message
+ * \param[out] SizePtr Size of message
+ * \param[out] RouteIdPtr Route ID of the message (invalid if none)
+ */
+int32 CFE_SB_TransmitMsgValidate(CFE_MSG_Message_t *MsgPtr, CFE_SB_MsgId_t *MsgIdPtr, CFE_MSG_Size_t *SizePtr,
+ CFE_SBR_RouteId_t *RouteIdPtr)
+{
+ CFE_ES_TaskId_t TskId;
+ char FullName[(OS_MAX_API_NAME * 2)];
+ uint16 PendingEventID;
+ int32 Status;
+
+ PendingEventID = 0;
+ Status = CFE_SUCCESS;
+
+ /* check input parameter */
+ if (MsgPtr == NULL)
+ {
+ PendingEventID = CFE_SB_SEND_BAD_ARG_EID;
+ Status = CFE_SB_BAD_ARGUMENT;
+ }
+
+ if (Status == CFE_SUCCESS)
+ {
+ CFE_MSG_GetMsgId(MsgPtr, MsgIdPtr);
+
+ /* validate the msgid in the message */
+ if (!CFE_SB_IsValidMsgId(*MsgIdPtr))
+ {
+ PendingEventID = CFE_SB_SEND_INV_MSGID_EID;
+ Status = CFE_SB_BAD_ARGUMENT;
+ }
+ }
+
+ if (Status == CFE_SUCCESS)
+ {
+ CFE_MSG_GetSize(MsgPtr, SizePtr);
+
+ /* Verify the size of the pkt is < or = the mission defined max */
+ if (*SizePtr > CFE_MISSION_SB_MAX_SB_MSG_SIZE)
+ {
+ PendingEventID = CFE_SB_MSG_TOO_BIG_EID;
+ Status = CFE_SB_MSG_TOO_BIG;
+ } /* end if */
+ }
+
+ if (Status == CFE_SUCCESS)
+ {
+ /* check the route, which should be done while locked */
+ CFE_SB_LockSharedData(__func__, __LINE__);
+
+ /* Get the routing id */
+ *RouteIdPtr = CFE_SBR_GetRouteId(*MsgIdPtr);
+
+ /* if there have been no subscriptions for this pkt, */
+ /* increment the dropped pkt cnt, send event and return success */
+ if (!CFE_SBR_IsValidRouteId(*RouteIdPtr))
+ {
+ CFE_SB_Global.HKTlmMsg.Payload.NoSubscribersCounter++;
+ PendingEventID = CFE_SB_SEND_NO_SUBS_EID;
+ }
+
+ CFE_SB_UnlockSharedData(__func__, __LINE__);
+ }
+
+ if (PendingEventID != 0)
+ {
+ /* get task id for events */
+ CFE_ES_GetTaskID(&TskId);
+
+ switch (PendingEventID)
+ {
+ case CFE_SB_SEND_BAD_ARG_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_SEND_BAD_ARG_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "Send Err:Bad input argument,Arg 0x%lx,App %s", (unsigned long)MsgPtr,
+ CFE_SB_GetAppTskName(TskId, FullName));
+ break;
+
+ case CFE_SB_SEND_INV_MSGID_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_SEND_INV_MSGID_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "Send Err:Invalid MsgId(0x%x)in msg,App %s",
+ (unsigned int)CFE_SB_MsgIdToValue(*MsgIdPtr),
+ CFE_SB_GetAppTskName(TskId, FullName));
+ break;
+
+ case CFE_SB_MSG_TOO_BIG_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_MSG_TOO_BIG_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "Send Err:Msg Too Big MsgId=0x%x,app=%s,size=%d,MaxSz=%d",
+ (unsigned int)CFE_SB_MsgIdToValue(*MsgIdPtr),
+ CFE_SB_GetAppTskName(TskId, FullName), (int)*SizePtr,
+ CFE_MISSION_SB_MAX_SB_MSG_SIZE);
+ break;
+
+ case CFE_SB_SEND_NO_SUBS_EID:
+ /* Determine if event can be sent without causing recursive event problem */
+ if (CFE_SB_RequestToSendEvent(TskId, CFE_SB_SEND_NO_SUBS_EID_BIT) == CFE_SB_GRANTED)
+ {
+ CFE_EVS_SendEventWithAppID(CFE_SB_SEND_NO_SUBS_EID, CFE_EVS_EventType_INFORMATION,
+ CFE_SB_Global.AppId, "No subscribers for MsgId 0x%x,sender %s",
+ (unsigned int)CFE_SB_MsgIdToValue(*MsgIdPtr),
+ CFE_SB_GetAppTskName(TskId, FullName));
+
+ /* clear the bit so the task may send this event again */
+ CFE_SB_FinishSendEvent(TskId, CFE_SB_SEND_NO_SUBS_EID_BIT);
+ } /* end if */
+ break;
+ }
+
+ } /* end if */
+
+ return Status;
+}
+
+/*****************************************************************************/
+/**
+ * \brief Internal routine implements full send logic
+ *
+ * \param[in] BufDscPtr Pointer to the buffer description from the memory pool,
+ * released prior to return
+ * \param[in] RouteId Route to send to
+ */
+void CFE_SB_BroadcastBufferToRoute(CFE_SB_BufferD_t *BufDscPtr, CFE_SBR_RouteId_t RouteId)
+{
+ CFE_ES_AppId_t AppId;
+ CFE_ES_TaskId_t TskId;
+ CFE_SB_DestinationD_t *DestPtr;
+ CFE_SB_PipeD_t * PipeDscPtr;
+ CFE_SB_EventBuf_t SBSndErr;
+ int32 Status;
+ uint32 i;
+ char FullName[(OS_MAX_API_NAME * 2)];
+ char PipeName[OS_MAX_API_NAME];
+
+ SBSndErr.EvtsToSnd = 0;
+
+ /* get app id for loopback testing */
+ CFE_ES_GetAppID(&AppId);
+
+ /* get task id for events and Sender Info*/
+ CFE_ES_GetTaskID(&TskId);
+
+ /* take semaphore to prevent a task switch during processing */
+ CFE_SB_LockSharedData(__func__, __LINE__);
+
+ /* For an invalid route / no subsribers this whole logic can be skipped */
+ if (CFE_SBR_IsValidRouteId(RouteId))
+ {
+ /* Set the seq count if requested (while locked) before actually sending */
+ /* For some reason this is only done for TLM types (historical, TBD) */
+ if (BufDscPtr->AutoSequence && BufDscPtr->ContentType == CFE_MSG_Type_Tlm)
+ {
+ CFE_SBR_IncrementSequenceCounter(RouteId);
+
+ /* Write the sequence into the message header itself (overwrites whatever was there) */
+ CFE_MSG_SetSequenceCount(&BufDscPtr->Content.Msg, CFE_SBR_GetSequenceCounter(RouteId));
+ }
+
+ /* Send the packet to all destinations */
+ for (DestPtr = CFE_SBR_GetDestListHeadPtr(RouteId); DestPtr != NULL; DestPtr = DestPtr->Next)
+ {
+ if (DestPtr->Active == CFE_SB_ACTIVE) /* destination is active */
+ {
+ PipeDscPtr = CFE_SB_LocatePipeDescByID(DestPtr->PipeId);
+ }
+ else
+ {
+ PipeDscPtr = NULL;
+ }
+
+ if (!CFE_SB_PipeDescIsMatch(PipeDscPtr, DestPtr->PipeId))
+ {
+ continue;
+ }
+
+ if ((PipeDscPtr->Opts & CFE_SB_PIPEOPTS_IGNOREMINE) != 0 &&
+ CFE_RESOURCEID_TEST_EQUAL(PipeDscPtr->AppId, AppId))
+ {
+ continue;
+ } /* end if */
+
+ /* if Msg limit exceeded, log event, increment counter */
+ /* and go to next destination */
+ if (DestPtr->BuffCount >= DestPtr->MsgId2PipeLim)
+ {
+ SBSndErr.EvtBuf[SBSndErr.EvtsToSnd].PipeId = DestPtr->PipeId;
+ SBSndErr.EvtBuf[SBSndErr.EvtsToSnd].EventId = CFE_SB_MSGID_LIM_ERR_EID;
+ SBSndErr.EvtsToSnd++;
+ CFE_SB_Global.HKTlmMsg.Payload.MsgLimitErrorCounter++;
+ PipeDscPtr->SendErrors++;
+
+ continue;
+ } /* end if */
+
+ /*
+ ** 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, &BufDscPtr, sizeof(BufDscPtr), 0);
+
+ if (Status == OS_SUCCESS)
+ {
+ /* The queue now holds a ref to the buffer, so increment its ref count. */
+ CFE_SB_IncrBufUseCnt(BufDscPtr);
+
+ DestPtr->BuffCount++; /* used for checking MsgId2PipeLimit */
+ DestPtr->DestCnt++; /* used for statistics */
+ ++PipeDscPtr->CurrentQueueDepth;
+ if (PipeDscPtr->CurrentQueueDepth >= PipeDscPtr->PeakQueueDepth)
+ {
+ PipeDscPtr->PeakQueueDepth = PipeDscPtr->CurrentQueueDepth;
+ }
+ }
+ else 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_Global.HKTlmMsg.Payload.PipeOverflowErrorCounter++;
+ PipeDscPtr->SendErrors++;
+ }
+ 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_Global.HKTlmMsg.Payload.InternalErrorCounter++;
+ PipeDscPtr->SendErrors++;
+ } /*end if */
+
+ } /* end loop over destinations */
+ }
+
+ /*
+ * If any specific delivery issues occured, also increment the
+ * general error count before releasing the lock.
+ */
+ if (SBSndErr.EvtsToSnd > 0)
+ {
+ CFE_SB_Global.HKTlmMsg.Payload.MsgSendErrorCounter++;
+ }
+
+ /*
+ * Remove this from whatever list it was in
+ *
+ * If it was a singleton/new buffer this has no effect.
+ * If it was a zero-copy buffer this removes it from the ZeroCopyList.
+ */
+ CFE_SB_TrackingListRemove(&BufDscPtr->Link);
+
+ /* clear the AppID field in case it was a zero copy buffer,
+ * as it is no longer owned by that app after broadcasting */
+ BufDscPtr->AppId = CFE_ES_APPID_UNDEFINED;
+
+ /* track the buffer as an in-transit message */
+ CFE_SB_TrackingListAdd(&CFE_SB_Global.InTransitList, &BufDscPtr->Link);
+
+ /*
+ ** Decrement the buffer UseCount and free buffer if cnt=0. This decrement is done
+ ** because the use cnt is initialized to 1 in CFE_SB_GetBufferFromPool.
+ ** Initializing the count to 1 (as opposed to zero) and decrementing it here are
+ ** done to ensure the buffer gets released when there are destinations that have
+ ** been disabled via ground command.
+ */
+ CFE_SB_DecrBufUseCnt(BufDscPtr);
+
+ /* release the semaphore */
+ CFE_SB_UnlockSharedData(__func__, __LINE__);
+
+ /* send an event for each pipe write error that may have occurred */
+ for (i = 0; i < SBSndErr.EvtsToSnd; i++)
+ {
+ if (SBSndErr.EvtBuf[i].EventId == CFE_SB_MSGID_LIM_ERR_EID)
+ {
+
+ /* Determine if event can be sent without causing recursive event problem */
+ if (CFE_SB_RequestToSendEvent(TskId, CFE_SB_MSGID_LIM_ERR_EID_BIT) == CFE_SB_GRANTED)
+ {
+
+ CFE_SB_GetPipeName(PipeName, sizeof(PipeName), SBSndErr.EvtBuf[i].PipeId);
+
+ CFE_ES_PerfLogEntry(CFE_MISSION_SB_MSG_LIM_PERF_ID);
+ CFE_ES_PerfLogExit(CFE_MISSION_SB_MSG_LIM_PERF_ID);
+
+ CFE_EVS_SendEventWithAppID(CFE_SB_MSGID_LIM_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "Msg Limit Err,MsgId 0x%x,pipe %s,sender %s",
+ (unsigned int)CFE_SB_MsgIdToValue(BufDscPtr->MsgId), PipeName,
+ CFE_SB_GetAppTskName(TskId, FullName));
+
+ /* clear the bit so the task may send this event again */
+ CFE_SB_FinishSendEvent(TskId, CFE_SB_MSGID_LIM_ERR_EID_BIT);
+ } /* end if */
+ }
+ else if (SBSndErr.EvtBuf[i].EventId == CFE_SB_Q_FULL_ERR_EID)
+ {
+
+ /* Determine if event can be sent without causing recursive event problem */
+ if (CFE_SB_RequestToSendEvent(TskId, CFE_SB_Q_FULL_ERR_EID_BIT) == CFE_SB_GRANTED)
+ {
+
+ CFE_SB_GetPipeName(PipeName, sizeof(PipeName), SBSndErr.EvtBuf[i].PipeId);
+
+ CFE_ES_PerfLogEntry(CFE_MISSION_SB_PIPE_OFLOW_PERF_ID);
+ CFE_ES_PerfLogExit(CFE_MISSION_SB_PIPE_OFLOW_PERF_ID);
+
+ CFE_EVS_SendEventWithAppID(CFE_SB_Q_FULL_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "Pipe Overflow,MsgId 0x%x,pipe %s,sender %s",
+ (unsigned int)CFE_SB_MsgIdToValue(BufDscPtr->MsgId), PipeName,
+ CFE_SB_GetAppTskName(TskId, FullName));
+
+ /* clear the bit so the task may send this event again */
+ CFE_SB_FinishSendEvent(TskId, CFE_SB_Q_FULL_ERR_EID_BIT);
+ } /* end if */
+ }
+ else
+ {
+
+ /* Determine if event can be sent without causing recursive event problem */
+ if (CFE_SB_RequestToSendEvent(TskId, CFE_SB_Q_WR_ERR_EID_BIT) == CFE_SB_GRANTED)
+ {
+
+ CFE_SB_GetPipeName(PipeName, sizeof(PipeName), SBSndErr.EvtBuf[i].PipeId);
+
+ CFE_EVS_SendEventWithAppID(CFE_SB_Q_WR_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "Pipe Write Err,MsgId 0x%x,pipe %s,sender %s,stat 0x%x",
+ (unsigned int)CFE_SB_MsgIdToValue(BufDscPtr->MsgId), PipeName,
+ CFE_SB_GetAppTskName(TskId, FullName),
+ (unsigned int)SBSndErr.EvtBuf[i].ErrStat);
+
+ /* clear the bit so the task may send this event again */
+ CFE_SB_FinishSendEvent(TskId, CFE_SB_Q_WR_ERR_EID_BIT);
+ } /* end if */
+
+ } /* end if */
+ }
+}
+
+/*
+ * Function: CFE_SB_ReceiveBuffer - See API and header file for details
+ */
+int32 CFE_SB_ReceiveBuffer(CFE_SB_Buffer_t **BufPtr, CFE_SB_PipeId_t PipeId, int32 TimeOut)
+{
+ int32 Status;
+ int32 RcvStatus;
+ CFE_SB_BufferD_t * BufDscPtr;
+ size_t BufDscSize;
+ CFE_SB_PipeD_t * PipeDscPtr;
+ CFE_SB_DestinationD_t *DestPtr;
+ CFE_SBR_RouteId_t RouteId;
+ CFE_ES_TaskId_t TskId;
+ uint16 PendingEventID;
+ osal_id_t SysQueueId;
+ int32 SysTimeout;
+ char FullName[(OS_MAX_API_NAME * 2)];
+
+ PendingEventID = 0;
+ Status = CFE_SUCCESS;
+ SysTimeout = OS_PEND;
+ SysQueueId = OS_OBJECT_ID_UNDEFINED;
+ PipeDscPtr = NULL;
+ BufDscPtr = NULL;
+ DestPtr = NULL;
+ BufDscSize = 0;
+ RcvStatus = OS_SUCCESS;
+
+ /*
+ * Check input args and see if any are bad, which require
+ * a "BAD_ARG_EID" to be generated.
+ *
+ * Also translate the timeout here. Timeouts greater than 0
+ * may be passed to OSAL directly, but the two fixed constants
+ * CFE_SB_PEND_FOREVER and CFE_SB_POLL are checked explicitly,
+ * to maintain API independence - even though the values are
+ * currently defined the same.
+ */
+
+ if (BufPtr == NULL)
+ {
+ PendingEventID = CFE_SB_RCV_BAD_ARG_EID;
+ Status = CFE_SB_BAD_ARGUMENT;
+ }
+ else if (TimeOut > 0)
+ {
+ /* time outs greater than 0 can be passed to OSAL directly */
+ SysTimeout = TimeOut;
+ }
+ else if (TimeOut == CFE_SB_POLL)
+ {
+ SysTimeout = OS_CHECK;
+ }
+ else if (TimeOut != CFE_SB_PEND_FOREVER)
+ {
+ /* any other timeout value is invalid */
+ PendingEventID = CFE_SB_RCV_BAD_ARG_EID;
+ Status = CFE_SB_BAD_ARGUMENT;
+ }
+
+ /* If OK, then lock and pull relevent info from Pipe Descriptor */
+ if (Status == CFE_SUCCESS)
+ {
+ CFE_SB_LockSharedData(__func__, __LINE__);
+
+ PipeDscPtr = CFE_SB_LocatePipeDescByID(PipeId);
+
+ /* If the pipe does not exist or PipeId is out of range... */
+ if (!CFE_SB_PipeDescIsMatch(PipeDscPtr, PipeId))
+ {
+ PendingEventID = CFE_SB_BAD_PIPEID_EID;
+ Status = CFE_SB_BAD_ARGUMENT;
+ }
+ else
+ {
+ /* Grab the queue ID */
+ SysQueueId = PipeDscPtr->SysQueueId;
+
+ /*
+ * Un-reference any previous buffer from the last call.
+ *
+ * NOTE: This is historical behavior where apps call CFE_SB_ReceiveBuffer()
+ * in the loop within the app's main task. There is currently no separate
+ * API to "free" or unreference a buffer that was returned from SB.
+ *
+ * Instead, each time this function is invoked, it is implicitly interpreted
+ * as an indication that the caller is done with the previous buffer.
+ *
+ * Unfortunately this prevents pipe IDs from being serviced/shared across
+ * multiple child tasks in a worker pattern design. This may be changed
+ * in a future version of CFE to decouple these actions, to allow for
+ * multiple workers to service the same pipe.
+ */
+ if (PipeDscPtr->LastBuffer != NULL)
+ {
+ /* Decrement the Buffer Use Count, which will Free buffer if it becomes 0 */
+ CFE_SB_DecrBufUseCnt(PipeDscPtr->LastBuffer);
+ PipeDscPtr->LastBuffer = NULL;
+ }
+ }
+
+ CFE_SB_UnlockSharedData(__func__, __LINE__);
+ }
+
+ /*
+ * If everything validated, then proceed to get a buffer from the queue.
+ * This must be done OUTSIDE the SB lock, as this call likely blocks.
+ */
+ if (Status == CFE_SUCCESS)
+ {
+ /* Read the buffer descriptor address from the queue. */
+ RcvStatus = OS_QueueGet(SysQueueId, &BufDscPtr, sizeof(BufDscPtr), &BufDscSize, SysTimeout);
+
+ /*
+ * translate the return value -
+ *
+ * CFE functions have their own set of RC values should not directly return OSAL codes
+ * The size should always match. If it does not, then generate CFE_SB_Q_RD_ERR_EID.
+ */
+ if (RcvStatus == OS_SUCCESS && BufDscPtr != NULL && BufDscSize == sizeof(BufDscPtr))
+ {
+ /* Pass through */
+ }
+ else if (RcvStatus == OS_QUEUE_EMPTY)
+ {
+ /* normal if using CFE_SB_POLL */
+ Status = CFE_SB_NO_MESSAGE;
+ }
+ else if (RcvStatus == OS_QUEUE_TIMEOUT)
+ {
+ /* normal if using a nonzero timeout */
+ Status = CFE_SB_TIME_OUT;
+ }
+ else
+ {
+ /* off-nominal condition, report an error event */
+ PendingEventID = CFE_SB_Q_RD_ERR_EID;
+ Status = CFE_SB_PIPE_RD_ERR;
+ }
+ }
+
+ /* Now re-lock to store the buffer in the pipe descriptor */
+ CFE_SB_LockSharedData(__func__, __LINE__);
+
+ if (Status == CFE_SUCCESS)
+ {
+ /*
+ * NOTE: This uses the same PipeDscPtr that was found earlier.
+ * Technically it is possible that the pipe was changed between now and then,
+ * but the current PipeID definition doesn't really allow this to be detected.
+ */
+ if (CFE_SB_PipeDescIsMatch(PipeDscPtr, PipeId))
+ {
+ /*
+ ** Load the pipe tables 'CurrentBuff' with the buffer descriptor
+ ** ptr corresponding to the message just read. This is done so that
+ ** the buffer can be released on the next receive call for this pipe.
+ **
+ ** This counts as a new reference as it is being stored in the PipeDsc
+ */
+ CFE_SB_IncrBufUseCnt(BufDscPtr);
+ PipeDscPtr->LastBuffer = BufDscPtr;
+
+ /*
+ * Also set the Receivers pointer to the address of the actual message
+ * (currently this is "borrowing" the ref above, not its own ref)
+ */
+ *BufPtr = &BufDscPtr->Content;
+
+ /* get pointer to destination to be used in decrementing msg limit cnt*/
+ RouteId = CFE_SBR_GetRouteId(BufDscPtr->MsgId);
+ DestPtr = CFE_SB_GetDestPtr(RouteId, PipeId);
+
+ /*
+ ** DestPtr would be NULL if the msg is unsubscribed to while it is on
+ ** the pipe. The BuffCount may be zero if the msg is unsubscribed to and
+ ** then resubscribed to while it is on the pipe. Both of these cases are
+ ** considered nominal and are handled by the code below.
+ */
+ if (DestPtr != NULL && DestPtr->BuffCount > 0)
+ {
+ DestPtr->BuffCount--;
+ }
+
+ if (PipeDscPtr->CurrentQueueDepth > 0)
+ {
+ --PipeDscPtr->CurrentQueueDepth;
+ }
+ }
+ else
+ {
+ /* should send the bad pipe ID event here too */
+ PendingEventID = CFE_SB_BAD_PIPEID_EID;
+ Status = CFE_SB_PIPE_RD_ERR;
+ }
+
+ /* Always decrement the use count, for the ref that was in the queue */
+ CFE_SB_DecrBufUseCnt(BufDscPtr);
+ }
+
+ /* Before unlocking, check the PendingEventID and increment relevant error counter */
+ if (Status != CFE_SUCCESS)
+ {
+ if (PendingEventID == CFE_SB_RCV_BAD_ARG_EID || PendingEventID == CFE_SB_BAD_PIPEID_EID)
+ {
+ ++CFE_SB_Global.HKTlmMsg.Payload.MsgReceiveErrorCounter;
+ }
+ else
+ {
+ /* For any other unexpected error (e.g. CFE_SB_Q_RD_ERR_EID) */
+ ++CFE_SB_Global.HKTlmMsg.Payload.InternalErrorCounter;
+ }
+ }
+
+ CFE_SB_UnlockSharedData(__func__, __LINE__);
+
+ /* Now actually send the event, after unlocking (do not call EVS with SB locked) */
+ if (PendingEventID != 0)
+ {
+ /* get task id for events */
+ CFE_ES_GetTaskID(&TskId);
+
+ switch (PendingEventID)
+ {
+ case CFE_SB_Q_RD_ERR_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_Q_RD_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "Pipe Read Err,pipe %lu,app %s,stat 0x%x", CFE_RESOURCEID_TO_ULONG(PipeId),
+ CFE_SB_GetAppTskName(TskId, FullName), (unsigned int)RcvStatus);
+ break;
+ case CFE_SB_RCV_BAD_ARG_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_RCV_BAD_ARG_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "Rcv Err:Bad Input Arg:BufPtr 0x%lx,pipe %lu,t/o %d,app %s",
+ (unsigned long)BufPtr, CFE_RESOURCEID_TO_ULONG(PipeId), (int)TimeOut,
+ CFE_SB_GetAppTskName(TskId, FullName));
+ break;
+ case CFE_SB_BAD_PIPEID_EID:
+ CFE_EVS_SendEventWithAppID(CFE_SB_BAD_PIPEID_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "Rcv Err:PipeId %lu does not exist,app %s", CFE_RESOURCEID_TO_ULONG(PipeId),
+ CFE_SB_GetAppTskName(TskId, FullName));
+ break;
+ }
+ }
+
+ /* If not successful, set the output pointer to NULL */
+ if (Status != CFE_SUCCESS && BufPtr != NULL)
+ {
+ *BufPtr = NULL;
+ }
+
+ return Status;
+}
+
+/*
+ * Function: CFE_SB_AllocateMessageBuffer - See API and header file for details
+ */
+CFE_SB_Buffer_t *CFE_SB_AllocateMessageBuffer(size_t MsgSize)
+{
+ CFE_ES_AppId_t AppId;
+ CFE_SB_BufferD_t *BufDscPtr;
+ CFE_SB_Buffer_t * BufPtr;
+
+ AppId = CFE_ES_APPID_UNDEFINED;
+ BufDscPtr = NULL;
+ BufPtr = NULL;
+
+ if (MsgSize > CFE_MISSION_SB_MAX_SB_MSG_SIZE)
+ {
+ CFE_ES_WriteToSysLog(" CFE_SB:ZeroCopyGetPtr-Failed, MsgSize is too large\n");
+ return NULL;
+ }
+
+ /* get callers AppId */
+ if (CFE_ES_GetAppID(&AppId) == CFE_SUCCESS)
+ {
+ CFE_SB_LockSharedData(__func__, __LINE__);
+
+ /*
+ * All this needs to do is get a descriptor from the pool,
+ * and associate that descriptor with this app ID, so it
+ * can be freed if this app is deleted before it uses it.
+ */
+ BufDscPtr = CFE_SB_GetBufferFromPool(MsgSize);
+
+ if (BufDscPtr != NULL)
+ {
+ /* Track the buffer as a zero-copy assigned to this app ID */
+ BufDscPtr->AppId = AppId;
+ BufPtr = &BufDscPtr->Content;
+ CFE_SB_TrackingListAdd(&CFE_SB_Global.ZeroCopyList, &BufDscPtr->Link);
+ }
+
+ CFE_SB_UnlockSharedData(__func__, __LINE__);
+ }
+
+ if (BufPtr != NULL)
+ {
+ /*
+ * If a buffer was obtained, wipe it now.
+ * (This ensures the buffer is fully cleared at least once,
+ * no stale data from a prior use of the same memory)
+ */
+ memset(BufPtr, 0, MsgSize);
+ }
+
+ return BufPtr;
+
+} /* CFE_SB_AllocateMessageBuffer */
+
+/*
+ * Helper function to do sanity checks on the Zero Copy Buffer and
+ * outputs the encapsulating descriptor if successful
+ */
+int32 CFE_SB_ZeroCopyBufferValidate(CFE_SB_Buffer_t *BufPtr, CFE_SB_BufferD_t **BufDscPtr)
+{
+ cpuaddr BufDscAddr;
+
+ /*
+ * Sanity Check that the pointers are not NULL
+ */
+ if (BufPtr == NULL)
+ {
+ return CFE_SB_BAD_ARGUMENT;
+ }
+
+ /*
+ * Calculate descriptor pointer from buffer pointer -
+ * The buffer is just a member (offset) in the descriptor
+ */
+ BufDscAddr = (cpuaddr)BufPtr - offsetof(CFE_SB_BufferD_t, Content);
+ *BufDscPtr = (CFE_SB_BufferD_t *)BufDscAddr;
+
+ /*
+ * Check that the descriptor is actually a "zero copy" type,
+ */
+ if (!CFE_RESOURCEID_TEST_DEFINED((*BufDscPtr)->AppId))
+ {
+ return CFE_SB_BUFFER_INVALID;
+ }
+
+ /* Basic sanity check passed */
+ return CFE_SUCCESS;
+}
+
+/*
+ * Function: CFE_SB_ReleaseMessageBuffer - See API and header file for details
+ */
+CFE_Status_t CFE_SB_ReleaseMessageBuffer(CFE_SB_Buffer_t *BufPtr)
+{
+ CFE_SB_BufferD_t *BufDscPtr;
+ int32 Status;
+
+ Status = CFE_SB_ZeroCopyBufferValidate(BufPtr, &BufDscPtr);
+
+ CFE_SB_LockSharedData(__func__, __LINE__);
+
+ if (Status == CFE_SUCCESS)
+ {
+ /* Clear the ownership app ID and decrement use count (may also free) */
+ BufDscPtr->AppId = CFE_ES_APPID_UNDEFINED;
+ CFE_SB_DecrBufUseCnt(BufDscPtr);
+ }
+
+ CFE_SB_UnlockSharedData(__func__, __LINE__);
+
+ return Status;
+
+} /* end CFE_SB_ReleaseMessageBuffer */
+
+/*
+ * Function CFE_SB_TransmitBuffer - See API and header file for details
+ */
+int32 CFE_SB_TransmitBuffer(CFE_SB_Buffer_t *BufPtr, bool IncrementSequenceCount)
+{
+ int32 Status;
+ CFE_SB_BufferD_t *BufDscPtr;
+ CFE_SBR_RouteId_t RouteId;
+
+ Status = CFE_SB_ZeroCopyBufferValidate(BufPtr, &BufDscPtr);
+
+ if (Status == CFE_SUCCESS)
+ {
+ /* Validate the content and get the MsgId, store it in the descriptor */
+ Status = CFE_SB_TransmitMsgValidate(&BufPtr->Msg, &BufDscPtr->MsgId, &BufDscPtr->ContentSize, &RouteId);
+
+ /*
+ * Broadcast the message if validation succeeded.
+ *
+ * Note that for the case of no subscribers, the validation returns CFE_SUCCESS
+ * but the actual route ID may be invalid. This is OK and considered normal-
+ * the validation will increment the NoSubscribers count, but we should NOT
+ * increment the MsgSendErrorCounter here - it is not really a sending error to
+ * have no subscribers. CFE_SB_BroadcastBufferToRoute() will not send to
+ * anything if the route is not valid (benign).
+ */
+ if (Status == CFE_SUCCESS)
+ {
+ BufDscPtr->AutoSequence = IncrementSequenceCount;
+ CFE_MSG_GetType(&BufPtr->Msg, &BufDscPtr->ContentType);
+
+ /* Now broadcast the message, which consumes the buffer */
+ CFE_SB_BroadcastBufferToRoute(BufDscPtr, RouteId);
+
+ /*
+ * IMPORTANT - the descriptor might be freed at any time after this,
+ * so the descriptor should not be accessed again after this point.
+ */
+ BufDscPtr = NULL;
+ }
+ }
+
+ if (Status != CFE_SUCCESS)
+ {
+ /* Increment send error counter for validation failure */
+ CFE_SB_LockSharedData(__func__, __LINE__);
+ CFE_SB_Global.HKTlmMsg.Payload.MsgSendErrorCounter++;
+ CFE_SB_UnlockSharedData(__func__, __LINE__);
+ }
+
+ return Status;
+}
diff --git a/modules/sb/fsw/src/cfe_sb_buf.c b/modules/sb/fsw/src/cfe_sb_buf.c
new file mode 100644
index 000000000..fc4d595ae
--- /dev/null
+++ b/modules/sb/fsw/src/cfe_sb_buf.c
@@ -0,0 +1,317 @@
+/*
+** 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_sb_buf.c
+**
+** Purpose:
+** This file contains the source code for the SB memory management
+** functions.
+**
+** Author: R.McGraw/SSI
+**
+******************************************************************************/
+
+/*
+** Include Files
+*/
+
+#include "cfe_sb_module_all.h"
+
+/*
+ * The actual message content of a SB Buffer Descriptor is the
+ * offset of the content member. This will be auto-aligned by
+ * the compiler according to the requirements of the machine.
+ */
+#define CFE_SB_BUFFERD_CONTENT_OFFSET (offsetof(CFE_SB_BufferD_t, Content))
+
+/******************************************************************************
+ *
+ * Helper function to reset/clear the links on a list node (make empty)
+ */
+void CFE_SB_TrackingListReset(CFE_SB_BufferLink_t *Link)
+{
+ /* A singleton node/empty list points to itself */
+ Link->Prev = Link;
+ Link->Next = Link;
+}
+
+/******************************************************************************
+ *
+ * Helper function to remove a node from a tracking list
+ */
+void CFE_SB_TrackingListRemove(CFE_SB_BufferLink_t *Node)
+{
+ /* Remove from list */
+ Node->Prev->Next = Node->Next;
+ Node->Next->Prev = Node->Prev;
+
+ /* The node is now a singleton */
+ CFE_SB_TrackingListReset(Node);
+}
+
+/******************************************************************************
+ *
+ * Helper function to add a node to a tracking list
+ */
+void CFE_SB_TrackingListAdd(CFE_SB_BufferLink_t *List, CFE_SB_BufferLink_t *Node)
+{
+ /* Connect this node to the list at "prev" position (tail) */
+ Node->Prev = List->Prev;
+ Node->Next = List;
+
+ /* Connect list nodes to this node */
+ Node->Prev->Next = Node;
+ Node->Next->Prev = Node;
+}
+
+/******************************************************************************
+** Function: CFE_SB_GetBufferFromPool()
+**
+** Purpose:
+** Request a buffer from the SB buffer pool. The SB buffer pool is a
+** pre-allocated block of memory of size CFE_PLATFORM_SB_BUF_MEMORY_BYTES. It is used
+** by the SB to dynamically allocate memory to hold the message and a buffer
+** descriptor associated with the message during the sending of a message.
+**
+** Note:
+** This must only be invoked while holding the SB global lock
+**
+** Arguments:
+** MaxMsgSize : Size of the buffer content area in bytes.
+**
+** Return:
+** Pointer to the buffer descriptor for the new buffer, or NULL if the buffer
+** could not be allocated.
+*/
+
+CFE_SB_BufferD_t *CFE_SB_GetBufferFromPool(size_t MaxMsgSize)
+{
+ int32 stat1;
+ size_t AllocSize;
+ CFE_SB_BufferD_t *bd = NULL;
+
+ /* The allocation needs to include enough space for the descriptor object */
+ AllocSize = MaxMsgSize + CFE_SB_BUFFERD_CONTENT_OFFSET;
+
+ /* Allocate a new buffer descriptor from the SB memory pool.*/
+ stat1 = CFE_ES_GetPoolBuf((CFE_ES_MemPoolBuf_t *)&bd, CFE_SB_Global.Mem.PoolHdl, AllocSize);
+ if (stat1 < 0)
+ {
+ return NULL;
+ }
+
+ /* increment the number of buffers in use and adjust the high water mark if needed */
+ CFE_SB_Global.StatTlmMsg.Payload.SBBuffersInUse++;
+ if (CFE_SB_Global.StatTlmMsg.Payload.SBBuffersInUse > CFE_SB_Global.StatTlmMsg.Payload.PeakSBBuffersInUse)
+ {
+ CFE_SB_Global.StatTlmMsg.Payload.PeakSBBuffersInUse = CFE_SB_Global.StatTlmMsg.Payload.SBBuffersInUse;
+ } /* end if */
+
+ /* Add the size of the actual buffer to the memory-in-use ctr and */
+ /* adjust the high water mark if needed */
+ CFE_SB_Global.StatTlmMsg.Payload.MemInUse += AllocSize;
+ if (CFE_SB_Global.StatTlmMsg.Payload.MemInUse > CFE_SB_Global.StatTlmMsg.Payload.PeakMemInUse)
+ {
+ CFE_SB_Global.StatTlmMsg.Payload.PeakMemInUse = CFE_SB_Global.StatTlmMsg.Payload.MemInUse;
+ } /* end if */
+
+ /* Initialize the buffer descriptor structure. */
+ memset(bd, 0, CFE_SB_BUFFERD_CONTENT_OFFSET);
+
+ bd->MsgId = CFE_SB_INVALID_MSG_ID;
+ bd->UseCount = 1;
+ bd->AllocatedSize = AllocSize;
+
+ CFE_SB_TrackingListReset(&bd->Link);
+
+ return bd;
+
+} /* CFE_SB_GetBufferFromPool */
+
+/******************************************************************************
+** Function: CFE_SB_ReturnBufferToPool()
+**
+** Purpose:
+** This function will return two blocks of memory back to the memory pool.
+** One block is the memory used to store the actual message, the other block
+** was used to store the buffer descriptor for the message.
+**
+** Note:
+** This must only be invoked while holding the SB global lock
+**
+** Arguments:
+** bd : Pointer to the buffer descriptor.
+**
+** Return:
+** None
+*/
+void CFE_SB_ReturnBufferToPool(CFE_SB_BufferD_t *bd)
+{
+ /* Remove from any tracking list (no effect if not in a list) */
+ CFE_SB_TrackingListRemove(&bd->Link);
+
+ --CFE_SB_Global.StatTlmMsg.Payload.SBBuffersInUse;
+ CFE_SB_Global.StatTlmMsg.Payload.MemInUse -= bd->AllocatedSize;
+
+ /* finally give the buf descriptor back to the buf descriptor pool */
+ CFE_ES_PutPoolBuf(CFE_SB_Global.Mem.PoolHdl, bd);
+
+} /* end CFE_SB_ReturnBufferToPool */
+
+/******************************************************************************
+** Function: CFE_SB_IncrBufUseCnt()
+**
+** Purpose:
+** This function will increment the UseCount of a particular buffer.
+**
+** Note:
+** UseCount is a variable in the CFE_SB_BufferD_t and is used only to
+** determine when a buffer may be returned to the memory pool.
+**
+** This must only be invoked while holding the SB global lock
+**
+** Arguments:
+** bd : Pointer to the buffer descriptor.
+**
+** Return:
+** CFE_SUCCESS for normal operation.
+*/
+void CFE_SB_IncrBufUseCnt(CFE_SB_BufferD_t *bd)
+{
+ /* range check the UseCount variable */
+ if (bd->UseCount < 0x7FFF)
+ {
+ ++bd->UseCount;
+ }
+
+} /* end CFE_SB_DecrBufUseCnt */
+
+/******************************************************************************
+** Function: CFE_SB_DecrBufUseCnt()
+**
+** Purpose:
+** This function will decrement the UseCount of a particular buffer. If the
+** the UseCount is decremented to zero, it will return the buffer to the
+** memory pool.
+**
+** Note:
+** UseCount is a variable in the CFE_SB_BufferD_t and is used only to
+** determine when a buffer may be returned to the memory pool.
+**
+** This must only be invoked while holding the SB global lock
+**
+** Arguments:
+** bd : Pointer to the buffer descriptor.
+**
+** Return:
+** CFE_SUCCESS for normal operation.
+*/
+void CFE_SB_DecrBufUseCnt(CFE_SB_BufferD_t *bd)
+{
+ /* range check the UseCount variable */
+ if (bd->UseCount > 0)
+ {
+ --bd->UseCount;
+
+ if (bd->UseCount == 0)
+ {
+ CFE_SB_ReturnBufferToPool(bd);
+ }
+ }
+
+} /* end CFE_SB_DecrBufUseCnt */
+
+/******************************************************************************
+** Function: CFE_SB_GetDestinationBlk()
+**
+** Purpose:
+** This function gets a destination descriptor from the SB memory pool.
+**
+** Note:
+** This must only be invoked while holding the SB global lock
+**
+** Arguments:
+** None
+**
+** Return:
+** Pointer to the destination descriptor
+*/
+CFE_SB_DestinationD_t *CFE_SB_GetDestinationBlk(void)
+{
+ int32 Stat;
+ CFE_SB_DestinationD_t *Dest = NULL;
+
+ /* Allocate a new destination descriptor from the SB memory pool.*/
+ Stat = CFE_ES_GetPoolBuf((CFE_ES_MemPoolBuf_t *)&Dest, CFE_SB_Global.Mem.PoolHdl, sizeof(CFE_SB_DestinationD_t));
+ if (Stat < 0)
+ {
+ return NULL;
+ }
+
+ /* Add the size of a destination descriptor to the memory-in-use ctr and */
+ /* adjust the high water mark if needed */
+ CFE_SB_Global.StatTlmMsg.Payload.MemInUse += Stat;
+ if (CFE_SB_Global.StatTlmMsg.Payload.MemInUse > CFE_SB_Global.StatTlmMsg.Payload.PeakMemInUse)
+ {
+ CFE_SB_Global.StatTlmMsg.Payload.PeakMemInUse = CFE_SB_Global.StatTlmMsg.Payload.MemInUse;
+ } /* end if */
+
+ return Dest;
+
+} /* end CFE_SB_GetDestinationBlk */
+
+/******************************************************************************
+** Function: CFE_SB_PutDestinationBlk()
+**
+** Purpose:
+** This function returns a destination descriptor to the SB memory pool.
+**
+** Note:
+** This must only be invoked while holding the SB global lock
+**
+** Arguments:
+** None
+**
+** Return:
+** Pointer to the destination descriptor
+*/
+int32 CFE_SB_PutDestinationBlk(CFE_SB_DestinationD_t *Dest)
+{
+ int32 Stat;
+
+ if (Dest == NULL)
+ {
+ return CFE_SB_BAD_ARGUMENT;
+ } /* end if */
+
+ /* give the destination block back to the SB memory pool */
+ Stat = CFE_ES_PutPoolBuf(CFE_SB_Global.Mem.PoolHdl, Dest);
+ if (Stat > 0)
+ {
+ /* Substract the size of the destination block from the Memory in use ctr */
+ CFE_SB_Global.StatTlmMsg.Payload.MemInUse -= Stat;
+ } /* end if */
+
+ return CFE_SUCCESS;
+
+} /* end CFE_SB_PutDestinationBlk */
+
+/*****************************************************************************/
diff --git a/modules/sb/fsw/src/cfe_sb_init.c b/modules/sb/fsw/src/cfe_sb_init.c
new file mode 100644
index 000000000..5312de7af
--- /dev/null
+++ b/modules/sb/fsw/src/cfe_sb_init.c
@@ -0,0 +1,166 @@
+/*
+** 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_sb_init.c
+**
+** Purpose:
+** This file contains the source code for the SB Initialization.
+**
+** Author: R.McGraw/SSI
+**
+******************************************************************************/
+
+/*
+** Include Files
+*/
+
+#include "cfe_sb_module_all.h"
+
+#include
+
+/*
+** External Declarations
+*/
+
+const size_t CFE_SB_MemPoolDefSize[CFE_PLATFORM_ES_POOL_MAX_BUCKETS] = {
+ CFE_PLATFORM_SB_MAX_BLOCK_SIZE, CFE_PLATFORM_SB_MEM_BLOCK_SIZE_16, CFE_PLATFORM_SB_MEM_BLOCK_SIZE_15,
+ CFE_PLATFORM_SB_MEM_BLOCK_SIZE_14, CFE_PLATFORM_SB_MEM_BLOCK_SIZE_13, CFE_PLATFORM_SB_MEM_BLOCK_SIZE_12,
+ CFE_PLATFORM_SB_MEM_BLOCK_SIZE_11, CFE_PLATFORM_SB_MEM_BLOCK_SIZE_10, CFE_PLATFORM_SB_MEM_BLOCK_SIZE_09,
+ CFE_PLATFORM_SB_MEM_BLOCK_SIZE_08, CFE_PLATFORM_SB_MEM_BLOCK_SIZE_07, CFE_PLATFORM_SB_MEM_BLOCK_SIZE_06,
+ CFE_PLATFORM_SB_MEM_BLOCK_SIZE_05, CFE_PLATFORM_SB_MEM_BLOCK_SIZE_04, CFE_PLATFORM_SB_MEM_BLOCK_SIZE_03,
+ CFE_PLATFORM_SB_MEM_BLOCK_SIZE_02, CFE_PLATFORM_SB_MEM_BLOCK_SIZE_01};
+
+/******************************************************************************
+** Function: CFE_SB_EarlyInit()
+**
+** Purpose:
+** Initialize the Software Bus routing tables.
+**
+** Arguments:
+**
+** Notes:
+** This function MUST be called before any SB API's are called.
+**
+** Return:
+** CFE_SUCCESS
+*/
+int32 CFE_SB_EarlyInit(void)
+{
+
+ int32 Stat;
+
+ /* Clear task global */
+ memset(&CFE_SB_Global, 0, sizeof(CFE_SB_Global));
+
+ Stat = OS_MutSemCreate(&CFE_SB_Global.SharedDataMutexId, "CFE_SB_DataMutex", 0);
+ if (Stat != OS_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("SB shared data mutex creation failed! RC=0x%08x\n", (unsigned int)Stat);
+ return Stat;
+ } /* end if */
+
+ /* Initialize the state of susbcription reporting */
+ CFE_SB_Global.SubscriptionReporting = CFE_SB_DISABLE;
+
+ /* Initialize memory partition. */
+ Stat = CFE_SB_InitBuffers();
+ if (Stat != CFE_SUCCESS)
+ {
+ /* error reported in CFE_SB_InitBuffers */
+ return Stat;
+ } /* end if */
+
+ /* Initialize the pipe table. */
+ CFE_SB_InitPipeTbl();
+
+ /* Initialize the routing module */
+ CFE_SBR_Init();
+
+ /* Initialize the SB Statistics Pkt */
+ CFE_MSG_Init(&CFE_SB_Global.StatTlmMsg.Hdr.Msg, CFE_SB_ValueToMsgId(CFE_SB_STATS_TLM_MID),
+ sizeof(CFE_SB_Global.StatTlmMsg));
+
+ return Stat;
+
+} /* end CFE_SB_EarlyInit */
+
+/******************************************************************************
+** Function: CFE_SB_InitBuffers()
+**
+** Purpose:
+** Initialize the Software Bus Buffer Pool.
+**
+** Arguments:
+**
+** Notes:
+** This function MUST be called before any SB API's are called.
+**
+** Return:
+** none
+*/
+int32 CFE_SB_InitBuffers(void)
+{
+
+ int32 Stat = 0;
+
+ Stat = CFE_ES_PoolCreateEx(&CFE_SB_Global.Mem.PoolHdl, CFE_SB_Global.Mem.Partition.Data,
+ CFE_PLATFORM_SB_BUF_MEMORY_BYTES, CFE_PLATFORM_ES_POOL_MAX_BUCKETS,
+ &CFE_SB_MemPoolDefSize[0], CFE_ES_NO_MUTEX);
+
+ if (Stat != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("PoolCreate failed for SB Buffers, gave adr 0x%lx,size %d,stat=0x%x\n",
+ (unsigned long)CFE_SB_Global.Mem.Partition.Data, CFE_PLATFORM_SB_BUF_MEMORY_BYTES,
+ (unsigned int)Stat);
+ return Stat;
+ }
+
+ /*
+ * Initialize the buffer tracking lists to be empty
+ */
+ CFE_SB_TrackingListReset(&CFE_SB_Global.InTransitList);
+ CFE_SB_TrackingListReset(&CFE_SB_Global.ZeroCopyList);
+
+ return CFE_SUCCESS;
+
+} /* end CFE_SB_InitBuffers */
+
+/******************************************************************************
+** Function: CFE_SB_InitPipeTbl()
+**
+** Purpose:
+** Initialize the Software Bus Pipe Table.
+**
+** Arguments:
+**
+** Notes:
+** This function MUST be called before any SB API's are called.
+**
+** Return:
+** none
+*/
+void CFE_SB_InitPipeTbl(void)
+{
+ CFE_SB_Global.LastPipeId = CFE_ResourceId_FromInteger(CFE_SB_PIPEID_BASE);
+
+} /* end CFE_SB_InitPipeTbl */
+
+/*****************************************************************************/
diff --git a/modules/sb/fsw/src/cfe_sb_module_all.h b/modules/sb/fsw/src/cfe_sb_module_all.h
new file mode 100644
index 000000000..f54ecb67c
--- /dev/null
+++ b/modules/sb/fsw/src/cfe_sb_module_all.h
@@ -0,0 +1,51 @@
+/*
+** 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
+ *
+ * Encapsulates all SB module internal header files, as well
+ * as the public API from all other CFE core modules, OSAL, and PSP.
+ *
+ * This simplifies the set of include files that need to be put at the
+ * start of every source file.
+ */
+
+#ifndef CFE_SB_MODULE_ALL_H
+#define CFE_SB_MODULE_ALL_H
+
+/*
+** Includes
+*/
+#include "cfe.h"
+#include "cfe_platform_cfg.h"
+#include "cfe_msgids.h"
+#include "cfe_perfids.h"
+
+#include "cfe_sb_core_internal.h"
+
+#include "cfe_sb_priv.h"
+#include "cfe_sb_events.h"
+#include "cfe_sb_destination_typedef.h"
+#include "cfe_sb_msg.h"
+#include "cfe_sbr.h"
+#include "cfe_core_resourceid_basevalues.h"
+
+#endif /* CFE_SB_MODULE_ALL_H */
diff --git a/modules/sb/fsw/src/cfe_sb_msg_id_util.c b/modules/sb/fsw/src/cfe_sb_msg_id_util.c
new file mode 100644
index 000000000..9924a7a04
--- /dev/null
+++ b/modules/sb/fsw/src/cfe_sb_msg_id_util.c
@@ -0,0 +1,38 @@
+/*
+** 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_sb_msg_id_util.c
+** Purpose: message ID utility functions
+*/
+
+/*
+** Include Files
+*/
+#include "cfe_sb_module_all.h"
+
+/*
+ * Function: CFE_SB_IsValidMsgId - See API and header file for details
+ */
+bool CFE_SB_IsValidMsgId(CFE_SB_MsgId_t MsgId)
+{
+ return (!CFE_SB_MsgId_Equal(MsgId, CFE_SB_INVALID_MSG_ID) &&
+ CFE_SB_MsgIdToValue(MsgId) <= CFE_PLATFORM_SB_HIGHEST_VALID_MSGID);
+} /* end CFE_SB_IsValidMsgId */
diff --git a/modules/sb/fsw/src/cfe_sb_priv.c b/modules/sb/fsw/src/cfe_sb_priv.c
new file mode 100644
index 000000000..a7c929a20
--- /dev/null
+++ b/modules/sb/fsw/src/cfe_sb_priv.c
@@ -0,0 +1,562 @@
+/*
+** 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_sb_priv.c
+**
+** Purpose:
+** This header file contains prototypes for private functions and type
+** definitions for cFE internal use.
+**
+** Author: R.McGraw/SSI
+**
+** Notes:
+
+** The following 4 terms have been or are used in the cFS architecture and implementation
+**
+** StreamId - First 16 bits of CCSDS Space Packet Protocol (SPP) 133.0-B.1c2 Blue Book
+** packet primary header. It contains the 3 bit Version Number, 1 bit Packet Type ID,
+** 1 bit Secondary Header flag, and 11 bit Application Process ID
+** It was used in earlier cFS implementaions and is defined here for historical reference
+** It is NOT exposed to user applications.
+**
+** MsgId - Unique numeric message identifier within a mission namespace. It is used by cFS
+** applications to the identify messages for publishing and subscribing
+** It is used by the SB API and encoded in a mission defended way in the header of
+** all cFS messages.
+** It is exposed to all cFS applications
+**
+** ApId - CCSDS Application Process Id field in the primary header.
+** It has default bit mask of 0x07FF and is part of the cFS message Id
+** It should not be confused with the cFE Executive Services (ES) term appId which
+** identifies the software application/component
+** It is NOT exposed to user applications.
+**
+** MsgIdkey - This is a unique numeric key within a mission namespace that is used with
+** cFS software bus internal structures.
+** It is algorithmically created in a mission defined way from the MsgId to support
+** efficient lookup and mapping implementations
+** It is NOT exposed to user applications.
+**
+** Some functions have EXTERNAL SYNC REQUIREMENTS
+**
+** SB functions marked with "Unsync" in their name are designated
+** as functions which are _not_ safe to be called concurrently by multiple
+** threads, and also do _not_ implement any locking or protection. These
+** functions expect the caller to perform all thread synchronization before
+** calling it.
+**
+** The synchronization requirement is across all functions; i.e. it is not safe
+** to call B_Unsync() while A_Unsync() is executing or vice-versa. The external
+** lock must wait until A_Unsync() finishes before calling B_Unsync().
+**
+** The expectation is that the required level of synchronization can be achieved
+** using the SB shared data lock.
+**
+******************************************************************************/
+
+/*
+** Include Files
+*/
+
+#include "cfe_sb_module_all.h"
+
+#include
+
+/******************************************************************************
+** Function: CFE_SB_CleanUpApp()
+**
+** Purpose:
+**
+** Arguments:
+**
+** Return:
+** None
+*/
+int32 CFE_SB_CleanUpApp(CFE_ES_AppId_t AppId)
+{
+ uint32 i;
+ uint32 DelCount;
+ CFE_SB_PipeD_t *PipeDscPtr;
+ CFE_SB_PipeId_t DelList[CFE_PLATFORM_SB_MAX_PIPES];
+
+ PipeDscPtr = CFE_SB_Global.PipeTbl;
+ DelCount = 0;
+
+ CFE_SB_LockSharedData(__func__, __LINE__);
+
+ /* loop through the pipe table looking for pipes owned by AppId */
+ for (i = 0; i < CFE_PLATFORM_SB_MAX_PIPES; ++i)
+ {
+ if (CFE_SB_PipeDescIsUsed(PipeDscPtr) && CFE_RESOURCEID_TEST_EQUAL(PipeDscPtr->AppId, AppId))
+ {
+ DelList[DelCount] = CFE_SB_PipeDescGetID(PipeDscPtr);
+ ++DelCount;
+ }
+ ++PipeDscPtr;
+ }
+
+ CFE_SB_UnlockSharedData(__func__, __LINE__);
+
+ for (i = 0; i < DelCount; ++i)
+ {
+ CFE_SB_DeletePipeWithAppId(DelList[i], AppId);
+ }
+
+ /* Release any zero copy buffers */
+ CFE_SB_ZeroCopyReleaseAppId(AppId);
+
+ return CFE_SUCCESS;
+
+} /* end CFE_SB_CleanUpApp */
+
+/******************************************************************************
+** Function: CFE_SB_LockSharedData()
+**
+** Purpose:
+** SB internal function to handle a semaphore take failure for the Shared
+** Data Mutex
+**
+** Arguments:
+** FuncName - the function name containing the code that generated the error.
+** LineNumber - the line number in the file of the code that generated the error.
+**
+** Return:
+** None
+*/
+void CFE_SB_LockSharedData(const char *FuncName, int32 LineNumber)
+{
+
+ int32 Status;
+ CFE_ES_AppId_t AppId;
+
+ Status = OS_MutSemTake(CFE_SB_Global.SharedDataMutexId);
+ if (Status != OS_SUCCESS)
+ {
+
+ CFE_ES_GetAppID(&AppId);
+
+ CFE_ES_WriteToSysLog("SB SharedData Mutex Take Err Stat=0x%x,App=%lu,Func=%s,Line=%d\n", (unsigned int)Status,
+ CFE_RESOURCEID_TO_ULONG(AppId), FuncName, (int)LineNumber);
+
+ } /* end if */
+
+ return;
+
+} /* end CFE_SB_LockSharedData */
+
+/******************************************************************************
+** Function: CFE_SB_UnlockSharedData()
+**
+** Purpose:
+** SB internal function to handle a semaphore give failure for the Shared
+** Data Mutex
+**
+** Arguments:
+** FuncName - the function name containing the code that generated the error.
+** LineNumber - the line number in the file of the code that generated the error.
+**
+** Return:
+** None
+*/
+void CFE_SB_UnlockSharedData(const char *FuncName, int32 LineNumber)
+{
+
+ int32 Status;
+ CFE_ES_AppId_t AppId;
+
+ Status = OS_MutSemGive(CFE_SB_Global.SharedDataMutexId);
+ if (Status != OS_SUCCESS)
+ {
+
+ CFE_ES_GetAppID(&AppId);
+
+ CFE_ES_WriteToSysLog("SB SharedData Mutex Give Err Stat=0x%x,App=%lu,Func=%s,Line=%d\n", (unsigned int)Status,
+ CFE_RESOURCEID_TO_ULONG(AppId), FuncName, (int)LineNumber);
+
+ } /* end if */
+
+ return;
+
+} /* end CFE_SB_UnlockSharedData */
+
+/******************************************************************************
+ * 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)
+{
+ CFE_SB_DestinationD_t *destptr;
+
+ destptr = CFE_SBR_GetDestListHeadPtr(RouteId);
+
+ /* Check all destinations */
+ while (destptr != NULL)
+ {
+ if (CFE_RESOURCEID_TEST_EQUAL(destptr->PipeId, PipeId))
+ {
+ break;
+ }
+ destptr = destptr->Next;
+ }
+
+ return destptr;
+}
+
+/******************************************************************************
+** Function: CFE_SB_ValidateMsgId()
+**
+** Purpose:
+** SB internal function to validate a given MsgId.
+**
+** Arguments:
+**
+** Return:
+** None
+*/
+int32 CFE_SB_ValidateMsgId(CFE_SB_MsgId_t MsgId)
+{
+
+ if (!CFE_SB_IsValidMsgId(MsgId))
+ {
+ return CFE_SB_FAILED;
+ }
+ else
+ {
+ return CFE_SUCCESS;
+ } /* end if */
+
+} /* end CFE_SB_ValidateMsgId */
+
+/*********************************************************************/
+/*
+ * CFE_SB_LocatePipeDescByID
+ *
+ * For complete API information, see prototype in header
+ */
+CFE_SB_PipeD_t *CFE_SB_LocatePipeDescByID(CFE_SB_PipeId_t PipeId)
+{
+ CFE_SB_PipeD_t *PipeDscPtr;
+ uint32 Idx;
+
+ if (CFE_SB_PipeId_ToIndex(PipeId, &Idx) == CFE_SUCCESS)
+ {
+ PipeDscPtr = &CFE_SB_Global.PipeTbl[Idx];
+ }
+ else
+ {
+ PipeDscPtr = NULL;
+ }
+
+ return PipeDscPtr;
+}
+
+/*********************************************************************/
+/*
+ * CFE_SB_CheckPipeDescSlotUsed
+ *
+ * Checks if a table slot is used or not (helper for allocating IDs)
+ */
+bool CFE_SB_CheckPipeDescSlotUsed(CFE_ResourceId_t CheckId)
+{
+ CFE_SB_PipeD_t *PipeDscPtr;
+ /*
+ * Note - The pointer here should never be NULL because the ID should always be
+ * within the expected range, but if it ever is NULL, this should return true
+ * such that the caller will _not_ attempt to use the record.
+ */
+ PipeDscPtr = CFE_SB_LocatePipeDescByID(CFE_SB_PIPEID_C(CheckId));
+ return (PipeDscPtr == NULL || CFE_SB_PipeDescIsUsed(PipeDscPtr));
+}
+
+/******************************************************************************
+** Function: CFE_SB_GetAppTskName()
+**
+** Purpose:
+** This function returns a pointer to the app.tsk name string
+**
+** Arguments:
+** TaskId - the task id of the app.task name desired
+** FullName - string buffer to store name
+**
+** Return:
+** Pointer to App.Tsk Name
+**
+** Note: With taskId, Parent App name and Child Task name can be queried from ES
+**
+*/
+char *CFE_SB_GetAppTskName(CFE_ES_TaskId_t TaskId, char *FullName)
+{
+
+ CFE_ES_TaskInfo_t TaskInfo;
+ CFE_ES_TaskInfo_t *ptr = &TaskInfo;
+ char AppName[OS_MAX_API_NAME];
+ char TskName[OS_MAX_API_NAME];
+
+ if (CFE_ES_GetTaskInfo(ptr, TaskId) != CFE_SUCCESS)
+ {
+
+ /* unlikely, but possible if TaskId is bogus */
+ strncpy(FullName, "Unknown", OS_MAX_API_NAME - 1);
+ FullName[OS_MAX_API_NAME - 1] = '\0';
+ }
+ else if (strncmp((char *)ptr->AppName, (char *)ptr->TaskName, sizeof(ptr->AppName)) == 0)
+ {
+
+ /* if app name and task name are the same */
+ strncpy(FullName, (char *)ptr->AppName, OS_MAX_API_NAME - 1);
+ FullName[OS_MAX_API_NAME - 1] = '\0';
+ }
+ else
+ {
+
+ /* AppName and TskName buffers and strncpy are needed to limit string sizes */
+ strncpy(AppName, (char *)ptr->AppName, sizeof(AppName) - 1);
+ AppName[sizeof(AppName) - 1] = '\0';
+ strncpy(TskName, (char *)ptr->TaskName, sizeof(TskName) - 1);
+ TskName[sizeof(TskName) - 1] = '\0';
+
+ sprintf(FullName, "%s.%s", AppName, TskName);
+
+ } /* end if */
+
+ return FullName;
+
+} /* end CFE_SB_GetAppTskName */
+
+/******************************************************************************
+** Function: CFE_SB_RequestToSendEvent()
+**
+** Purpose:
+** This function will test the given bit for the given task. If the bit is set
+** this function will return CFE_SB_DENIED. If bit is not set, this function set
+** the bit and return CFE_SB_GRANTED. This will prevent recursive events from
+** occurring.
+**
+** Arguments:
+**
+** Return:
+** If the bit is set this function will return CFE_SB_DENIED.
+** If bit is not set, this function set the bit and return CFE_SB_GRANTED.
+*/
+uint32 CFE_SB_RequestToSendEvent(CFE_ES_TaskId_t TaskId, uint32 Bit)
+{
+
+ uint32 Indx;
+
+ if (CFE_ES_TaskID_ToIndex(TaskId, &Indx) != CFE_SUCCESS)
+ {
+ return CFE_SB_DENIED;
+ }
+
+ /* if bit is set... */
+ if (CFE_TST(CFE_SB_Global.StopRecurseFlags[Indx], Bit))
+ {
+
+ return CFE_SB_DENIED;
+ }
+ else
+ {
+
+ CFE_SET(CFE_SB_Global.StopRecurseFlags[Indx], Bit);
+ return CFE_SB_GRANTED;
+
+ } /* end if */
+
+} /* end CFE_SB_RequestToSendEvent */
+
+/******************************************************************************
+** Function: CFE_SB_FinishSendEvent()
+**
+** Purpose:
+** This function will clear the given bit for the given task. Called after
+** a successful CFE_SB_RequestToSendEvent()
+**
+** Arguments:
+**
+** Return:
+** If the bit is set this function will return CFE_SB_DENIED.
+** If bit is not set, this function set the bit and return CFE_SB_GRANTED.
+*/
+void CFE_SB_FinishSendEvent(CFE_ES_TaskId_t TaskId, uint32 Bit)
+{
+
+ uint32 Indx;
+
+ if (CFE_ES_TaskID_ToIndex(TaskId, &Indx) != CFE_SUCCESS)
+ {
+ return;
+ }
+
+ /* clear the bit so the task may send this event again */
+ CFE_CLR(CFE_SB_Global.StopRecurseFlags[Indx], Bit);
+} /* end CFE_SB_RequestToSendEvent */
+
+/******************************************************************************
+ * 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;
+
+ listheadptr = CFE_SBR_GetDestListHeadPtr(RouteId);
+
+ /* if first node in list */
+ if (listheadptr == NULL)
+ {
+ /* initialize the new node */
+ NewNode->Next = NULL;
+ NewNode->Prev = NULL;
+ }
+ else
+ {
+ WBS = listheadptr;
+
+ /* initialize the new node */
+ NewNode->Next = WBS;
+ NewNode->Prev = NULL;
+
+ /* insert the new node */
+ WBS->Prev = NewNode;
+ }
+
+ /* Update Head */
+ CFE_SBR_SetDestListHeadPtr(RouteId, NewNode);
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+ * 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_Global.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 ((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)
+ {
+
+ /* Last in the list, remove previous pointer */
+ PrevNode = NodeToRemove->Prev;
+ PrevNode->Next = NULL;
+ }
+ else
+ {
+ /* Middle of list, remove */
+ PrevNode = NodeToRemove->Prev;
+ NextNode = NodeToRemove->Next;
+ PrevNode->Next = NextNode;
+ NextNode->Prev = PrevNode;
+ }
+
+ /* initialize the node before returning it to the heap */
+ NodeToRemove->Next = NULL;
+ NodeToRemove->Prev = NULL;
+}
+
+/******************************************************************************
+** Name: CFE_SB_ZeroCopyReleaseAppId
+**
+** Purpose: API used for releasing all pointers to a buffers (for zero copy mode
+** only) for a specific Application. This function is used for cleaning
+** up when an application crashes.
+**
+** Assumptions, External Events, and Notes:
+** None
+**
+** Date Written:
+** 07/23/2009
+**
+** Input Arguments:
+** AppId
+**
+** Output Arguments:
+** None
+**
+** Return Values:
+** Status
+**
+******************************************************************************/
+int32 CFE_SB_ZeroCopyReleaseAppId(CFE_ES_AppId_t AppId)
+{
+ CFE_SB_BufferLink_t *NextLink;
+ CFE_SB_BufferD_t * DscPtr;
+
+ /*
+ * First go through the "ZeroCopy" tracking list and find all nodes
+ * with a matching AppID. This needs to be done while locked to
+ * prevent other tasks from changing the list at the same time.
+ */
+ if (CFE_RESOURCEID_TEST_DEFINED(AppId))
+ {
+ CFE_SB_LockSharedData(__func__, __LINE__);
+
+ /* Get start of list */
+ NextLink = CFE_SB_TrackingListGetNext(&CFE_SB_Global.ZeroCopyList);
+ while (!CFE_SB_TrackingListIsEnd(&CFE_SB_Global.ZeroCopyList, NextLink))
+ {
+ /* Get buffer descriptor pointer */
+ /* NOTE: casting via void* here rather than CFE_SB_BufferD_t* avoids a false
+ * alignment warning on platforms with strict alignment requirements */
+ DscPtr = (void *)NextLink;
+
+ /* Read the next link now in case this node gets moved */
+ NextLink = CFE_SB_TrackingListGetNext(NextLink);
+
+ /* Check if it is a zero-copy buffer owned by this app */
+ if (CFE_RESOURCEID_TEST_EQUAL(DscPtr->AppId, AppId))
+ {
+ /* If so, decrement the use count as the app has now gone away */
+ CFE_SB_DecrBufUseCnt(DscPtr);
+ }
+ }
+
+ CFE_SB_UnlockSharedData(__func__, __LINE__);
+ }
+
+ return CFE_SUCCESS;
+
+} /* end CFE_SB_ZeroCopyReleaseAppId */
+
+/*****************************************************************************/
diff --git a/modules/sb/fsw/src/cfe_sb_priv.h b/modules/sb/fsw/src/cfe_sb_priv.h
new file mode 100644
index 000000000..a607853fb
--- /dev/null
+++ b/modules/sb/fsw/src/cfe_sb_priv.h
@@ -0,0 +1,635 @@
+/*
+** 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
+ *
+ * Purpose:
+ * This header file contains prototypes for private functions and type
+ * definitions for SB internal use.
+ *
+ * Author: R.McGraw/SSI
+ *
+ */
+
+#ifndef CFE_SB_PRIV_H
+#define CFE_SB_PRIV_H
+
+/*
+** Includes
+*/
+#include "cfe_platform_cfg.h"
+#include "common_types.h"
+#include "cfe_sb_api_typedefs.h"
+#include "cfe_es_api_typedefs.h"
+#include "cfe_sbr_api_typedefs.h"
+#include "cfe_msg_api_typedefs.h"
+#include "cfe_fs_api_typedefs.h"
+#include "cfe_resourceid_api_typedefs.h"
+#include "cfe_sb_destination_typedef.h"
+#include "cfe_sb_msg.h"
+
+/*
+** Macro Definitions
+*/
+
+#define CFE_SB_UNUSED_QUEUE OS_OBJECT_ID_UNDEFINED
+#define CFE_SB_NO_DESTINATION 0xFF
+#define CFE_SB_FAILED 1
+#define SB_DONT_CARE 0
+
+#define CFE_SB_NO_DUPLICATE 0
+#define CFE_SB_DUPLICATE 1
+
+#define CFE_SB_INACTIVE 0
+#define CFE_SB_ACTIVE 1
+
+#define CFE_SB_MSG_GLOBAL 0
+#define CFE_SB_MSG_LOCAL 1
+
+#define CFE_SB_SEND_ZEROCOPY 0
+#define CFE_SB_SEND_ONECOPY 1
+
+#define CFE_SB_NOT_IN_USE 0
+#define CFE_SB_IN_USE 1
+
+#define CFE_SB_DISABLE 0
+#define CFE_SB_ENABLE 1
+
+#define CFE_SB_DENIED 0
+#define CFE_SB_GRANTED 1
+
+#define CFE_SB_DO_NOT_INCREMENT 0
+#define CFE_SB_INCREMENT_TLM 1
+
+#define CFE_SB_MAIN_LOOP_ERR_DLY 1000
+#define CFE_SB_CMD_PIPE_DEPTH 32
+#define CFE_SB_CMD_PIPE_NAME "SB_CMD_PIPE"
+#define CFE_SB_MAX_CFG_FILE_EVENTS_TO_FILTER 8
+
+#define CFE_SB_PIPE_OVERFLOW (-1)
+#define CFE_SB_PIPE_WR_ERR (-2)
+#define CFE_SB_USECNT_ERR (-3)
+#define CFE_SB_FILE_IO_ERR (-5)
+
+/* bit map for stopping recursive event problem */
+#define CFE_SB_SEND_NO_SUBS_EID_BIT 0
+#define CFE_SB_GET_BUF_ERR_EID_BIT 1
+#define CFE_SB_MSGID_LIM_ERR_EID_BIT 2
+#define CFE_SB_Q_FULL_ERR_EID_BIT 3
+#define CFE_SB_Q_WR_ERR_EID_BIT 4
+
+/*
+** Type Definitions
+*/
+
+/**
+ * \brief Basic linked list structure allowing all buffer descriptors to be tracked.
+ */
+typedef struct CFE_SB_BufferLink
+{
+ struct CFE_SB_BufferLink *Next;
+ struct CFE_SB_BufferLink *Prev;
+
+} CFE_SB_BufferLink_t;
+
+/******************************************************************************
+** Typedef: CFE_SB_BufferD_t
+**
+** Purpose:
+** This structure defines a BUFFER DESCRIPTOR used to specify the MsgId
+** and address of each packet buffer.
+**
+** Note: Changing the size of this structure may require the memory pool
+** block sizes to change.
+*/
+typedef struct CFE_SB_BufferD
+{
+ CFE_SB_BufferLink_t Link; /**< Links for inclusion in the tracking lists */
+
+ /**
+ * Actual MsgId of the content, cached here to avoid repeat
+ * calls into CFE_MSG API during traversal/delivery of the message.
+ *
+ * MsgId is set for buffers which contain actual data in transit. AppId is unset
+ * while in transit, as it may be sent to multiple apps.
+ *
+ * During zero copy buffer initial allocation, the MsgId is not known at this time
+ * and should be set to the invalid msg ID.
+ */
+ CFE_SB_MsgId_t MsgId;
+
+ /**
+ * Current owner of the buffer, if owned by a single app.
+ *
+ * This is used to track "zero copy" buffer allocations - this will be set to
+ * the AppID that initally allocated it, before it is used to transmit a message.
+ *
+ * When the message is in transit, it may be queued to multiple applictions,
+ * so this is unset.
+ */
+ CFE_ES_AppId_t AppId;
+
+ size_t AllocatedSize; /**< Total size of this descriptor (including descriptor itself) */
+ size_t ContentSize; /**< Actual size of message content currently stored in the buffer */
+ CFE_MSG_Type_t ContentType; /**< Type of message content currently stored in the buffer */
+
+ bool AutoSequence; /**< If message should get its sequence number assigned from the route */
+
+ uint16 UseCount; /**< Number of active references to this buffer in the system */
+
+ CFE_SB_Buffer_t Content; /* Variably sized content field, Keep last */
+
+} CFE_SB_BufferD_t;
+
+/******************************************************************************
+** Typedef: CFE_SB_PipeD_t
+**
+** Purpose:
+** This structure defines a pipe descriptor used to specify the
+** characteristics and status of a pipe.
+*/
+
+typedef struct
+{
+ CFE_SB_PipeId_t PipeId;
+ uint8 Opts;
+ uint8 Spare;
+ CFE_ES_AppId_t AppId;
+ osal_id_t SysQueueId;
+ uint16 SendErrors;
+ uint16 MaxQueueDepth;
+ uint16 CurrentQueueDepth;
+ uint16 PeakQueueDepth;
+ CFE_SB_BufferD_t *LastBuffer;
+} CFE_SB_PipeD_t;
+
+/******************************************************************************
+** Typedef: CFE_SB_BufParams_t
+**
+** Purpose:
+** This structure defines the variables related to the SB routing buffers.
+*/
+typedef struct
+{
+
+ CFE_ES_MemHandle_t PoolHdl;
+ CFE_ES_STATIC_POOL_TYPE(CFE_PLATFORM_SB_BUF_MEMORY_BYTES) Partition;
+
+} CFE_SB_MemParams_t;
+
+/*******************************************************************************/
+/**
+** \brief SB route info temporary structure
+**
+** This tracks the number of desinations along with destination data for 1 route.
+** Each route may contain zero or more desinations (variable length).
+*/
+typedef struct
+{
+ uint32 NumDestinations;
+ CFE_SB_RoutingFileEntry_t DestEntries[CFE_PLATFORM_SB_MAX_DEST_PER_PKT]; /**< Actual data written to file */
+} CFE_SB_BackgroundRouteInfoBuffer_t;
+
+/**
+ * \brief Temporary holding buffer for records being written to a file.
+ *
+ * This is shared/reused between all file types (msg map, route info, pipe info).
+ */
+typedef union
+{
+ CFE_SB_BackgroundRouteInfoBuffer_t RouteInfo;
+ CFE_SB_PipeInfoEntry_t PipeInfo;
+ CFE_SB_MsgMapFileEntry_t MsgMapInfo;
+} CFE_SB_BackgroundFileBuffer_t;
+
+/**
+ * \brief SB Background file write state information
+ *
+ * Must be stored in persistent memory (e.g. global).
+ */
+typedef struct
+{
+ CFE_FS_FileWriteMetaData_t FileWrite; /**< FS state data - must be first */
+ CFE_SB_BackgroundFileBuffer_t Buffer; /**< Temporary holding area for file record */
+} CFE_SB_BackgroundFileStateInfo_t;
+
+/******************************************************************************
+** Typedef: CFE_SB_Global_t
+**
+** Purpose:
+** This structure contains the SB global variables.
+*/
+typedef struct
+{
+ osal_id_t SharedDataMutexId;
+ uint32 SubscriptionReporting;
+ CFE_ES_AppId_t AppId;
+ uint32 StopRecurseFlags[OS_MAX_TASKS];
+ 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_MemParams_t Mem;
+ CFE_SB_AllSubscriptionsTlm_t PrevSubMsg;
+ CFE_EVS_BinFilter_t EventFilters[CFE_SB_MAX_CFG_FILE_EVENTS_TO_FILTER];
+ CFE_SB_Qos_t Default_Qos;
+ CFE_ResourceId_t LastPipeId;
+
+ CFE_SB_BackgroundFileStateInfo_t BackgroundFile;
+
+ /* A list of buffers currently in-transit, owned by SB */
+ CFE_SB_BufferLink_t InTransitList;
+
+ /* A list of buffers currently issued to apps for zero-copy */
+ CFE_SB_BufferLink_t ZeroCopyList;
+
+} CFE_SB_Global_t;
+
+/******************************************************************************
+** Typedef: CFE_SB_SendErrEventBuf_t
+**
+** Purpose:
+** This structure is used to store event information during a send.
+*/
+typedef struct
+{
+ uint32 EventId;
+ int32 ErrStat;
+ CFE_SB_PipeId_t PipeId;
+} CFE_SB_SendErrEventBuf_t;
+
+/******************************************************************************
+** Typedef: CFE_SB_EventBuf_t
+**
+** Purpose:
+** This structure is used to store event information during a send.
+*/
+typedef struct
+{
+ uint32 EvtsToSnd;
+ CFE_SB_SendErrEventBuf_t EvtBuf[CFE_PLATFORM_SB_MAX_DEST_PER_PKT];
+} CFE_SB_EventBuf_t;
+
+/*
+** Software Bus Function Prototypes
+*/
+
+int32 CFE_SB_AppInit(void);
+int32 CFE_SB_InitBuffers(void);
+void CFE_SB_InitPipeTbl(void);
+void CFE_SB_InitIdxStack(void);
+void CFE_SB_ResetCounts(void);
+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);
+int32 CFE_SB_WriteQueue(CFE_SB_PipeD_t *pd, uint32 TskId, const CFE_SB_BufferD_t *bd, CFE_SB_MsgId_t MsgId);
+void CFE_SB_ProcessCmdPipePkt(CFE_SB_Buffer_t *SBBufPtr);
+void CFE_SB_ResetCounters(void);
+void CFE_SB_SetMsgSeqCnt(CFE_MSG_Message_t *MsgPtr, uint32 Count);
+char *CFE_SB_GetAppTskName(CFE_ES_TaskId_t TaskId, char *FullName);
+int32 CFE_SB_DeletePipeWithAppId(CFE_SB_PipeId_t PipeId, CFE_ES_AppId_t AppId);
+int32 CFE_SB_DeletePipeFull(CFE_SB_PipeId_t PipeId, CFE_ES_AppId_t AppId);
+int32 CFE_SB_SubscribeFull(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId, CFE_SB_Qos_t Quality, uint16 MsgLim,
+ uint8 Scope);
+
+int32 CFE_SB_UnsubscribeWithAppId(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId, CFE_ES_AppId_t AppId);
+
+int32 CFE_SB_UnsubscribeFull(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId, uint8 Scope, CFE_ES_AppId_t AppId);
+int32 CFE_SB_TransmitMsgValidate(CFE_MSG_Message_t *MsgPtr, CFE_SB_MsgId_t *MsgIdPtr, CFE_MSG_Size_t *SizePtr,
+ CFE_SBR_RouteId_t *RouteIdPtr);
+int32 CFE_SB_ZeroCopyReleaseAppId(CFE_ES_AppId_t AppId);
+void CFE_SB_IncrBufUseCnt(CFE_SB_BufferD_t *bd);
+void CFE_SB_DecrBufUseCnt(CFE_SB_BufferD_t *bd);
+int32 CFE_SB_ValidateMsgId(CFE_SB_MsgId_t MsgId);
+int32 CFE_SB_ValidatePipeId(CFE_SB_PipeId_t PipeId);
+void CFE_SB_IncrCmdCtr(int32 status);
+void CFE_SB_SetSubscriptionReporting(uint32 state);
+int32 CFE_SB_SendSubscriptionReport(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId, CFE_SB_Qos_t Quality);
+uint32 CFE_SB_RequestToSendEvent(CFE_ES_TaskId_t TaskId, uint32 Bit);
+void CFE_SB_FinishSendEvent(CFE_ES_TaskId_t TaskId, uint32 Bit);
+CFE_SB_DestinationD_t *CFE_SB_GetDestinationBlk(void);
+int32 CFE_SB_PutDestinationBlk(CFE_SB_DestinationD_t *Dest);
+
+/**
+ * \brief For SB buffer tracking, get first/next position in a list
+ */
+static inline CFE_SB_BufferLink_t *CFE_SB_TrackingListGetNext(CFE_SB_BufferLink_t *Node)
+{
+ return Node->Next;
+}
+
+/**
+ * \brief For SB buffer tracking, checks if this current position represents the end of the list
+ */
+static inline bool CFE_SB_TrackingListIsEnd(CFE_SB_BufferLink_t *List, CFE_SB_BufferLink_t *Node)
+{
+ /* Normally list nodes should never have NULL, buf if they do, do not follow it */
+ return (Node == NULL || Node == List);
+}
+
+/**
+ * \brief For SB buffer tracking, reset link state to default
+ *
+ * This turns the node into a singleton/lone object (not in a list)
+ * or resets the head link to be empty.
+ */
+void CFE_SB_TrackingListReset(CFE_SB_BufferLink_t *Link);
+
+/**
+ * \brief For SB buffer tracking, removes a node from a tracking list
+ *
+ * Extracts a single node from whatever list it is in. After this the
+ * node becomes a singleton owned by the caller. It may be put into
+ * another list or freed.
+ */
+void CFE_SB_TrackingListRemove(CFE_SB_BufferLink_t *Node);
+
+/**
+ * \brief For SB buffer tracking, adds a node to a tracking list
+ *
+ * Extracts a single node from the list its in. After this the
+ * node becomes a singleton owned by the caller. It must put it
+ * in another list or free it.
+ */
+void CFE_SB_TrackingListAdd(CFE_SB_BufferLink_t *List, CFE_SB_BufferLink_t *Node);
+
+/**
+ * \brief Allocates a new buffer descriptor from the SB memory pool.
+ *
+ * \param[in] MaxMsgSize Maximum message content size that the buffer must be capable of holding
+ * \returns Pointer to buffer descriptor, or NULL on failure.
+ */
+CFE_SB_BufferD_t *CFE_SB_GetBufferFromPool(size_t MaxMsgSize);
+
+/**
+ * \brief Returns a buffer to SB memory pool
+ *
+ * \param[in] Pointer to descriptor to return
+ */
+void CFE_SB_ReturnBufferToPool(CFE_SB_BufferD_t *bd);
+
+/**
+ * \brief Broadcast a SB buffer descriptor to all destinations in route
+ *
+ * Internal routine that implements the logic of transmitting a message buffer
+ * to all destinations subscribed in the SB route.
+ *
+ * As this function will broadcast the message to any number of destinations (0-many),
+ * and some may be successful and some may fail, the status cannot be expressed
+ * in any single error code, so this does not return any status.
+ *
+ * Instead, this routine handles all potential outcomes on its own, and does
+ * not expect the caller to handle any delivery issues. Also note that the general
+ * design pattern of the software bus is a "send and forget" model where the sender does
+ * not know (or care) what entities are subscribed to the data being generated.
+ *
+ * - For any undeliverable destination (limit, OSAL error, etc), a proper event is generated.
+ * - For any successful queueing, the buffer use count is incremented
+ *
+ * The caller is expected to hold a reference (use count) of the buffer prior to invoking
+ * this routine, representing itself, which is then consumed by this routine.
+ *
+ * \note _This call will "consume" the buffer by decrementing the buffer use count_ after
+ * broadcasting the message to all subscribed pipes.
+ *
+ * The caller should not access the buffer again after calling this function, as it may
+ * be deallocated at any time. If the caller wishes to continue accessing the buffer,
+ * it should explicitly increment the use count before calling this, which will prevent
+ * deallocation.
+ *
+ * \param[in] BufDscPtr Pointer to the buffer descriptor to broadcast
+ * \param[in] RouteId Route to send to
+ */
+void CFE_SB_BroadcastBufferToRoute(CFE_SB_BufferD_t *BufDscPtr, CFE_SBR_RouteId_t RouteId);
+
+/**
+ * \brief Perform basic sanity check on the Zero Copy handle
+ *
+ * \param[in] BufPtr pointer to the content buffer
+ * \param[out] BufDscPtr Will be set to actual buffer descriptor
+ *
+ * \returns CFE_SUCCESS if validation passed, or error code.
+ */
+int32 CFE_SB_ZeroCopyBufferValidate(CFE_SB_Buffer_t *BufPtr, CFE_SB_BufferD_t **BufDscPtr);
+
+/**
+ * \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);
+
+/*****************************************************************************/
+/**
+** \brief Get the size of a message header.
+**
+** \par Description
+** This routine is a best guess of the message header size based off type
+** information and the local message implementation.
+** If a different header implementation was used to generate the message
+** the returned size may not be correct. Critical functionality should
+** use the real message structure or otherwise confirm header implementation
+** matches expectations prior to using this API.
+**
+** \par Assumptions, External Events, and Notes:
+** - Utilize CFE_MSG_CommandHeader_t and CFE_MSG_TelemetryHeader_t for
+** defining message structures.
+**
+** \param[in] *MsgPtr The message ID to calculate header size for. The size of the message
+** header may depend on the MsgId in some implementations. For example,
+** if SB messages are implemented as CCSDS packets, the size of the header
+** is different for command vs. telemetry packets.
+**
+** \returns Estimated number of bytes in the message header for the given message
+**/
+size_t CFE_SB_MsgHdrSize(const CFE_MSG_Message_t *MsgPtr);
+
+/*
+ * Software Bus Message Handler Function prototypes
+ */
+int32 CFE_SB_NoopCmd(const CFE_SB_NoopCmd_t *data);
+int32 CFE_SB_ResetCountersCmd(const CFE_SB_ResetCountersCmd_t *data);
+int32 CFE_SB_EnableSubReportingCmd(const CFE_SB_EnableSubReportingCmd_t *data);
+int32 CFE_SB_DisableSubReportingCmd(const CFE_SB_DisableSubReportingCmd_t *data);
+int32 CFE_SB_SendHKTlmCmd(const CFE_MSG_CommandHeader_t *data);
+int32 CFE_SB_EnableRouteCmd(const CFE_SB_EnableRouteCmd_t *data);
+int32 CFE_SB_DisableRouteCmd(const CFE_SB_DisableRouteCmd_t *data);
+int32 CFE_SB_SendStatsCmd(const CFE_SB_SendSbStatsCmd_t *data);
+int32 CFE_SB_WriteRoutingInfoCmd(const CFE_SB_WriteRoutingInfoCmd_t *data);
+int32 CFE_SB_WritePipeInfoCmd(const CFE_SB_WritePipeInfoCmd_t *data);
+int32 CFE_SB_WriteMapInfoCmd(const CFE_SB_WriteMapInfoCmd_t *data);
+int32 CFE_SB_SendPrevSubsCmd(const CFE_SB_SendPrevSubsCmd_t *data);
+
+/**
+ * @brief Locate the Pipe table entry correlating with a given Pipe ID.
+ *
+ * This only returns a pointer to the table entry and does _not_
+ * otherwise check/validate the entry.
+ *
+ * @param[in] PipeId the Pipe ID to locate
+ * @return pointer to Pipe Table entry for the given Pipe ID
+ */
+extern CFE_SB_PipeD_t *CFE_SB_LocatePipeDescByID(CFE_SB_PipeId_t PipeId);
+
+/**
+ * @brief Check if an Pipe descriptor is in use or free/empty
+ *
+ * This routine checks if the Pipe table entry is in use or if it is free
+ *
+ * As this dereferences fields within the descriptor, global data must be
+ * locked prior to invoking this function.
+ *
+ * @param[in] PipeDscPtr pointer to Pipe table entry
+ * @returns true if the entry is in use/configured, or false if it is free/empty
+ */
+static inline bool CFE_SB_PipeDescIsUsed(const CFE_SB_PipeD_t *PipeDscPtr)
+{
+ return CFE_RESOURCEID_TEST_DEFINED(PipeDscPtr->PipeId);
+}
+
+/**
+ * @brief Get the ID value from an Pipe table entry
+ *
+ * This routine converts the table entry back to an abstract ID.
+ *
+ * @param[in] PipeDscPtr pointer to Pipe table entry
+ * @returns PipeID of entry
+ */
+static inline CFE_SB_PipeId_t CFE_SB_PipeDescGetID(const CFE_SB_PipeD_t *PipeDscPtr)
+{
+ return PipeDscPtr->PipeId;
+}
+
+/**
+ * @brief Marks an Pipe table entry as used (not free)
+ *
+ * This sets the internal field(s) within this entry, and marks
+ * it as being associated with the given Pipe ID.
+ *
+ * As this dereferences fields within the descriptor, global data must be
+ * locked prior to invoking this function.
+ *
+ * @param[in] PipeDscPtr pointer to Pipe table entry
+ * @param[in] PipeID the Pipe ID of this entry
+ */
+static inline void CFE_SB_PipeDescSetUsed(CFE_SB_PipeD_t *PipeDscPtr, CFE_ResourceId_t PendingID)
+{
+ PipeDscPtr->PipeId = CFE_SB_PIPEID_C(PendingID);
+}
+
+/**
+ * @brief Set an Pipe descriptor table entry free (not used)
+ *
+ * This clears the internal field(s) within this entry, and allows the
+ * memory to be re-used in the future.
+ *
+ * As this dereferences fields within the descriptor, global data must be
+ * locked prior to invoking this function.
+ *
+ * @param[in] PipeDscPtr pointer to Pipe table entry
+ */
+static inline void CFE_SB_PipeDescSetFree(CFE_SB_PipeD_t *PipeDscPtr)
+{
+ PipeDscPtr->PipeId = CFE_SB_INVALID_PIPE;
+}
+
+/**
+ * @brief Check if an Pipe descriptor is a match for the given PipeID
+ *
+ * This routine confirms that the previously-located descriptor is valid
+ * and matches the expected Pipe ID.
+ *
+ * As this dereferences fields within the descriptor, global data must be
+ * locked prior to invoking this function.
+ *
+ * @param[in] PipeDscPtr pointer to Pipe table entry
+ * @param[in] PipeID expected Pipe ID
+ * @returns true if the entry matches the given Pipe ID
+ */
+static inline bool CFE_SB_PipeDescIsMatch(const CFE_SB_PipeD_t *PipeDscPtr, CFE_SB_PipeId_t PipeID)
+{
+ return (PipeDscPtr != NULL && CFE_RESOURCEID_TEST_EQUAL(PipeDscPtr->PipeId, PipeID));
+}
+
+/* Availability check functions used in conjunction with CFE_ResourceId_FindNext() */
+bool CFE_SB_CheckPipeDescSlotUsed(CFE_ResourceId_t CheckId);
+
+/*
+ * Helper functions for background file write requests (callbacks)
+ */
+void CFE_SB_CollectMsgMapInfo(CFE_SBR_RouteId_t RouteId, void *ArgPtr);
+bool CFE_SB_WriteMsgMapInfoDataGetter(void *Meta, uint32 RecordNum, void **Buffer, size_t *BufSize);
+void CFE_SB_CollectRouteInfo(CFE_SBR_RouteId_t RouteId, void *ArgPtr);
+bool CFE_SB_WriteRouteInfoDataGetter(void *Meta, uint32 RecordNum, void **Buffer, size_t *BufSize);
+bool CFE_SB_WritePipeInfoDataGetter(void *Meta, uint32 RecordNum, void **Buffer, size_t *BufSize);
+void CFE_SB_BackgroundFileEventHandler(void *Meta, CFE_FS_FileWriteEvent_t Event, int32 Status, uint32 RecordNum,
+ size_t BlockSize, size_t Position);
+
+/*
+ * External variables private to the software bus module
+ */
+
+extern CFE_SB_Global_t CFE_SB_Global;
+
+#endif /* CFE_SB_PRIV_H */
diff --git a/modules/sb/fsw/src/cfe_sb_task.c b/modules/sb/fsw/src/cfe_sb_task.c
new file mode 100644
index 000000000..d34f186d8
--- /dev/null
+++ b/modules/sb/fsw/src/cfe_sb_task.c
@@ -0,0 +1,1446 @@
+/*
+** 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_sb_task.c
+**
+** Purpose:
+** This file contains the source code for the SB task.
+**
+** Author: R.McGraw/SSI
+**
+******************************************************************************/
+
+/* Include Files */
+
+#include "cfe_sb_module_all.h"
+#include "cfe_version.h"
+#include "cfe_es_msg.h" /* needed for local use of CFE_ES_RestartCmd_t */
+
+#include
+
+/* Task Globals */
+CFE_SB_Global_t CFE_SB_Global;
+
+/* 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()
+**
+** Purpose:
+** Main loop for Software Bus task, used to process SB commands.
+**
+** Arguments:
+** none
+**
+** Return:
+** none
+*/
+void CFE_SB_TaskMain(void)
+{
+ int32 Status;
+ CFE_SB_Buffer_t *SBBufPtr;
+
+ CFE_ES_PerfLogEntry(CFE_MISSION_SB_MAIN_PERF_ID);
+
+ Status = CFE_SB_AppInit();
+
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("SB:Application Init Failed,RC=0x%08X\n", (unsigned int)Status);
+ CFE_ES_PerfLogExit(CFE_MISSION_SB_MAIN_PERF_ID);
+ /* Note: CFE_ES_ExitApp will not return */
+ CFE_ES_ExitApp(CFE_ES_RunStatus_CORE_APP_INIT_ERROR);
+ } /* end if */
+
+ /*
+ * Wait for other apps to start.
+ * It is important that the core apps are present before this starts receiving
+ * messages from the command pipe, as some of those handlers might depend on
+ * the other core apps.
+ */
+ CFE_ES_WaitForSystemState(CFE_ES_SystemState_CORE_READY, CFE_PLATFORM_CORE_MAX_STARTUP_MSEC);
+
+ /* Main loop */
+ while (Status == CFE_SUCCESS)
+ {
+ /* Increment the Main task Execution Counter */
+ CFE_ES_IncrementTaskCounter();
+
+ CFE_ES_PerfLogExit(CFE_MISSION_SB_MAIN_PERF_ID);
+
+ /* Pend on receipt of packet */
+ Status = CFE_SB_ReceiveBuffer(&SBBufPtr, CFE_SB_Global.CmdPipe, CFE_SB_PEND_FOREVER);
+
+ CFE_ES_PerfLogEntry(CFE_MISSION_SB_MAIN_PERF_ID);
+
+ if (Status == CFE_SUCCESS)
+ {
+ /* Process cmd pipe msg */
+ CFE_SB_ProcessCmdPipePkt(SBBufPtr);
+ }
+ else
+ {
+ CFE_ES_WriteToSysLog("SB:Error reading cmd pipe,RC=0x%08X\n", (unsigned int)Status);
+ } /* end if */
+
+ } /* end while */
+
+ /* while loop exits only if CFE_SB_ReceiveBuffer returns error */
+ CFE_ES_ExitApp(CFE_ES_RunStatus_CORE_APP_RUNTIME_ERROR);
+
+} /* end CFE_SB_TaskMain */
+
+/******************************************************************************
+** Function: CFE_SB_AppInit()
+**
+** Purpose:
+** Initialization routine for SB application. This routine is executed when
+** the SB application is started by Executive Services.
+**
+** Arguments:
+** none
+**
+** Return:
+** CFE_SUCCESS if no errors, otherwise this function returns the error code
+** that was received from the function that detected the error.
+**
+*/
+int32 CFE_SB_AppInit(void)
+{
+
+ uint32 CfgFileEventsToFilter = 0;
+ CFE_ES_MemPoolBuf_t TmpPtr;
+ int32 Status;
+
+ /* Get the assigned Application ID for the SB Task */
+ CFE_ES_GetAppID(&CFE_SB_Global.AppId);
+
+ /* Process the platform cfg file events to be filtered */
+ if (CFE_PLATFORM_SB_FILTERED_EVENT1 != 0)
+ {
+ CFE_SB_Global.EventFilters[CfgFileEventsToFilter].EventID = CFE_PLATFORM_SB_FILTERED_EVENT1;
+ CFE_SB_Global.EventFilters[CfgFileEventsToFilter].Mask = CFE_PLATFORM_SB_FILTER_MASK1;
+ CfgFileEventsToFilter++;
+ } /* end if */
+
+ if (CFE_PLATFORM_SB_FILTERED_EVENT2 != 0)
+ {
+ CFE_SB_Global.EventFilters[CfgFileEventsToFilter].EventID = CFE_PLATFORM_SB_FILTERED_EVENT2;
+ CFE_SB_Global.EventFilters[CfgFileEventsToFilter].Mask = CFE_PLATFORM_SB_FILTER_MASK2;
+ CfgFileEventsToFilter++;
+ } /* end if */
+
+ if (CFE_PLATFORM_SB_FILTERED_EVENT3 != 0)
+ {
+ CFE_SB_Global.EventFilters[CfgFileEventsToFilter].EventID = CFE_PLATFORM_SB_FILTERED_EVENT3;
+ CFE_SB_Global.EventFilters[CfgFileEventsToFilter].Mask = CFE_PLATFORM_SB_FILTER_MASK3;
+ CfgFileEventsToFilter++;
+ } /* end if */
+
+ if (CFE_PLATFORM_SB_FILTERED_EVENT4 != 0)
+ {
+ CFE_SB_Global.EventFilters[CfgFileEventsToFilter].EventID = CFE_PLATFORM_SB_FILTERED_EVENT4;
+ CFE_SB_Global.EventFilters[CfgFileEventsToFilter].Mask = CFE_PLATFORM_SB_FILTER_MASK4;
+ CfgFileEventsToFilter++;
+ } /* end if */
+
+ if (CFE_PLATFORM_SB_FILTERED_EVENT5 != 0)
+ {
+ CFE_SB_Global.EventFilters[CfgFileEventsToFilter].EventID = CFE_PLATFORM_SB_FILTERED_EVENT5;
+ CFE_SB_Global.EventFilters[CfgFileEventsToFilter].Mask = CFE_PLATFORM_SB_FILTER_MASK5;
+ CfgFileEventsToFilter++;
+ } /* end if */
+
+ if (CFE_PLATFORM_SB_FILTERED_EVENT6 != 0)
+ {
+ CFE_SB_Global.EventFilters[CfgFileEventsToFilter].EventID = CFE_PLATFORM_SB_FILTERED_EVENT6;
+ CFE_SB_Global.EventFilters[CfgFileEventsToFilter].Mask = CFE_PLATFORM_SB_FILTER_MASK6;
+ CfgFileEventsToFilter++;
+ } /* end if */
+
+ if (CFE_PLATFORM_SB_FILTERED_EVENT7 != 0)
+ {
+ CFE_SB_Global.EventFilters[CfgFileEventsToFilter].EventID = CFE_PLATFORM_SB_FILTERED_EVENT7;
+ CFE_SB_Global.EventFilters[CfgFileEventsToFilter].Mask = CFE_PLATFORM_SB_FILTER_MASK7;
+ CfgFileEventsToFilter++;
+ } /* end if */
+
+ if (CFE_PLATFORM_SB_FILTERED_EVENT8 != 0)
+ {
+ CFE_SB_Global.EventFilters[CfgFileEventsToFilter].EventID = CFE_PLATFORM_SB_FILTERED_EVENT8;
+ CFE_SB_Global.EventFilters[CfgFileEventsToFilter].Mask = CFE_PLATFORM_SB_FILTER_MASK8;
+ CfgFileEventsToFilter++;
+ } /* end if */
+
+ /* Be sure the number of events to register for filtering
+ ** does not exceed CFE_PLATFORM_EVS_MAX_EVENT_FILTERS */
+ if (CFE_PLATFORM_EVS_MAX_EVENT_FILTERS < CfgFileEventsToFilter)
+ {
+ CfgFileEventsToFilter = CFE_PLATFORM_EVS_MAX_EVENT_FILTERS;
+ } /* end if */
+
+ /* Register event filter table... */
+ Status = CFE_EVS_Register(CFE_SB_Global.EventFilters, CfgFileEventsToFilter, CFE_EVS_EventFilter_BINARY);
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("SB:Call to CFE_EVS_Register Failed:RC=0x%08X\n", (unsigned int)Status);
+ return Status;
+ } /* end if */
+
+ CFE_ES_WriteToSysLog("SB:Registered %d events for filtering\n", (int)CfgFileEventsToFilter);
+
+ CFE_MSG_Init(&CFE_SB_Global.HKTlmMsg.Hdr.Msg, CFE_SB_ValueToMsgId(CFE_SB_HK_TLM_MID),
+ sizeof(CFE_SB_Global.HKTlmMsg));
+
+ CFE_MSG_Init(&CFE_SB_Global.PrevSubMsg.Hdr.Msg, CFE_SB_ValueToMsgId(CFE_SB_ALLSUBS_TLM_MID),
+ sizeof(CFE_SB_Global.PrevSubMsg));
+
+ /* Populate the fixed fields in the HK Tlm Msg */
+ CFE_SB_Global.HKTlmMsg.Payload.MemPoolHandle = CFE_SB_Global.Mem.PoolHdl;
+
+ /* Populate the fixed fields in the Stat Tlm Msg */
+ CFE_SB_Global.StatTlmMsg.Payload.MaxMsgIdsAllowed = CFE_PLATFORM_SB_MAX_MSG_IDS;
+ CFE_SB_Global.StatTlmMsg.Payload.MaxPipesAllowed = CFE_PLATFORM_SB_MAX_PIPES;
+ CFE_SB_Global.StatTlmMsg.Payload.MaxMemAllowed = CFE_PLATFORM_SB_BUF_MEMORY_BYTES;
+ CFE_SB_Global.StatTlmMsg.Payload.MaxPipeDepthAllowed = OS_QUEUE_MAX_DEPTH;
+ CFE_SB_Global.StatTlmMsg.Payload.MaxSubscriptionsAllowed =
+ ((CFE_PLATFORM_SB_MAX_MSG_IDS) * (CFE_PLATFORM_SB_MAX_DEST_PER_PKT));
+
+ Status = CFE_SB_CreatePipe(&CFE_SB_Global.CmdPipe, CFE_SB_CMD_PIPE_DEPTH, CFE_SB_CMD_PIPE_NAME);
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("SB:Call to CFE_SB_CreatePipe Failed:RC=0x%08X\n", (unsigned int)Status);
+ return Status;
+ } /* end if */
+
+ Status = CFE_SB_Subscribe(CFE_SB_ValueToMsgId(CFE_SB_CMD_MID), CFE_SB_Global.CmdPipe);
+
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("SB:Subscribe to Cmds Failed:RC=0x%08X\n", (unsigned int)Status);
+ return Status;
+ } /* end if */
+
+ Status = CFE_SB_Subscribe(CFE_SB_ValueToMsgId(CFE_SB_SEND_HK_MID), CFE_SB_Global.CmdPipe);
+
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("SB:Subscribe to HK Request Failed:RC=0x%08X\n", (unsigned int)Status);
+ return Status;
+ } /* end if */
+
+ Status = CFE_SB_Subscribe(CFE_SB_ValueToMsgId(CFE_SB_SUB_RPT_CTRL_MID), CFE_SB_Global.CmdPipe);
+
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("SB:Subscribe to Subscription Report Request Failed:RC=0x%08X\n", (unsigned int)Status);
+ return Status;
+ } /* end if */
+
+ /* Ensure a ground commanded reset does not get blocked if SB mem pool */
+ /* becomes fully configured (DCR6772) */
+ Status = CFE_ES_GetPoolBuf(&TmpPtr, CFE_SB_Global.Mem.PoolHdl, sizeof(CFE_ES_RestartCmd_t));
+
+ if (Status < 0)
+ {
+ CFE_ES_WriteToSysLog("SB:Init error, GetPool Failed:RC=0x%08X\n", (unsigned int)Status);
+ return Status;
+ } /* end if */
+
+ /* Return mem block used on previous call,the actual memory is not needed.*/
+ /* The SB mem pool is now configured with a block size for the reset cmd. */
+ Status = CFE_ES_PutPoolBuf(CFE_SB_Global.Mem.PoolHdl, TmpPtr);
+
+ if (Status < 0)
+ {
+ CFE_ES_WriteToSysLog("SB:Init error, PutPool Failed:RC=0x%08X\n", (unsigned int)Status);
+ return Status;
+ } /* end if */
+
+ Status = CFE_EVS_SendEvent(CFE_SB_INIT_EID, CFE_EVS_EventType_INFORMATION, "cFE SB Initialized");
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("SB:Error sending init event:RC=0x%08X\n", (unsigned int)Status);
+ return Status;
+ } /* end if */
+
+ return CFE_SUCCESS;
+
+} /* end CFE_SB_AppInit */
+
+/******************************************************************************
+** Function: CFE_SB_VerifyCmdLength()
+**
+** Purpose:
+** Function to verify the length of incoming SB command packets
+**
+** Arguments:
+** Message pointer and expected length
+**
+** Return:
+** true if length is acceptable
+*/
+bool CFE_SB_VerifyCmdLength(CFE_MSG_Message_t *MsgPtr, size_t ExpectedLength)
+{
+ bool result = true;
+ CFE_MSG_Size_t ActualLength = 0;
+ CFE_MSG_FcnCode_t FcnCode = 0;
+ CFE_SB_MsgId_t MsgId = CFE_SB_INVALID_MSG_ID;
+
+ CFE_MSG_GetSize(MsgPtr, &ActualLength);
+
+ /*
+ ** Verify the command packet length
+ */
+ if (ExpectedLength != ActualLength)
+ {
+ CFE_MSG_GetMsgId(MsgPtr, &MsgId);
+ CFE_MSG_GetFcnCode(MsgPtr, &FcnCode);
+
+ CFE_EVS_SendEvent(CFE_SB_LEN_ERR_EID, CFE_EVS_EventType_ERROR,
+ "Invalid msg length: ID = 0x%X, CC = %u, Len = %u, Expected = %u",
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId), (unsigned int)FcnCode, (unsigned int)ActualLength,
+ (unsigned int)ExpectedLength);
+ result = false;
+ ++CFE_SB_Global.HKTlmMsg.Payload.CommandErrorCounter;
+ }
+
+ return (result);
+
+} /* End of CFE_SB_VerifyCmdLength() */
+
+/******************************************************************************
+** Function: CFE_SB_ProcessCmdPipePkt()
+**
+** Purpose:
+** Function to control actions when an SB command is received.
+**
+** Arguments:
+** Software bus buffer pointer
+**
+** Return:
+** none
+*/
+void CFE_SB_ProcessCmdPipePkt(CFE_SB_Buffer_t *SBBufPtr)
+{
+ CFE_SB_MsgId_t MessageID = CFE_SB_INVALID_MSG_ID;
+ CFE_MSG_FcnCode_t FcnCode = 0;
+
+ CFE_MSG_GetMsgId(&SBBufPtr->Msg, &MessageID);
+
+ switch (CFE_SB_MsgIdToValue(MessageID))
+ {
+
+ case CFE_SB_SEND_HK_MID:
+ /* Note: Command counter not incremented for this command */
+ CFE_SB_SendHKTlmCmd((CFE_MSG_CommandHeader_t *)SBBufPtr);
+ break;
+
+ case CFE_SB_SUB_RPT_CTRL_MID:
+ /* Note: Command counter not incremented for this command */
+ CFE_MSG_GetFcnCode(&SBBufPtr->Msg, &FcnCode);
+ switch (FcnCode)
+ {
+ case CFE_SB_SEND_PREV_SUBS_CC:
+ if (CFE_SB_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_SB_SendPrevSubsCmd_t)))
+ {
+ CFE_SB_SendPrevSubsCmd((CFE_SB_SendPrevSubsCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_SB_ENABLE_SUB_REPORTING_CC:
+ if (CFE_SB_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_SB_EnableSubReportingCmd_t)))
+ {
+ CFE_SB_EnableSubReportingCmd((CFE_SB_EnableSubReportingCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_SB_DISABLE_SUB_REPORTING_CC:
+ if (CFE_SB_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_SB_DisableSubReportingCmd_t)))
+ {
+ CFE_SB_DisableSubReportingCmd((CFE_SB_DisableSubReportingCmd_t *)SBBufPtr);
+ }
+ break;
+
+ default:
+ CFE_EVS_SendEvent(CFE_SB_BAD_CMD_CODE_EID, CFE_EVS_EventType_ERROR,
+ "Invalid Cmd, Unexpected Command Code %u", (unsigned int)FcnCode);
+ CFE_SB_Global.HKTlmMsg.Payload.CommandErrorCounter++;
+ break;
+ } /* end switch on cmd code */
+ break;
+
+ case CFE_SB_CMD_MID:
+ CFE_MSG_GetFcnCode(&SBBufPtr->Msg, &FcnCode);
+ switch (FcnCode)
+ {
+ case CFE_SB_NOOP_CC:
+ if (CFE_SB_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_SB_NoopCmd_t)))
+ {
+ CFE_SB_NoopCmd((CFE_SB_NoopCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_SB_RESET_COUNTERS_CC:
+ if (CFE_SB_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_SB_ResetCountersCmd_t)))
+ {
+ /* Note: Command counter not incremented for this command */
+ CFE_SB_ResetCountersCmd((CFE_SB_ResetCountersCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_SB_SEND_SB_STATS_CC:
+ if (CFE_SB_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_SB_SendSbStatsCmd_t)))
+ {
+ CFE_SB_SendStatsCmd((CFE_SB_SendSbStatsCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_SB_WRITE_ROUTING_INFO_CC:
+ if (CFE_SB_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_SB_WriteRoutingInfoCmd_t)))
+ {
+ CFE_SB_WriteRoutingInfoCmd((CFE_SB_WriteRoutingInfoCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_SB_ENABLE_ROUTE_CC:
+ if (CFE_SB_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_SB_EnableRouteCmd_t)))
+ {
+ CFE_SB_EnableRouteCmd((CFE_SB_EnableRouteCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_SB_DISABLE_ROUTE_CC:
+ if (CFE_SB_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_SB_DisableRouteCmd_t)))
+ {
+ CFE_SB_DisableRouteCmd((CFE_SB_DisableRouteCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_SB_WRITE_PIPE_INFO_CC:
+ if (CFE_SB_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_SB_WritePipeInfoCmd_t)))
+ {
+ CFE_SB_WritePipeInfoCmd((CFE_SB_WritePipeInfoCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_SB_WRITE_MAP_INFO_CC:
+ if (CFE_SB_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_SB_WriteMapInfoCmd_t)))
+ {
+ CFE_SB_WriteMapInfoCmd((CFE_SB_WriteMapInfoCmd_t *)SBBufPtr);
+ }
+ break;
+
+ default:
+ CFE_EVS_SendEvent(CFE_SB_BAD_CMD_CODE_EID, CFE_EVS_EventType_ERROR,
+ "Invalid Cmd, Unexpected Command Code %u", FcnCode);
+ CFE_SB_Global.HKTlmMsg.Payload.CommandErrorCounter++;
+ break;
+ } /* end switch on cmd code */
+ break;
+
+ default:
+ CFE_EVS_SendEvent(CFE_SB_BAD_MSGID_EID, CFE_EVS_EventType_ERROR, "Invalid Cmd, Unexpected Msg Id: 0x%x",
+ (unsigned int)CFE_SB_MsgIdToValue(MessageID));
+ CFE_SB_Global.HKTlmMsg.Payload.CommandErrorCounter++;
+ break;
+
+ } /* end switch on MsgId */
+
+} /* end CFE_SB_ProcessCmdPipePkt */
+
+/******************************************************************************
+** Function: CFE_SB_NoopCmd()
+**
+** Purpose:
+** Handler function the SB command
+**
+*/
+int32 CFE_SB_NoopCmd(const CFE_SB_NoopCmd_t *data)
+{
+ CFE_EVS_SendEvent(CFE_SB_CMD0_RCVD_EID, CFE_EVS_EventType_INFORMATION, "No-op Cmd Rcvd. %s", CFE_VERSION_STRING);
+ CFE_SB_Global.HKTlmMsg.Payload.CommandCounter++;
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+** Function: CFE_SB_ResetCountersCmd()
+**
+** Purpose:
+** Handler function the SB command
+**
+*/
+int32 CFE_SB_ResetCountersCmd(const CFE_SB_ResetCountersCmd_t *data)
+{
+ CFE_EVS_SendEvent(CFE_SB_CMD1_RCVD_EID, CFE_EVS_EventType_DEBUG, "Reset Counters Cmd Rcvd");
+
+ CFE_SB_ResetCounters();
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+** Function: CFE_SB_EnableSubReportingCmd()
+**
+** Purpose:
+** Handler function the SB command
+**
+*/
+int32 CFE_SB_EnableSubReportingCmd(const CFE_SB_EnableSubReportingCmd_t *data)
+{
+ CFE_SB_SetSubscriptionReporting(CFE_SB_ENABLE);
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+** Function: CFE_SB_DisableSubReportingCmd()
+**
+** Purpose:
+** Handler function the SB command
+**
+*/
+int32 CFE_SB_DisableSubReportingCmd(const CFE_SB_DisableSubReportingCmd_t *data)
+{
+ CFE_SB_SetSubscriptionReporting(CFE_SB_DISABLE);
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+** Function: CFE_SB_SendHKTlmCmd()
+**
+** Purpose:
+** Function to send the SB housekeeping packet.
+**
+** Arguments:
+** none
+**
+** Notes:
+** Command counter not incremented for this command
+**
+** Return:
+** none
+*/
+int32 CFE_SB_SendHKTlmCmd(const CFE_MSG_CommandHeader_t *data)
+{
+ CFE_SB_LockSharedData(__FILE__, __LINE__);
+
+ CFE_SB_Global.HKTlmMsg.Payload.MemInUse = CFE_SB_Global.StatTlmMsg.Payload.MemInUse;
+ CFE_SB_Global.HKTlmMsg.Payload.UnmarkedMem =
+ CFE_PLATFORM_SB_BUF_MEMORY_BYTES - CFE_SB_Global.StatTlmMsg.Payload.PeakMemInUse;
+
+ CFE_SB_UnlockSharedData(__FILE__, __LINE__);
+
+ CFE_SB_TimeStampMsg(&CFE_SB_Global.HKTlmMsg.Hdr.Msg);
+ CFE_SB_TransmitMsg(&CFE_SB_Global.HKTlmMsg.Hdr.Msg, true);
+
+ return CFE_SUCCESS;
+} /* end CFE_SB_SendHKTlmCmd */
+
+/******************************************************************************
+** Function: CFE_SB_ResetCounters()
+**
+** Purpose:
+** Function to reset the SB housekeeping counters.
+**
+** Arguments:
+** none
+**
+** Notes:
+** Command counter not incremented for this command
+**
+** Return:
+** none
+*/
+void CFE_SB_ResetCounters(void)
+{
+
+ CFE_SB_Global.HKTlmMsg.Payload.CommandCounter = 0;
+ CFE_SB_Global.HKTlmMsg.Payload.CommandErrorCounter = 0;
+ CFE_SB_Global.HKTlmMsg.Payload.NoSubscribersCounter = 0;
+ CFE_SB_Global.HKTlmMsg.Payload.DuplicateSubscriptionsCounter = 0;
+ CFE_SB_Global.HKTlmMsg.Payload.MsgSendErrorCounter = 0;
+ CFE_SB_Global.HKTlmMsg.Payload.MsgReceiveErrorCounter = 0;
+ CFE_SB_Global.HKTlmMsg.Payload.InternalErrorCounter = 0;
+ CFE_SB_Global.HKTlmMsg.Payload.CreatePipeErrorCounter = 0;
+ CFE_SB_Global.HKTlmMsg.Payload.SubscribeErrorCounter = 0;
+ CFE_SB_Global.HKTlmMsg.Payload.PipeOverflowErrorCounter = 0;
+ CFE_SB_Global.HKTlmMsg.Payload.MsgLimitErrorCounter = 0;
+
+} /* end CFE_SB_ResetCounters */
+
+/******************************************************************************
+** Function: CFE_SB_EnableRouteCmd()
+**
+** Purpose:
+** SB internal function to enable a specific route. A route is defined as a
+** MsgId/PipeId combination.
+**
+** Arguments:
+** MsgPtr : pointer to the message
+**
+** Return:
+** None
+*/
+int32 CFE_SB_EnableRouteCmd(const CFE_SB_EnableRouteCmd_t *data)
+{
+ CFE_SB_MsgId_t MsgId;
+ CFE_SB_PipeD_t * PipeDscPtr;
+ CFE_SB_DestinationD_t * DestPtr;
+ const CFE_SB_RouteCmd_Payload_t *CmdPtr;
+ uint16 PendingEventID;
+
+ PendingEventID = 0;
+ CmdPtr = &data->Payload;
+
+ MsgId = CmdPtr->MsgId;
+
+ CFE_SB_LockSharedData(__func__, __LINE__);
+
+ /* check cmd parameters */
+ PipeDscPtr = CFE_SB_LocatePipeDescByID(CmdPtr->Pipe);
+ if (!CFE_SB_IsValidMsgId(MsgId) || !CFE_SB_PipeDescIsMatch(PipeDscPtr, CmdPtr->Pipe))
+ {
+ PendingEventID = CFE_SB_ENBL_RTE3_EID;
+ CFE_SB_Global.HKTlmMsg.Payload.CommandErrorCounter++;
+ }
+ else
+ {
+ DestPtr = CFE_SB_GetDestPtr(CFE_SBR_GetRouteId(MsgId), CmdPtr->Pipe);
+ if (DestPtr == NULL)
+ {
+ PendingEventID = CFE_SB_ENBL_RTE1_EID;
+ CFE_SB_Global.HKTlmMsg.Payload.CommandErrorCounter++;
+ }
+ else
+ {
+ DestPtr->Active = CFE_SB_ACTIVE;
+ PendingEventID = CFE_SB_ENBL_RTE2_EID;
+ CFE_SB_Global.HKTlmMsg.Payload.CommandCounter++;
+ }
+
+ } /* end if */
+
+ CFE_SB_UnlockSharedData(__func__, __LINE__);
+
+ switch (PendingEventID)
+ {
+ case CFE_SB_ENBL_RTE1_EID:
+ CFE_EVS_SendEvent(CFE_SB_ENBL_RTE1_EID, CFE_EVS_EventType_ERROR,
+ "Enbl Route Cmd:Route does not exist.Msg 0x%x,Pipe %lu",
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId), CFE_RESOURCEID_TO_ULONG(CmdPtr->Pipe));
+ break;
+ case CFE_SB_ENBL_RTE3_EID:
+ CFE_EVS_SendEvent(CFE_SB_ENBL_RTE3_EID, CFE_EVS_EventType_ERROR,
+ "Enbl Route Cmd:Invalid Param.Msg 0x%x,Pipe %lu",
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId), CFE_RESOURCEID_TO_ULONG(CmdPtr->Pipe));
+ break;
+ case CFE_SB_ENBL_RTE2_EID:
+ CFE_EVS_SendEvent(CFE_SB_ENBL_RTE2_EID, CFE_EVS_EventType_DEBUG, "Enabling Route,Msg 0x%x,Pipe %lu",
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId), CFE_RESOURCEID_TO_ULONG(CmdPtr->Pipe));
+ break;
+ }
+
+ return CFE_SUCCESS;
+} /* end CFE_SB_EnableRouteCmd */
+
+/******************************************************************************
+** Function: CFE_SB_DisableRouteCmd()
+**
+** Purpose:
+** SB internal function to disable a specific route. A route is defined as a
+** MsgId/PipeId combination.
+**
+** Arguments:
+** MsgPtr : pointer to the message
+**
+** Return:
+** None
+*/
+int32 CFE_SB_DisableRouteCmd(const CFE_SB_DisableRouteCmd_t *data)
+{
+ CFE_SB_MsgId_t MsgId;
+ CFE_SB_PipeD_t * PipeDscPtr;
+ CFE_SB_DestinationD_t * DestPtr;
+ const CFE_SB_RouteCmd_Payload_t *CmdPtr;
+ uint16 PendingEventID;
+
+ PendingEventID = 0;
+ CmdPtr = &data->Payload;
+
+ MsgId = CmdPtr->MsgId;
+
+ CFE_SB_LockSharedData(__func__, __LINE__);
+
+ /* check cmd parameters */
+ PipeDscPtr = CFE_SB_LocatePipeDescByID(CmdPtr->Pipe);
+ if (!CFE_SB_IsValidMsgId(MsgId) || !CFE_SB_PipeDescIsMatch(PipeDscPtr, CmdPtr->Pipe))
+ {
+ PendingEventID = CFE_SB_DSBL_RTE3_EID;
+ CFE_SB_Global.HKTlmMsg.Payload.CommandErrorCounter++;
+ }
+ else
+ {
+ DestPtr = CFE_SB_GetDestPtr(CFE_SBR_GetRouteId(MsgId), CmdPtr->Pipe);
+ if (DestPtr == NULL)
+ {
+ PendingEventID = CFE_SB_DSBL_RTE1_EID;
+ CFE_SB_Global.HKTlmMsg.Payload.CommandErrorCounter++;
+ }
+ else
+ {
+ DestPtr->Active = CFE_SB_INACTIVE;
+ PendingEventID = CFE_SB_DSBL_RTE2_EID;
+ CFE_SB_Global.HKTlmMsg.Payload.CommandCounter++;
+ }
+
+ } /* end if */
+
+ CFE_SB_UnlockSharedData(__func__, __LINE__);
+
+ switch (PendingEventID)
+ {
+ case CFE_SB_DSBL_RTE1_EID:
+ CFE_EVS_SendEvent(CFE_SB_DSBL_RTE1_EID, CFE_EVS_EventType_ERROR,
+ "Disable Route Cmd:Route does not exist,Msg 0x%x,Pipe %lu",
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId), CFE_RESOURCEID_TO_ULONG(CmdPtr->Pipe));
+ break;
+ case CFE_SB_DSBL_RTE3_EID:
+ CFE_EVS_SendEvent(CFE_SB_DSBL_RTE3_EID, CFE_EVS_EventType_ERROR,
+ "Disable Route Cmd:Invalid Param.Msg 0x%x,Pipe %lu",
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId), CFE_RESOURCEID_TO_ULONG(CmdPtr->Pipe));
+ break;
+ case CFE_SB_DSBL_RTE2_EID:
+ CFE_EVS_SendEvent(CFE_SB_DSBL_RTE2_EID, CFE_EVS_EventType_DEBUG, "Route Disabled,Msg 0x%x,Pipe %lu",
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId), CFE_RESOURCEID_TO_ULONG(CmdPtr->Pipe));
+ break;
+ }
+
+ return CFE_SUCCESS;
+} /* end CFE_SB_DisableRouteCmd */
+
+/******************************************************************************
+** Function: CFE_SB_SendStatsCmd()
+**
+** Purpose:
+** SB internal function to send a Software Bus statistics packet
+**
+** Arguments:
+** None
+**
+** Return:
+** None
+*/
+int32 CFE_SB_SendStatsCmd(const CFE_SB_SendSbStatsCmd_t *data)
+{
+ uint32 PipeDscCount;
+ uint32 PipeStatCount;
+ CFE_SB_PipeD_t * PipeDscPtr;
+ CFE_SB_PipeDepthStats_t *PipeStatPtr;
+
+ CFE_SB_LockSharedData(__FILE__, __LINE__);
+
+ /* Collect data on pipes */
+ PipeDscCount = CFE_PLATFORM_SB_MAX_PIPES;
+ PipeStatCount = CFE_MISSION_SB_MAX_PIPES;
+ PipeDscPtr = CFE_SB_Global.PipeTbl;
+ PipeStatPtr = CFE_SB_Global.StatTlmMsg.Payload.PipeDepthStats;
+
+ while (PipeDscCount > 0 && PipeStatCount > 0)
+ {
+ if (CFE_SB_PipeDescIsUsed(PipeDscPtr))
+ {
+ PipeStatPtr->PipeId = PipeDscPtr->PipeId;
+
+ /* Copy depth info */
+ PipeStatPtr->CurrentQueueDepth = PipeDscPtr->CurrentQueueDepth;
+ PipeStatPtr->PeakQueueDepth = PipeDscPtr->PeakQueueDepth;
+ PipeStatPtr->MaxQueueDepth = PipeDscPtr->MaxQueueDepth;
+
+ ++PipeStatPtr;
+ --PipeStatCount;
+ }
+
+ --PipeDscCount;
+ ++PipeDscPtr;
+ }
+
+ CFE_SB_UnlockSharedData(__FILE__, __LINE__);
+
+ while (PipeStatCount > 0)
+ {
+ memset(PipeStatPtr, 0, sizeof(*PipeStatPtr));
+
+ ++PipeStatPtr;
+ --PipeStatCount;
+ }
+
+ CFE_SB_TimeStampMsg(&CFE_SB_Global.StatTlmMsg.Hdr.Msg);
+ CFE_SB_TransmitMsg(&CFE_SB_Global.StatTlmMsg.Hdr.Msg, true);
+
+ CFE_EVS_SendEvent(CFE_SB_SND_STATS_EID, CFE_EVS_EventType_DEBUG, "Software Bus Statistics packet sent");
+
+ CFE_SB_Global.HKTlmMsg.Payload.CommandCounter++;
+
+ return CFE_SUCCESS;
+} /* CFE_SB_SendStatsCmd */
+
+/******************************************************************************
+ * Local callback helper for writing routing info to a file
+ */
+void CFE_SB_CollectRouteInfo(CFE_SBR_RouteId_t RouteId, void *ArgPtr)
+{
+ CFE_SB_DestinationD_t * DestPtr;
+ CFE_SB_PipeD_t * PipeDscPtr;
+ CFE_SB_MsgId_t RouteMsgId;
+ CFE_SB_BackgroundRouteInfoBuffer_t *RouteBufferPtr;
+ CFE_SB_RoutingFileEntry_t * FileEntryPtr;
+ CFE_ES_AppId_t DestAppId[CFE_PLATFORM_SB_MAX_DEST_PER_PKT];
+ uint32 i;
+
+ /* Cast arguments for local use */
+ RouteBufferPtr = (CFE_SB_BackgroundRouteInfoBuffer_t *)ArgPtr;
+
+ /* Extract data from runtime info, write into the temporary buffer */
+ /* Data must be locked to snapshot the route info */
+ CFE_SB_LockSharedData(__FILE__, __LINE__);
+
+ RouteMsgId = CFE_SBR_GetMsgId(RouteId);
+ RouteBufferPtr->NumDestinations = 0;
+
+ /* If this is a valid route, get the destinations */
+ if (CFE_SB_IsValidMsgId(RouteMsgId))
+ {
+ DestPtr = CFE_SBR_GetDestListHeadPtr(RouteId);
+
+ /* copy relevant data from the destination list into the temp buffer */
+ while (DestPtr != NULL && RouteBufferPtr->NumDestinations < CFE_PLATFORM_SB_MAX_DEST_PER_PKT)
+ {
+ PipeDscPtr = CFE_SB_LocatePipeDescByID(DestPtr->PipeId);
+
+ /* If invalid id, continue on to next entry */
+ if (CFE_SB_PipeDescIsMatch(PipeDscPtr, DestPtr->PipeId))
+ {
+ FileEntryPtr = &RouteBufferPtr->DestEntries[RouteBufferPtr->NumDestinations];
+
+ /* clear all fields in the temp buffer before re-use */
+ memset(FileEntryPtr, 0, sizeof(*FileEntryPtr));
+
+ FileEntryPtr->PipeId = DestPtr->PipeId;
+ FileEntryPtr->State = DestPtr->Active;
+ FileEntryPtr->MsgCnt = DestPtr->DestCnt;
+
+ /* Stash the Pipe Owner AppId - App Name is looked up later (comes from ES) */
+ DestAppId[RouteBufferPtr->NumDestinations] = PipeDscPtr->AppId;
+
+ ++RouteBufferPtr->NumDestinations;
+ }
+
+ DestPtr = DestPtr->Next;
+ }
+ }
+
+ CFE_SB_UnlockSharedData(__FILE__, __LINE__);
+
+ /* Go through the temp buffer and fill in the remaining info for each dest */
+ FileEntryPtr = RouteBufferPtr->DestEntries;
+ for (i = 0; i < RouteBufferPtr->NumDestinations; ++i)
+ {
+ /* All dest entries refer to the same MsgId (based on the route) */
+ FileEntryPtr->MsgId = RouteMsgId;
+
+ /*
+ * NOTE: as long as CFE_ES_GetAppName() is given a nonzero-length
+ * output buffer, it guarantees null termination of the output, even
+ * if the AppID is invalid - in which case it returns an empty string.
+ */
+ CFE_ES_GetAppName(FileEntryPtr->AppName, DestAppId[i], sizeof(FileEntryPtr->AppName));
+ CFE_SB_GetPipeName(FileEntryPtr->PipeName, sizeof(FileEntryPtr->PipeName), FileEntryPtr->PipeId);
+
+ ++FileEntryPtr;
+ }
+}
+
+/******************************************************************************
+** Function: CFE_SB_SendSubscriptionReport()
+**
+** Purpose:
+** SB internal function to generate the "ONESUB_TLM" message after a subscription.
+** No-op when subscription reporting is disabled.
+**
+** Arguments:
+** Payload of notification message - MsgId, PipeId, QOS
+**
+** Return:
+** CFE_SUCCESS or error code
+*/
+int32 CFE_SB_SendSubscriptionReport(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId, CFE_SB_Qos_t Quality)
+{
+ CFE_SB_SingleSubscriptionTlm_t SubRptMsg;
+ int32 Status;
+
+ Status = CFE_SUCCESS;
+
+ if (CFE_SB_Global.SubscriptionReporting == CFE_SB_ENABLE)
+ {
+ CFE_MSG_Init(&SubRptMsg.Hdr.Msg, CFE_SB_ValueToMsgId(CFE_SB_ONESUB_TLM_MID), sizeof(SubRptMsg));
+
+ SubRptMsg.Payload.MsgId = MsgId;
+ SubRptMsg.Payload.Pipe = PipeId;
+ SubRptMsg.Payload.Qos = Quality;
+ SubRptMsg.Payload.SubType = CFE_SB_SUBSCRIPTION;
+
+ Status = CFE_SB_TransmitMsg(&SubRptMsg.Hdr.Msg, true);
+ CFE_EVS_SendEventWithAppID(CFE_SB_SUBSCRIPTION_RPT_EID, CFE_EVS_EventType_DEBUG, CFE_SB_Global.AppId,
+ "Sending Subscription Report Msg=0x%x,Pipe=%lu,Stat=0x%x",
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId), CFE_RESOURCEID_TO_ULONG(PipeId),
+ (unsigned int)Status);
+ }
+
+ return Status;
+}
+
+bool CFE_SB_WriteRouteInfoDataGetter(void *Meta, uint32 RecordNum, void **Buffer, size_t *BufSize)
+{
+ CFE_SB_BackgroundFileStateInfo_t *BgFilePtr;
+ CFE_SBR_Throttle_t Throttle;
+
+ /* Cast arguments for local use */
+ BgFilePtr = (CFE_SB_BackgroundFileStateInfo_t *)Meta;
+
+ Throttle.StartIndex = RecordNum;
+ Throttle.MaxLoop = 1;
+ Throttle.NextIndex = 0;
+
+ /* Reset NumDestinations to 0, just in case the CFE_SBR_ForEachRouteId() is a no-op */
+ BgFilePtr->Buffer.RouteInfo.NumDestinations = 0;
+
+ /* Collect info on the next route (limited to one per cycle via throttle) */
+ CFE_SBR_ForEachRouteId(CFE_SB_CollectRouteInfo, &BgFilePtr->Buffer.RouteInfo, &Throttle);
+
+ /* Pass the output of CFE_SB_CollectRouteInfo() back to be written */
+ *Buffer = &BgFilePtr->Buffer.RouteInfo.DestEntries;
+ *BufSize = sizeof(CFE_SB_RoutingFileEntry_t) * BgFilePtr->Buffer.RouteInfo.NumDestinations;
+
+ /* Check for EOF (last entry) - NextIndex is nonzero if more records left, zero at the end of the route table */
+ return (Throttle.NextIndex == 0);
+}
+
+void CFE_SB_BackgroundFileEventHandler(void *Meta, CFE_FS_FileWriteEvent_t Event, int32 Status, uint32 RecordNum,
+ size_t BlockSize, size_t Position)
+{
+ CFE_SB_BackgroundFileStateInfo_t *BgFilePtr;
+
+ BgFilePtr = (CFE_SB_BackgroundFileStateInfo_t *)Meta;
+
+ /*
+ * Note that this runs in the context of ES background task (file writer background job)
+ * It does NOT run in the context of the CFE_TBL app task.
+ *
+ * Events should use CFE_EVS_SendEventWithAppID() rather than CFE_EVS_SendEvent()
+ * to get proper association with TBL task.
+ */
+ switch (Event)
+ {
+ case CFE_FS_FileWriteEvent_COMPLETE:
+ CFE_EVS_SendEventWithAppID(CFE_SB_SND_RTG_EID, CFE_EVS_EventType_DEBUG, CFE_SB_Global.AppId,
+ "%s written:Size=%d,Entries=%d", BgFilePtr->FileWrite.FileName, (int)Position,
+ (int)RecordNum);
+ break;
+
+ case CFE_FS_FileWriteEvent_HEADER_WRITE_ERROR:
+ case CFE_FS_FileWriteEvent_RECORD_WRITE_ERROR:
+ CFE_EVS_SendEventWithAppID(CFE_SB_FILEWRITE_ERR_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "File write,byte cnt err,file %s,request=%d,actual=%d",
+ BgFilePtr->FileWrite.FileName, (int)BlockSize, (int)Status);
+ break;
+
+ case CFE_FS_FileWriteEvent_CREATE_ERROR:
+ CFE_EVS_SendEventWithAppID(CFE_SB_SND_RTG_ERR1_EID, CFE_EVS_EventType_ERROR, CFE_SB_Global.AppId,
+ "Error creating file %s, stat=0x%x", BgFilePtr->FileWrite.FileName, (int)Status);
+ break;
+
+ default:
+ /* unhandled event - ignore */
+ break;
+ }
+}
+
+/******************************************************************************
+ * \brief SB internal function to handle processing of 'Write Routing Info' Cmd
+ *
+ * \param[in] data Pointer to command structure
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ */
+int32 CFE_SB_WriteRoutingInfoCmd(const CFE_SB_WriteRoutingInfoCmd_t *data)
+{
+ const CFE_SB_WriteFileInfoCmd_Payload_t *CmdPtr;
+ CFE_SB_BackgroundFileStateInfo_t * StatePtr;
+ int32 Status;
+
+ StatePtr = &CFE_SB_Global.BackgroundFile;
+ CmdPtr = &data->Payload;
+
+ /* If a routing info dump was already pending, do not overwrite the current request */
+ if (!CFE_FS_BackgroundFileDumpIsPending(&StatePtr->FileWrite))
+ {
+ /* Reset the entire state object (just for good measure, ensure no stale data) */
+ memset(StatePtr, 0, sizeof(*StatePtr));
+
+ /*
+ * Fill out the remainder of meta data.
+ * This data is currently the same for every request
+ */
+ StatePtr->FileWrite.FileSubType = CFE_FS_SubType_SB_ROUTEDATA;
+ snprintf(StatePtr->FileWrite.Description, sizeof(StatePtr->FileWrite.Description), "SB Routing Information");
+
+ StatePtr->FileWrite.GetData = CFE_SB_WriteRouteInfoDataGetter;
+ StatePtr->FileWrite.OnEvent = CFE_SB_BackgroundFileEventHandler;
+
+ /*
+ ** Copy the filename into local buffer with default name/path/extension if not specified
+ */
+ Status = CFE_FS_ParseInputFileNameEx(StatePtr->FileWrite.FileName, CmdPtr->Filename,
+ sizeof(StatePtr->FileWrite.FileName), sizeof(CmdPtr->Filename),
+ CFE_PLATFORM_SB_DEFAULT_ROUTING_FILENAME,
+ CFE_FS_GetDefaultMountPoint(CFE_FS_FileCategory_BINARY_DATA_DUMP),
+ CFE_FS_GetDefaultExtension(CFE_FS_FileCategory_BINARY_DATA_DUMP));
+
+ if (Status == CFE_SUCCESS)
+ {
+ Status = CFE_FS_BackgroundFileDumpRequest(&StatePtr->FileWrite);
+ }
+ }
+ else
+ {
+ Status = CFE_STATUS_REQUEST_ALREADY_PENDING;
+ }
+
+ if (Status != CFE_SUCCESS)
+ {
+ /* generate the same event as is generated when unable to create the file (same thing, really) */
+ CFE_SB_BackgroundFileEventHandler(StatePtr, CFE_FS_FileWriteEvent_CREATE_ERROR, Status, 0, 0, 0);
+ }
+
+ CFE_SB_IncrCmdCtr(Status);
+
+ return CFE_SUCCESS;
+} /* end CFE_SB_WriteRoutingInfoCmd */
+
+bool CFE_SB_WritePipeInfoDataGetter(void *Meta, uint32 RecordNum, void **Buffer, size_t *BufSize)
+{
+ CFE_SB_BackgroundFileStateInfo_t *BgFilePtr;
+ CFE_SB_PipeInfoEntry_t * PipeBufferPtr;
+ CFE_SB_PipeD_t * PipeDscPtr;
+ osal_id_t SysQueueId = OS_OBJECT_ID_UNDEFINED;
+ bool PipeIsValid;
+
+ BgFilePtr = (CFE_SB_BackgroundFileStateInfo_t *)Meta;
+ PipeDscPtr = NULL;
+ PipeIsValid = false;
+
+ PipeBufferPtr = &BgFilePtr->Buffer.PipeInfo;
+
+ if (RecordNum < CFE_PLATFORM_SB_MAX_PIPES)
+ {
+ PipeDscPtr = &CFE_SB_Global.PipeTbl[RecordNum];
+
+ CFE_SB_LockSharedData(__FILE__, __LINE__);
+
+ PipeIsValid = CFE_SB_PipeDescIsUsed(PipeDscPtr);
+
+ if (PipeIsValid)
+ {
+ /*
+ * Ensure any old data in the struct has been cleared
+ */
+ memset(PipeBufferPtr, 0, sizeof(*PipeBufferPtr));
+
+ /*
+ * Take a "snapshot" of the PipeDsc state while locked
+ */
+ PipeBufferPtr->PipeId = CFE_SB_PipeDescGetID(PipeDscPtr);
+ PipeBufferPtr->AppId = PipeDscPtr->AppId;
+ PipeBufferPtr->Opts = PipeDscPtr->Opts;
+
+ /* copy stats info */
+ PipeBufferPtr->SendErrors = PipeDscPtr->SendErrors;
+ PipeBufferPtr->MaxQueueDepth = PipeDscPtr->MaxQueueDepth;
+ PipeBufferPtr->CurrentQueueDepth = PipeDscPtr->CurrentQueueDepth;
+ PipeBufferPtr->PeakQueueDepth = PipeDscPtr->PeakQueueDepth;
+
+ SysQueueId = PipeDscPtr->SysQueueId;
+ }
+
+ CFE_SB_UnlockSharedData(__FILE__, __LINE__);
+ }
+
+ if (PipeIsValid)
+ {
+ /*
+ * Gather data from other subsystems while unlocked.
+ * This might fail if the pipe is deleted simultaneously while this runs, but in
+ * the unlikely event that happens, the name data will simply be blank as the ID(s)
+ * will not validate.
+ */
+ OS_GetResourceName(SysQueueId, PipeBufferPtr->PipeName, sizeof(PipeBufferPtr->PipeName));
+ CFE_ES_GetAppName(PipeBufferPtr->AppName, PipeBufferPtr->AppId, sizeof(PipeBufferPtr->AppName));
+
+ *Buffer = PipeBufferPtr;
+ *BufSize = sizeof(*PipeBufferPtr);
+ }
+ else
+ {
+ *Buffer = NULL;
+ *BufSize = 0;
+ }
+
+ /* Check for EOF (last entry) */
+ return (RecordNum >= (CFE_PLATFORM_SB_MAX_PIPES - 1));
+}
+
+/******************************************************************************
+ * \brief SB internal function to handle processing of 'Write Pipe Info' Cmd
+ *
+ * \param[in] data Pointer to command structure
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ */
+int32 CFE_SB_WritePipeInfoCmd(const CFE_SB_WritePipeInfoCmd_t *data)
+{
+ const CFE_SB_WriteFileInfoCmd_Payload_t *CmdPtr;
+ CFE_SB_BackgroundFileStateInfo_t * StatePtr;
+ int32 Status;
+
+ StatePtr = &CFE_SB_Global.BackgroundFile;
+ CmdPtr = &data->Payload;
+
+ /* If a pipe info dump was already pending, do not overwrite the current request */
+ if (!CFE_FS_BackgroundFileDumpIsPending(&StatePtr->FileWrite))
+ {
+ /* Reset the entire state object (just for good measure, ensure no stale data) */
+ memset(StatePtr, 0, sizeof(*StatePtr));
+
+ /*
+ * Fill out the remainder of meta data.
+ * This data is currently the same for every request
+ */
+ StatePtr->FileWrite.FileSubType = CFE_FS_SubType_SB_PIPEDATA;
+ snprintf(StatePtr->FileWrite.Description, sizeof(StatePtr->FileWrite.Description), "SB Pipe Information");
+
+ StatePtr->FileWrite.GetData = CFE_SB_WritePipeInfoDataGetter;
+ StatePtr->FileWrite.OnEvent = CFE_SB_BackgroundFileEventHandler;
+
+ /*
+ ** Copy the filename into local buffer with default name/path/extension if not specified
+ */
+ Status = CFE_FS_ParseInputFileNameEx(StatePtr->FileWrite.FileName, CmdPtr->Filename,
+ sizeof(StatePtr->FileWrite.FileName), sizeof(CmdPtr->Filename),
+ CFE_PLATFORM_SB_DEFAULT_PIPE_FILENAME,
+ CFE_FS_GetDefaultMountPoint(CFE_FS_FileCategory_BINARY_DATA_DUMP),
+ CFE_FS_GetDefaultExtension(CFE_FS_FileCategory_BINARY_DATA_DUMP));
+
+ if (Status == CFE_SUCCESS)
+ {
+ Status = CFE_FS_BackgroundFileDumpRequest(&StatePtr->FileWrite);
+ }
+ }
+ else
+ {
+ Status = CFE_STATUS_REQUEST_ALREADY_PENDING;
+ }
+
+ if (Status != CFE_SUCCESS)
+ {
+ /* generate the same event as is generated when unable to create the file (same thing, really) */
+ CFE_SB_BackgroundFileEventHandler(StatePtr, CFE_FS_FileWriteEvent_CREATE_ERROR, Status, 0, 0, 0);
+ }
+
+ CFE_SB_IncrCmdCtr(Status);
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+ * Local callback helper for writing map info to a file
+ */
+void CFE_SB_CollectMsgMapInfo(CFE_SBR_RouteId_t RouteId, void *ArgPtr)
+{
+ CFE_SB_MsgMapFileEntry_t *BufferPtr;
+
+ /* Cast arguments for local use */
+ BufferPtr = (CFE_SB_MsgMapFileEntry_t *)ArgPtr;
+
+ /* Extract data from runtime info, write into the temporary buffer */
+ /* Data must be locked to snapshot the route info */
+ CFE_SB_LockSharedData(__FILE__, __LINE__);
+
+ BufferPtr->MsgId = CFE_SBR_GetMsgId(RouteId);
+ BufferPtr->Index = CFE_SBR_RouteIdToValue(RouteId);
+
+ CFE_SB_UnlockSharedData(__FILE__, __LINE__);
+}
+
+bool CFE_SB_WriteMsgMapInfoDataGetter(void *Meta, uint32 RecordNum, void **Buffer, size_t *BufSize)
+{
+ CFE_SB_BackgroundFileStateInfo_t *BgFilePtr;
+ CFE_SBR_Throttle_t Throttle;
+
+ /* Cast arguments for local use */
+ BgFilePtr = (CFE_SB_BackgroundFileStateInfo_t *)Meta;
+
+ Throttle.StartIndex = RecordNum;
+ Throttle.MaxLoop = 1;
+ Throttle.NextIndex = 0;
+
+ /* Set the MsgId intially - will be overwritten with real info in CFE_SB_CollectMsgMapInfo */
+ BgFilePtr->Buffer.MsgMapInfo.MsgId = CFE_SB_INVALID_MSG_ID;
+
+ /* Collect info on the next route (limited to one per cycle via throttle) */
+ CFE_SBR_ForEachRouteId(CFE_SB_CollectMsgMapInfo, &BgFilePtr->Buffer.MsgMapInfo, &Throttle);
+
+ /* If Map was valid, pass the output of CFE_SB_CollectMsgMapInfo() back to be written */
+ if (CFE_SB_IsValidMsgId(BgFilePtr->Buffer.MsgMapInfo.MsgId))
+ {
+ *Buffer = &BgFilePtr->Buffer.MsgMapInfo;
+ *BufSize = sizeof(CFE_SB_MsgMapFileEntry_t);
+ }
+ else
+ {
+ *Buffer = NULL;
+ *BufSize = 0;
+ }
+
+ /* Check for EOF (last entry) - NextIndex is nonzero if more records left, zero at the end of the route table */
+ return (Throttle.NextIndex == 0);
+}
+
+/******************************************************************************
+ * \brief SB internal function to handle processing of 'Write Map Info' Cmd
+ *
+ * \param[in] data Pointer to command structure
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ */
+int32 CFE_SB_WriteMapInfoCmd(const CFE_SB_WriteMapInfoCmd_t *data)
+{
+ const CFE_SB_WriteFileInfoCmd_Payload_t *CmdPtr;
+ CFE_SB_BackgroundFileStateInfo_t * StatePtr;
+ int32 Status;
+
+ StatePtr = &CFE_SB_Global.BackgroundFile;
+ CmdPtr = &data->Payload;
+
+ /* If a pipe info dump was already pending, do not overwrite the current request */
+ if (!CFE_FS_BackgroundFileDumpIsPending(&StatePtr->FileWrite))
+ {
+ /* Reset the entire state object (just for good measure, ensure no stale data) */
+ memset(StatePtr, 0, sizeof(*StatePtr));
+
+ /*
+ * Fill out the remainder of meta data.
+ * This data is currently the same for every request
+ */
+ StatePtr->FileWrite.FileSubType = CFE_FS_SubType_SB_MAPDATA;
+ snprintf(StatePtr->FileWrite.Description, sizeof(StatePtr->FileWrite.Description), "SB Map Information");
+
+ StatePtr->FileWrite.GetData = CFE_SB_WriteMsgMapInfoDataGetter;
+ StatePtr->FileWrite.OnEvent = CFE_SB_BackgroundFileEventHandler;
+
+ /*
+ ** Copy the filename into local buffer with default name/path/extension if not specified
+ */
+ Status = CFE_FS_ParseInputFileNameEx(StatePtr->FileWrite.FileName, CmdPtr->Filename,
+ sizeof(StatePtr->FileWrite.FileName), sizeof(CmdPtr->Filename),
+ CFE_PLATFORM_SB_DEFAULT_MAP_FILENAME,
+ CFE_FS_GetDefaultMountPoint(CFE_FS_FileCategory_BINARY_DATA_DUMP),
+ CFE_FS_GetDefaultExtension(CFE_FS_FileCategory_BINARY_DATA_DUMP));
+
+ if (Status == CFE_SUCCESS)
+ {
+ Status = CFE_FS_BackgroundFileDumpRequest(&StatePtr->FileWrite);
+ }
+ }
+ else
+ {
+ Status = CFE_STATUS_REQUEST_ALREADY_PENDING;
+ }
+
+ if (Status != CFE_SUCCESS)
+ {
+ /* generate the same event as is generated when unable to create the file (same thing, really) */
+ CFE_SB_BackgroundFileEventHandler(StatePtr, CFE_FS_FileWriteEvent_CREATE_ERROR, Status, 0, 0, 0);
+ }
+
+ CFE_SB_IncrCmdCtr(Status);
+
+ return CFE_SUCCESS;
+} /* end CFE_SB_WriteMapInfoCmd */
+
+/******************************************************************************
+ * 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;
+
+ destptr = CFE_SBR_GetDestListHeadPtr(RouteId);
+
+ /* Loop through destinations */
+ while (destptr != NULL)
+ {
+
+ if (destptr->Scope == CFE_SB_MSG_GLOBAL)
+ {
+
+ /* ...add entry into pkt */
+ CFE_SB_Global.PrevSubMsg.Payload.Entry[CFE_SB_Global.PrevSubMsg.Payload.Entries].MsgId =
+ CFE_SBR_GetMsgId(RouteId);
+ CFE_SB_Global.PrevSubMsg.Payload.Entry[CFE_SB_Global.PrevSubMsg.Payload.Entries].Qos.Priority = 0;
+ CFE_SB_Global.PrevSubMsg.Payload.Entry[CFE_SB_Global.PrevSubMsg.Payload.Entries].Qos.Reliability = 0;
+ CFE_SB_Global.PrevSubMsg.Payload.Entries++;
+
+ /* send pkt if full */
+ if (CFE_SB_Global.PrevSubMsg.Payload.Entries >= CFE_SB_SUB_ENTRIES_PER_PKT)
+ {
+ CFE_SB_UnlockSharedData(__func__, __LINE__);
+ status = CFE_SB_TransmitMsg(&CFE_SB_Global.PrevSubMsg.Hdr.Msg, true);
+ 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_Global.PrevSubMsg.Payload.PktSegment,
+ (int)CFE_SB_Global.PrevSubMsg.Payload.Entries, (unsigned int)status);
+ CFE_SB_LockSharedData(__func__, __LINE__);
+ CFE_SB_Global.PrevSubMsg.Payload.Entries = 0;
+ CFE_SB_Global.PrevSubMsg.Payload.PktSegment++;
+ }
+
+ /*
+ * 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()
+**
+** Purpose:
+** SB function to build and send an SB packet containing a complete list of
+** current subscriptions.Intended to be used primarily for the Software Bus
+** Networking Application (SBN).
+**
+** Arguments:
+** None
+**
+** Return:
+** None
+*/
+int32 CFE_SB_SendPrevSubsCmd(const CFE_SB_SendPrevSubsCmd_t *data)
+{
+ int32 status;
+
+ /* Take semaphore to ensure data does not change during this function */
+ CFE_SB_LockSharedData(__func__, __LINE__);
+
+ /* Initialize entry/segment tracking */
+ CFE_SB_Global.PrevSubMsg.Payload.PktSegment = 1;
+ CFE_SB_Global.PrevSubMsg.Payload.Entries = 0;
+
+ /* Send subcription for each route */
+ CFE_SBR_ForEachRouteId(CFE_SB_SendRouteSub, NULL, NULL);
+
+ CFE_SB_UnlockSharedData(__func__, __LINE__);
+
+ /* if pkt has any number of entries, send it as a partial pkt */
+ if (CFE_SB_Global.PrevSubMsg.Payload.Entries > 0)
+ {
+ status = CFE_SB_TransmitMsg(&CFE_SB_Global.PrevSubMsg.Hdr.Msg, true);
+ 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_Global.PrevSubMsg.Payload.PktSegment,
+ (int)CFE_SB_Global.PrevSubMsg.Payload.Entries, (unsigned int)status);
+ }
+
+ return CFE_SUCCESS;
+} /* end CFE_SB_SendPrevSubsCmd */
+
+/******************************************************************************
+** Function: CFE_SB_IncrCmdCtr()
+**
+** Purpose:
+** SB internal function to increment the proper cmd counter based on the
+** status input. This small utility was written to eliminate duplicate code.
+**
+** Arguments:
+** status - typically CFE_SUCCESS or an SB error code
+**
+** Return:
+** None
+*/
+void CFE_SB_IncrCmdCtr(int32 status)
+{
+
+ if (status == CFE_SUCCESS)
+ {
+ CFE_SB_Global.HKTlmMsg.Payload.CommandCounter++;
+ }
+ else
+ {
+ CFE_SB_Global.HKTlmMsg.Payload.CommandErrorCounter++;
+ } /* end if */
+
+} /* end CFE_SB_IncrCmdCtr */
+
+/******************************************************************************
+** Function: CFE_SB_SetSubscriptionReporting()
+**
+** Purpose:
+** SB internal function to enable and disable subscription reporting.
+**
+** Arguments:
+**
+**
+** Return:
+** None
+*/
+void CFE_SB_SetSubscriptionReporting(uint32 state)
+{
+
+ CFE_SB_Global.SubscriptionReporting = state;
+
+} /* end CFE_SB_SetSubscriptionReporting */
diff --git a/modules/sb/fsw/src/cfe_sb_util.c b/modules/sb/fsw/src/cfe_sb_util.c
new file mode 100644
index 000000000..bbfa95a7b
--- /dev/null
+++ b/modules/sb/fsw/src/cfe_sb_util.c
@@ -0,0 +1,253 @@
+/*
+** 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_sb_util.c
+**
+** Purpose:
+** This file contains 'access' macros and functions for reading and
+** writing message header fields.
+**
+** Author: R.McGraw/SSI
+**
+******************************************************************************/
+
+/*
+** Include Files
+*/
+
+#include "cfe_sb_module_all.h"
+
+#include
+
+/******************************************************************************
+** Function: CFE_SB_MsgHdrSize()
+**
+** Purpose:
+** Get the size of a message header.
+**
+** Arguments:
+** *MsgPtr - Pointer to a SB message
+**
+** Return:
+** Size of Message Header.
+*/
+size_t CFE_SB_MsgHdrSize(const CFE_MSG_Message_t *MsgPtr)
+{
+ size_t size = 0;
+ bool hassechdr = false;
+ CFE_MSG_Type_t type = CFE_MSG_Type_Invalid;
+
+ if (MsgPtr == NULL)
+ {
+ return CFE_SB_BAD_ARGUMENT;
+ }
+
+ CFE_MSG_GetHasSecondaryHeader(MsgPtr, &hassechdr);
+ CFE_MSG_GetType(MsgPtr, &type);
+
+ /* if secondary hdr is not present... */
+ /* Since all cFE messages must have a secondary hdr this check is not needed */
+ if (!hassechdr)
+ {
+ size = sizeof(CCSDS_SpacePacket_t);
+ }
+ else if (type == CFE_MSG_Type_Cmd)
+ {
+ size = sizeof(CFE_MSG_CommandHeader_t);
+ }
+ else if (type == CFE_MSG_Type_Tlm)
+ {
+ size = sizeof(CFE_MSG_TelemetryHeader_t);
+ }
+
+ return size;
+
+} /* end CFE_SB_MsgHdrSize */
+
+/*
+ * Function: CFE_SB_GetUserData - See API and header file for details
+ */
+void *CFE_SB_GetUserData(CFE_MSG_Message_t *MsgPtr)
+{
+ uint8 *BytePtr;
+ size_t HdrSize;
+
+ if (MsgPtr == NULL)
+ {
+ CFE_ES_WriteToSysLog("CFE_SB:GetUserData-Failed invalid arguments\n");
+ return 0;
+ }
+
+ BytePtr = (uint8 *)MsgPtr;
+ HdrSize = CFE_SB_MsgHdrSize(MsgPtr);
+
+ return (BytePtr + HdrSize);
+} /* end CFE_SB_GetUserData */
+
+/*
+ * Function: CFE_SB_GetUserDataLength - See API and header file for details
+ */
+size_t CFE_SB_GetUserDataLength(const CFE_MSG_Message_t *MsgPtr)
+{
+ CFE_MSG_Size_t TotalMsgSize = 0;
+ size_t HdrSize;
+
+ if (MsgPtr == NULL)
+ {
+ return CFE_SB_BAD_ARGUMENT;
+ }
+
+ CFE_MSG_GetSize(MsgPtr, &TotalMsgSize);
+ HdrSize = CFE_SB_MsgHdrSize(MsgPtr);
+
+ return TotalMsgSize - HdrSize;
+} /* end CFE_SB_GetUserDataLength */
+
+/*
+ * Function: CFE_SB_SetUserDataLength - See API and header file for details
+ */
+void CFE_SB_SetUserDataLength(CFE_MSG_Message_t *MsgPtr, size_t DataLength)
+{
+ CFE_MSG_Size_t TotalMsgSize;
+ size_t HdrSize;
+
+ if (MsgPtr == NULL)
+ {
+ CFE_ES_WriteToSysLog("CFE_SB:SetUserDataLength-Failed invalid arguments\n");
+ }
+ else
+ {
+ HdrSize = CFE_SB_MsgHdrSize(MsgPtr);
+ TotalMsgSize = HdrSize + DataLength;
+
+ if (TotalMsgSize <= CFE_MISSION_SB_MAX_SB_MSG_SIZE)
+ {
+ CFE_MSG_SetSize(MsgPtr, TotalMsgSize);
+ }
+ else
+ {
+ CFE_ES_WriteToSysLog("CFE_SB:SetUserDataLength-Failed TotalMsgSize too large\n");
+ }
+ }
+} /* end CFE_SB_SetUserDataLength */
+
+/*
+ * Function: CFE_SB_TimeStampMsg - See API and header file for details
+ */
+void CFE_SB_TimeStampMsg(CFE_MSG_Message_t *MsgPtr)
+{
+ CFE_MSG_SetMsgTime(MsgPtr, CFE_TIME_GetTime());
+
+} /* end CFE_SB_TimeStampMsg */
+
+/*
+ * Function: CFE_SB_MessageStringGet - See API and header file for details
+ */
+int32 CFE_SB_MessageStringGet(char *DestStringPtr, const char *SourceStringPtr, const char *DefaultString,
+ size_t DestMaxSize, size_t SourceMaxSize)
+{
+ int32 Result;
+
+ /*
+ * Error in caller if DestMaxSize == 0.
+ * Cannot terminate the string, since there is no place for the NUL
+ * In this case, do nothing
+ */
+ if (DestMaxSize == 0 || DestStringPtr == NULL)
+ {
+ Result = CFE_SB_BAD_ARGUMENT;
+ }
+ else
+ {
+ Result = 0;
+
+ /*
+ * Check if should use the default, which is if
+ * the source string has zero length (first char is NUL).
+ */
+ if (DefaultString != NULL && (SourceMaxSize == 0 || *SourceStringPtr == 0))
+ {
+ SourceStringPtr = DefaultString;
+ SourceMaxSize = DestMaxSize;
+ }
+
+ /* Reserve 1 character for the required NUL */
+ --DestMaxSize;
+
+ while (SourceMaxSize > 0 && *SourceStringPtr != 0 && DestMaxSize > 0)
+ {
+ *DestStringPtr = *SourceStringPtr;
+ ++DestStringPtr;
+ ++SourceStringPtr;
+ --SourceMaxSize;
+ --DestMaxSize;
+
+ ++Result;
+ }
+
+ /* Put the NUL in the last character */
+ *DestStringPtr = 0;
+ }
+
+ return Result;
+}
+
+/*
+ * Function: CFE_SB_MessageStringSet - See API and header file for details
+ */
+int32 CFE_SB_MessageStringSet(char *DestStringPtr, const char *SourceStringPtr, size_t DestMaxSize,
+ size_t SourceMaxSize)
+{
+ int32 Result;
+
+ if (SourceStringPtr == NULL || DestStringPtr == NULL)
+ {
+ Result = CFE_SB_BAD_ARGUMENT;
+ }
+ else
+ {
+ Result = 0;
+
+ while (SourceMaxSize > 0 && *SourceStringPtr != 0 && DestMaxSize > 0)
+ {
+ *DestStringPtr = *SourceStringPtr;
+ ++DestStringPtr;
+ ++SourceStringPtr;
+ ++Result;
+ --DestMaxSize;
+ --SourceMaxSize;
+ }
+
+ /*
+ * Pad the remaining space with NUL chars,
+ * but this should NOT be included in the final size
+ */
+ while (DestMaxSize > 0)
+ {
+ /* Put the NUL in the last character */
+ *DestStringPtr = 0;
+ ++DestStringPtr;
+ --DestMaxSize;
+ }
+ }
+
+ return Result;
+}
diff --git a/modules/sb/fsw/src/cfe_sb_verify.h b/modules/sb/fsw/src/cfe_sb_verify.h
new file mode 100644
index 000000000..fd1221e3a
--- /dev/null
+++ b/modules/sb/fsw/src/cfe_sb_verify.h
@@ -0,0 +1,167 @@
+/*
+** 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
+ *
+ * Purpose:
+ * This header file performs compile time checking for SB configuration
+ * parameters.
+ *
+ * Author: R.McGraw/SSI
+ *
+ */
+
+#ifndef CFE_SB_VERIFY_H
+#define CFE_SB_VERIFY_H
+
+#include
+
+#if CFE_PLATFORM_SB_MAX_MSG_IDS < 1
+#error CFE_PLATFORM_SB_MAX_MSG_IDS cannot be less than 1!
+#endif
+
+#if CFE_PLATFORM_SB_MAX_PIPES < 1
+#error CFE_PLATFORM_SB_MAX_PIPES cannot be less than 1!
+#endif
+
+#if CFE_PLATFORM_SB_MAX_PIPES > OS_MAX_QUEUES
+#error CFE_PLATFORM_SB_MAX_PIPES cannot be greater than OS_MAX_QUEUES!
+#endif
+
+#if CFE_PLATFORM_SB_MAX_DEST_PER_PKT < 1
+#error CFE_PLATFORM_SB_MAX_DEST_PER_PKT cannot be less than 1!
+#endif
+
+#if CFE_PLATFORM_SB_HIGHEST_VALID_MSGID < 1
+#error CFE_PLATFORM_SB_HIGHEST_VALID_MSGID cannot be less than 1!
+#endif
+
+#if CFE_PLATFORM_SB_HIGHEST_VALID_MSGID > 0xFFFFFFFE
+#error CFE_PLATFORM_SB_HIGHEST_VALID_MSGID cannot be > 0xFFFFFFFE
+#endif
+
+#if CFE_PLATFORM_SB_BUF_MEMORY_BYTES < 512
+#error CFE_PLATFORM_SB_BUF_MEMORY_BYTES cannot be less than 512 bytes!
+#endif
+
+#if CFE_PLATFORM_SB_BUF_MEMORY_BYTES > UINT32_MAX
+#error CFE_PLATFORM_SB_BUF_MEMORY_BYTES cannot be greater than UINT32_MAX (4 Gigabytes)!
+#endif
+
+/*
+ * Legacy time formats no longer supported in core cFE, this will pass
+ * if default is selected or if both defines are removed
+ */
+#if (CFE_MISSION_SB_PACKET_TIME_FORMAT != CFE_MISSION_SB_TIME_32_16_SUBS)
+#error Legacy CFE_MISSION_SB_PACKET_TIME_FORMAT implementations no longer supported in core
+#endif
+
+#if CFE_MISSION_SB_MAX_SB_MSG_SIZE < 6
+#error CFE_MISSION_SB_MAX_SB_MSG_SIZE cannot be less than 6 (CCSDS Primary Hdr Size)!
+#endif
+
+/*
+** SB Memory Pool Block Sizes
+*/
+#if CFE_PLATFORM_SB_MAX_BLOCK_SIZE < CFE_MISSION_SB_MAX_SB_MSG_SIZE
+#error CFE_PLATFORM_SB_MAX_BLOCK_SIZE must be > or = to CFE_MISSION_SB_MAX_SB_MSG_SIZE!
+#endif
+
+#if CFE_PLATFORM_SB_MEM_BLOCK_SIZE_01 > CFE_PLATFORM_SB_MEM_BLOCK_SIZE_02
+#error CFE_PLATFORM_SB_MEM_BLOCK_SIZE_01 must be less than CFE_PLATFORM_SB_MEM_BLOCK_SIZE_02
+#endif
+
+#if CFE_PLATFORM_SB_MEM_BLOCK_SIZE_02 > CFE_PLATFORM_SB_MEM_BLOCK_SIZE_03
+#error CFE_PLATFORM_SB_MEM_BLOCK_SIZE_02 must be less than CFE_PLATFORM_SB_MEM_BLOCK_SIZE_03
+#endif
+
+#if CFE_PLATFORM_SB_MEM_BLOCK_SIZE_03 > CFE_PLATFORM_SB_MEM_BLOCK_SIZE_04
+#error CFE_PLATFORM_SB_MEM_BLOCK_SIZE_03 must be less than CFE_PLATFORM_SB_MEM_BLOCK_SIZE_04
+#endif
+
+#if CFE_PLATFORM_SB_MEM_BLOCK_SIZE_04 > CFE_PLATFORM_SB_MEM_BLOCK_SIZE_05
+#error CFE_PLATFORM_SB_MEM_BLOCK_SIZE_04 must be less than CFE_PLATFORM_SB_MEM_BLOCK_SIZE_05
+#endif
+
+#if CFE_PLATFORM_SB_MEM_BLOCK_SIZE_05 > CFE_PLATFORM_SB_MEM_BLOCK_SIZE_06
+#error CFE_PLATFORM_SB_MEM_BLOCK_SIZE_05 must be less than CFE_PLATFORM_SB_MEM_BLOCK_SIZE_06
+#endif
+
+#if CFE_PLATFORM_SB_MEM_BLOCK_SIZE_06 > CFE_PLATFORM_SB_MEM_BLOCK_SIZE_07
+#error CFE_PLATFORM_SB_MEM_BLOCK_SIZE_06 must be less than CFE_PLATFORM_SB_MEM_BLOCK_SIZE_07
+#endif
+
+#if CFE_PLATFORM_SB_MEM_BLOCK_SIZE_07 > CFE_PLATFORM_SB_MEM_BLOCK_SIZE_08
+#error CFE_PLATFORM_SB_MEM_BLOCK_SIZE_07 must be less than CFE_PLATFORM_SB_MEM_BLOCK_SIZE_08
+#endif
+
+#if CFE_PLATFORM_SB_MEM_BLOCK_SIZE_08 > CFE_PLATFORM_SB_MEM_BLOCK_SIZE_09
+#error CFE_PLATFORM_SB_MEM_BLOCK_SIZE_08 must be less than CFE_PLATFORM_SB_MEM_BLOCK_SIZE_09
+#endif
+
+#if CFE_PLATFORM_SB_MEM_BLOCK_SIZE_09 > CFE_PLATFORM_SB_MEM_BLOCK_SIZE_10
+#error CFE_PLATFORM_SB_MEM_BLOCK_SIZE_09 must be less than CFE_PLATFORM_SB_MEM_BLOCK_SIZE_10
+#endif
+
+#if CFE_PLATFORM_SB_MEM_BLOCK_SIZE_10 > CFE_PLATFORM_SB_MEM_BLOCK_SIZE_11
+#error CFE_PLATFORM_SB_MEM_BLOCK_SIZE_10 must be less than CFE_PLATFORM_SB_MEM_BLOCK_SIZE_11
+#endif
+
+#if CFE_PLATFORM_SB_MEM_BLOCK_SIZE_11 > CFE_PLATFORM_SB_MEM_BLOCK_SIZE_12
+#error CFE_PLATFORM_SB_MEM_BLOCK_SIZE_11 must be less than CFE_PLATFORM_SB_MEM_BLOCK_SIZE_12
+#endif
+
+#if CFE_PLATFORM_SB_MEM_BLOCK_SIZE_12 > CFE_PLATFORM_SB_MEM_BLOCK_SIZE_13
+#error CFE_PLATFORM_SB_MEM_BLOCK_SIZE_12 must be less than CFE_PLATFORM_SB_MEM_BLOCK_SIZE_13
+#endif
+
+#if CFE_PLATFORM_SB_MEM_BLOCK_SIZE_13 > CFE_PLATFORM_SB_MEM_BLOCK_SIZE_14
+#error CFE_PLATFORM_SB_MEM_BLOCK_SIZE_13 must be less than CFE_PLATFORM_SB_MEM_BLOCK_SIZE_14
+#endif
+
+#if CFE_PLATFORM_SB_MEM_BLOCK_SIZE_14 > CFE_PLATFORM_SB_MEM_BLOCK_SIZE_15
+#error CFE_PLATFORM_SB_MEM_BLOCK_SIZE_14 must be less than CFE_PLATFORM_SB_MEM_BLOCK_SIZE_15
+#endif
+
+#if CFE_PLATFORM_SB_MEM_BLOCK_SIZE_15 > CFE_PLATFORM_SB_MEM_BLOCK_SIZE_16
+#error CFE_PLATFORM_SB_MEM_BLOCK_SIZE_15 must be less than CFE_PLATFORM_SB_MEM_BLOCK_SIZE_16
+#endif
+
+#if CFE_PLATFORM_SB_MEM_BLOCK_SIZE_16 >= CFE_PLATFORM_SB_MAX_BLOCK_SIZE
+#error CFE_PLATFORM_SB_MEM_BLOCK_SIZE_16 must be less than CFE_PLATFORM_SB_MAX_BLOCK_SIZE
+#endif
+
+#if CFE_PLATFORM_SB_DEFAULT_MSG_LIMIT < 4
+#error CFE_PLATFORM_SB_DEFAULT_MSG_LIMIT cannot be less than 4!
+#endif
+
+#if CFE_PLATFORM_SB_DEFAULT_MSG_LIMIT > 65535
+#error CFE_PLATFORM_SB_DEFAULT_MSG_LIMIT cannot be greater than 65535!
+#endif
+
+/*
+** Validate task stack size...
+*/
+#if CFE_PLATFORM_SB_START_TASK_STACK_SIZE < 2048
+#error CFE_PLATFORM_SB_START_TASK_STACK_SIZE must be greater than or equal to 2048
+#endif
+
+#endif /* CFE_SB_VERIFY_H */
diff --git a/modules/sbr/CMakeLists.txt b/modules/sbr/CMakeLists.txt
new file mode 100644
index 000000000..a8a564a7a
--- /dev/null
+++ b/modules/sbr/CMakeLists.txt
@@ -0,0 +1,47 @@
+##################################################################
+#
+# 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.
+#
+##################################################################
+
+project(CFE_SBR C)
+
+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}/fsw/src/cfe_sbr_map_direct.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/fsw/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}/fsw/src/cfe_sbr_map_hash.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/fsw/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)
+target_link_libraries(sbr PRIVATE core_private)
+
+# Add unit test coverage subdirectory
+if(ENABLE_UNIT_TESTS)
+ add_subdirectory(ut-coverage)
+endif(ENABLE_UNIT_TESTS)
+
diff --git a/modules/sbr/fsw/src/cfe_sbr_map_direct.c b/modules/sbr/fsw/src/cfe_sbr_map_direct.c
new file mode 100644
index 000000000..8aab2d0fa
--- /dev/null
+++ b/modules/sbr/fsw/src/cfe_sbr_map_direct.c
@@ -0,0 +1,95 @@
+/*
+** 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 "cfe_sbr.h"
+#include "cfe_sbr_priv.h"
+#include
+
+#include "cfe_sb.h"
+
+/*
+ * 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/fsw/src/cfe_sbr_map_hash.c b/modules/sbr/fsw/src/cfe_sbr_map_hash.c
new file mode 100644
index 000000000..44a85dc8e
--- /dev/null
+++ b/modules/sbr/fsw/src/cfe_sbr_map_hash.c
@@ -0,0 +1,165 @@
+/*
+** 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 "cfe_sbr.h"
+#include "cfe_sbr_priv.h"
+#include "cfe_sb.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/fsw/src/cfe_sbr_priv.h b/modules/sbr/fsw/src/cfe_sbr_priv.h
new file mode 100644
index 000000000..6f490fd28
--- /dev/null
+++ b/modules/sbr/fsw/src/cfe_sbr_priv.h
@@ -0,0 +1,61 @@
+/*
+** 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
+ *
+ * Prototypes for private functions and type definitions for SB
+ * routing internal use.
+ */
+
+#ifndef CFE_SBR_PRIV_H
+#define CFE_SBR_PRIV_H
+
+/*
+ * Includes
+ */
+#include "cfe_sbr.h"
+
+/******************************************************************************
+ * 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/fsw/src/cfe_sbr_route_unsorted.c b/modules/sbr/fsw/src/cfe_sbr_route_unsorted.c
new file mode 100644
index 000000000..40404fc53
--- /dev/null
+++ b/modules/sbr/fsw/src/cfe_sbr_route_unsorted.c
@@ -0,0 +1,210 @@
+/*
+** 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 "cfe_sbr.h"
+#include "cfe_sbr_priv.h"
+#include
+
+#include "cfe_sb.h"
+
+/******************************************************************************
+ * 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;
+}
+
+/******************************************************************************
+ * 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_RouteId_Atom_t startidx = 0;
+ CFE_SB_RouteId_Atom_t endidx = CFE_SBR_RDATA.RouteIdxTop;
+
+ /* Update throttle settings if needed */
+ if (ThrottlePtr != NULL)
+ {
+ startidx = ThrottlePtr->StartIndex;
+
+ /* Return next index of zero if full range is processed */
+ ThrottlePtr->NextIndex = 0;
+
+ if ((startidx + ThrottlePtr->MaxLoop) < endidx)
+ {
+ endidx = startidx + ThrottlePtr->MaxLoop;
+ ThrottlePtr->NextIndex = endidx;
+ }
+ }
+
+ for (routeidx = startidx; routeidx < endidx; routeidx++)
+ {
+ (*CallbackPtr)(CFE_SBR_ValueToRouteId(routeidx), ArgPtr);
+ }
+}