diff --git a/.gitignore b/.gitignore
new file mode 100644
index 000000000..6463c6f14
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,29 @@
+# Ignore everything
+*
+
+# ...even if they are in subdirectories
+!*/
+
+# But not these files...
+!/.gitignore
+!/README.md
+
+
+
+# Software Bus (SB)
+!modules/core_api/fsw/inc/cfe_sb*
+
+!modules/core_private/fsw/inc/cfe_sb*
+
+!modules/sb/fsw/**
+!modules/sb/CMakeLists.txt
+
+!modules/sbr/fsw/src/cfe_sbr**
+!modules/sbr/CMakeLists.txt
+
+# CCSDS Message
+!modules/core_api/fsw/inc/cfe_msg*
+
+!modules/msg/fsw/**
+!modules/msg/option_inc/**
+!modules/msg/CMakeLists.txt
\ No newline at end of file
diff --git a/README.md b/README.md
index 7be7449c5..fc0c4042e 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,24 @@
-# cFE
\ No newline at end of file
+## cFS-Caelum Review: CFS-42
+
+This branch is meant for the cFS-Caelum code review of Software Bus, CCSDS Message and Global Variables. The review designation is "CFS-42"
+
+
+The corresponding, fully-working cFE instance matching the code in this branch can be found under the [cFE v7.0.0-rc1 tag](https://github.com/nasa/cFE/releases/tag/v7.0.0-rc1)
+
+### How to add your review comments
+
+Navigate to the ["files changed" tab](https://github.com/nasa/cFE/pull/1375/files) in the [nasa/cFE#1375](https://github.com/nasa/cFE/pull/1375) pull request.
+
+
+
+
+
+You can add comments on any line of code by hovering on the line number and clicking on the plus "+" sign. Once you're finished with the comment click on the green "Start Review" button. To add more comments, just click on the relevant line number in any file, type your comment, and click on "Add review comment".
+
+
+
+
+ If you need to take a break, or if you're done, click the green "Finish Review" button on the top right corner of the
+page, add any overall or summarizing comments and click on "Submit Review". You can always return and add new comments using the same process.
+
+**Thank you!**
diff --git a/modules/core_api/fsw/inc/cfe_msg.h b/modules/core_api/fsw/inc/cfe_msg.h
new file mode 100644
index 000000000..22a40bddc
--- /dev/null
+++ b/modules/core_api/fsw/inc/cfe_msg.h
@@ -0,0 +1,669 @@
+/*
+** 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
+ *
+ * Message access APIs
+ */
+
+#ifndef CFE_MSG_H
+#define CFE_MSG_H
+
+/*
+ * Includes
+ */
+#include "common_types.h"
+#include "cfe_error.h"
+#include "cfe_msg_hdr.h"
+#include "cfe_msg_api_typedefs.h"
+
+#include "cfe_es_api_typedefs.h"
+#include "cfe_sb_api_typedefs.h"
+#include "cfe_time_api_typedefs.h"
+
+/** \defgroup CFEAPIMSGHeader cFE Message header APIs
+ * \{
+ */
+
+/*****************************************************************************/
+/**
+ * \brief Initialize a message
+ *
+ * \par Description
+ * This routine initialize a message. The entire message is
+ * set to zero (based on size), defaults are set, then the
+ * size and bits from MsgId are set.
+ *
+ * \param[in, out] MsgPtr A pointer to the buffer that contains the message.
+ * \param[in] MsgId MsgId that corresponds to message
+ * \param[in] Size Total size of the mesage (used to set length field)
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_Init(CFE_MSG_Message_t *MsgPtr, CFE_SB_MsgId_t MsgId, CFE_MSG_Size_t Size);
+
+/*****************************************************************************/
+/**
+ * \brief Gets the total size of a message.
+ *
+ * \par Description
+ * This routine gets the total size of the message.
+ *
+ * \param[in] MsgPtr A pointer to the buffer that contains the message.
+ * \param[out] Size Total message size
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_GetSize(const CFE_MSG_Message_t *MsgPtr, CFE_MSG_Size_t *Size);
+
+/*****************************************************************************/
+/**
+ * \brief Sets the total size of a message.
+ *
+ * \par Description
+ * This routine sets the total size of the message.
+ *
+ * \param[in, out] MsgPtr A pointer to the buffer that contains the message.
+ * \param[in] Size Total message size
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_SetSize(CFE_MSG_Message_t *MsgPtr, CFE_MSG_Size_t Size);
+
+/*****************************************************************************/
+/**
+ * \brief Gets the message type.
+ *
+ * \par Description
+ * This routine gets the message type.
+ *
+ * \param[in] MsgPtr A pointer to the buffer that contains the message.
+ * \param[out] Type Message type
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_GetType(const CFE_MSG_Message_t *MsgPtr, CFE_MSG_Type_t *Type);
+
+/*****************************************************************************/
+/**
+ * \brief Sets the message type.
+ *
+ * \par Description
+ * This routine sets the message type.
+ *
+ * \param[in, out] MsgPtr A pointer to the buffer that contains the message.
+ * \param[in] Type Message type
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_SetType(CFE_MSG_Message_t *MsgPtr, CFE_MSG_Type_t Type);
+
+/*****************************************************************************/
+/**
+ * \brief Gets the message header version.
+ *
+ * \par Description
+ * This routine gets the message header version.
+ *
+ * \param[in] MsgPtr A pointer to the buffer that contains the message.
+ * \param[out] Version Header version
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_GetHeaderVersion(const CFE_MSG_Message_t *MsgPtr, CFE_MSG_HeaderVersion_t *Version);
+
+/*****************************************************************************/
+/**
+ * \brief Sets the message header version.
+ *
+ * \par Description
+ * This routine sets the message header version. Typically only
+ * set within message initialization and not used by APPs.
+ *
+ * \param[in, out] MsgPtr A pointer to the buffer that contains the message.
+ * \param[in] Version Header version
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_SetHeaderVersion(CFE_MSG_Message_t *MsgPtr, CFE_MSG_HeaderVersion_t Version);
+
+/*****************************************************************************/
+/**
+ * \brief Gets the message secondary header boolean
+ *
+ * \par Description
+ * This routine gets the message secondary header boolean.
+ *
+ * \param[in] MsgPtr A pointer to the buffer that contains the message.
+ * \param[out] HasSecondary Has secondary header flag
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_GetHasSecondaryHeader(const CFE_MSG_Message_t *MsgPtr, bool *HasSecondary);
+
+/*****************************************************************************/
+/**
+ * \brief Sets the message secondary header boolean
+ *
+ * \par Description
+ * This routine sets the message has secondary header boolean. Typically only
+ * set within message initialization and not used by APPs.
+ *
+ * \param[in, out] MsgPtr A pointer to the buffer that contains the message.
+ * \param[in] HasSecondary Has secondary header flag
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_SetHasSecondaryHeader(CFE_MSG_Message_t *MsgPtr, bool HasSecondary);
+
+/*****************************************************************************/
+/**
+ * \brief Gets the message application ID
+ *
+ * \par Description
+ * This routine gets the message application ID.
+ *
+ * \param[in] MsgPtr A pointer to the buffer that contains the message.
+ * \param[out] ApId Application ID
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_GetApId(const CFE_MSG_Message_t *MsgPtr, CFE_MSG_ApId_t *ApId);
+
+/*****************************************************************************/
+/**
+ * \brief Sets the message application ID
+ *
+ * \par Description
+ * This routine sets the message application ID. Typically set
+ * at initialization using the MsgId, but API available to set
+ * bits that may not be included in MsgId.
+ *
+ * \param[in, out] MsgPtr A pointer to the buffer that contains the message.
+ * \param[in] ApId Application ID
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_SetApId(CFE_MSG_Message_t *MsgPtr, CFE_MSG_ApId_t ApId);
+
+/*****************************************************************************/
+/**
+ * \brief Gets the message segmentation flag
+ *
+ * \par Description
+ * This routine gets the message segmentation flag
+ *
+ * \param[in] MsgPtr A pointer to the buffer that contains the message.
+ * \param[out] SegFlag Segmentation flag
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_GetSegmentationFlag(const CFE_MSG_Message_t *MsgPtr, CFE_MSG_SegmentationFlag_t *SegFlag);
+
+/*****************************************************************************/
+/**
+ * \brief Sets the message segmentation flag
+ *
+ * \par Description
+ * This routine sets the message segmentation flag.
+ *
+ * \param[in, out] MsgPtr A pointer to the buffer that contains the message.
+ * \param[in] SegFlag Segmentation flag
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_SetSegmentationFlag(CFE_MSG_Message_t *MsgPtr, CFE_MSG_SegmentationFlag_t SegFlag);
+
+/*****************************************************************************/
+/**
+ * \brief Gets the message sequence count
+ *
+ * \par Description
+ * This routine gets the message sequence count.
+ *
+ * \param[in] MsgPtr A pointer to the buffer that contains the message.
+ * \param[out] SeqCnt Sequence count
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_GetSequenceCount(const CFE_MSG_Message_t *MsgPtr, CFE_MSG_SequenceCount_t *SeqCnt);
+
+/*****************************************************************************/
+/**
+ * \brief Sets the message sequence count
+ *
+ * \par Description
+ * This routine sets the message sequence count.
+ *
+ * \param[in, out] MsgPtr A pointer to the buffer that contains the message.
+ * \param[in] SeqCnt Sequence count
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_SetSequenceCount(CFE_MSG_Message_t *MsgPtr, CFE_MSG_SequenceCount_t SeqCnt);
+
+/*****************************************************************************/
+/**
+ * \brief Gets the message EDS version
+ *
+ * \par Description
+ * This routine gets the message EDS version.
+ *
+ * \param[in] MsgPtr A pointer to the buffer that contains the message.
+ * \param[out] Version EDS Version
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_GetEDSVersion(const CFE_MSG_Message_t *MsgPtr, CFE_MSG_EDSVersion_t *Version);
+
+/*****************************************************************************/
+/**
+ * \brief Sets the message EDS version
+ *
+ * \par Description
+ * This routine sets the message EDS version.
+ *
+ * \param[in, out] MsgPtr A pointer to the buffer that contains the message.
+ * \param[in] Version EDS Version
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_SetEDSVersion(CFE_MSG_Message_t *MsgPtr, CFE_MSG_EDSVersion_t Version);
+
+/*****************************************************************************/
+/**
+ * \brief Gets the message endian
+ *
+ * \par Description
+ * This routine gets the message endian.
+ *
+ * \param[in] MsgPtr A pointer to the buffer that contains the message.
+ * \param[out] Endian Endian
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_GetEndian(const CFE_MSG_Message_t *MsgPtr, CFE_MSG_Endian_t *Endian);
+
+/*****************************************************************************/
+/**
+ * \brief Sets the message endian
+ *
+ * \par Description
+ * This routine sets the message endian. Invalid endian selection
+ * will set big endian.
+ *
+ * \param[in, out] MsgPtr A pointer to the buffer that contains the message.
+ * \param[in] Endian Endian
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_SetEndian(CFE_MSG_Message_t *MsgPtr, CFE_MSG_Endian_t Endian);
+
+/*****************************************************************************/
+/**
+ * \brief Gets the message playback flag
+ *
+ * \par Description
+ * This routine gets the message playback flag.
+ *
+ * \param[in] MsgPtr A pointer to the buffer that contains the message.
+ * \param[out] PlayFlag Playback Flag
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_GetPlaybackFlag(const CFE_MSG_Message_t *MsgPtr, CFE_MSG_PlaybackFlag_t *PlayFlag);
+
+/*****************************************************************************/
+/**
+ * \brief Sets the message playback flag
+ *
+ * \par Description
+ * This routine sets the message playback flag.
+ *
+ * \param[in, out] MsgPtr A pointer to the buffer that contains the message.
+ * \param[in] PlayFlag Playback Flag
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_SetPlaybackFlag(CFE_MSG_Message_t *MsgPtr, CFE_MSG_PlaybackFlag_t PlayFlag);
+
+/*****************************************************************************/
+/**
+ * \brief Gets the message subsystem
+ *
+ * \par Description
+ * This routine gets the message subsystem
+ *
+ * \param[in] MsgPtr A pointer to the buffer that contains the message.
+ * \param[out] Subsystem Subsystem
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_GetSubsystem(const CFE_MSG_Message_t *MsgPtr, CFE_MSG_Subsystem_t *Subsystem);
+
+/*****************************************************************************/
+/**
+ * \brief Sets the message subsystem
+ *
+ * \par Description
+ * This routine sets the message subsystem. Some bits may
+ * be set at initialization using the MsgId, but API available to set
+ * bits that may not be included in MsgId.
+ *
+ * \param[in, out] MsgPtr A pointer to the buffer that contains the message.
+ * \param[in] Subsystem Subsystem
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_SetSubsystem(CFE_MSG_Message_t *MsgPtr, CFE_MSG_Subsystem_t Subsystem);
+
+/*****************************************************************************/
+/**
+ * \brief Gets the message system
+ *
+ * \par Description
+ * This routine gets the message system id
+ *
+ * \param[in] MsgPtr A pointer to the buffer that contains the message.
+ * \param[out] System System
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_GetSystem(const CFE_MSG_Message_t *MsgPtr, CFE_MSG_System_t *System);
+
+/*****************************************************************************/
+/**
+ * \brief Sets the message system
+ *
+ * \par Description
+ * This routine sets the message system id. Some bits may
+ * be set at initialization using the MsgId, but API available to set
+ * bits that may not be included in MsgId.
+ *
+ * \param[in, out] MsgPtr A pointer to the buffer that contains the message.
+ * \param[in] System System
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_SetSystem(CFE_MSG_Message_t *MsgPtr, CFE_MSG_System_t System);
+
+/*****************************************************************************/
+/**
+ * \brief Calculates and sets the checksum of a message
+ *
+ * \par Description
+ * This routine calculates the checksum of a message according
+ * to an implementation-defined algorithm. Then, it sets the checksum field
+ * in the message with the calculated value. The contents and location of
+ * this field will depend on the underlying implementation of
+ * messages. It may be a checksum, a CRC, or some other algorithm.
+ *
+ * \par Assumptions, External Events, and Notes:
+ * - If the underlying implementation of messages does not
+ * include a checksum field, then this routine will return
+ * #CFE_MSG_WRONG_MSG_TYPE
+ *
+ * \param[in, out] MsgPtr A pointer to the buffer that contains the message.
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ * \retval #CFE_MSG_WRONG_MSG_TYPE \copybrief CFE_MSG_WRONG_MSG_TYPE
+ */
+CFE_Status_t CFE_MSG_GenerateChecksum(CFE_MSG_Message_t *MsgPtr);
+
+/*****************************************************************************/
+/**
+ * \brief Validates the checksum of a message.
+ *
+ * \par Description
+ * This routine validates the checksum of a message
+ * according to an implementation-defined algorithm.
+ *
+ * \par Assumptions, External Events, and Notes:
+ * - If the underlying implementation of messages does not
+ * include a checksum field, then this routine will return
+ * #CFE_MSG_WRONG_MSG_TYPE and set the IsValid parameter false.
+ *
+ * \param[in] MsgPtr A pointer to the buffer that contains the message.
+ * This must point to the first byte of the message header.
+ * \param[out] IsValid Checksum validation result
+ * \arg true - valid
+ * \arg false - invalid or not supported/implemented
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ * \retval #CFE_MSG_WRONG_MSG_TYPE \copybrief CFE_MSG_WRONG_MSG_TYPE
+ */
+CFE_Status_t CFE_MSG_ValidateChecksum(const CFE_MSG_Message_t *MsgPtr, bool *IsValid);
+
+/*****************************************************************************/
+/**
+ * \brief Sets the function code field in a message.
+ *
+ * \par Description
+ * This routine sets the function code of a message.
+ *
+ * \par Assumptions, External Events, and Notes:
+ * - If the underlying implementation of messages does not
+ * include a function code field, then this routine will do nothing to
+ * the message contents and will return #CFE_MSG_WRONG_MSG_TYPE.
+ *
+ * \param[in, out] MsgPtr A pointer to the buffer that contains the message.
+ * \param[in] FcnCode The function code to include in the message.
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ * \retval #CFE_MSG_WRONG_MSG_TYPE \copybrief CFE_MSG_WRONG_MSG_TYPE
+ *
+ */
+CFE_Status_t CFE_MSG_SetFcnCode(CFE_MSG_Message_t *MsgPtr, CFE_MSG_FcnCode_t FcnCode);
+
+/*****************************************************************************/
+/**
+ * \brief Gets the function code field from a message.
+ *
+ * \par Description
+ * This routine gets the function code from a message.
+ *
+ * \par Assumptions, External Events, and Notes:
+ * - If the underlying implementation of messages does not
+ * include a function code field, then this routine will
+ * set FcnCode to zero and return #CFE_MSG_WRONG_MSG_TYPE
+ *
+ * \param[in] MsgPtr A pointer to the buffer that contains the message.
+ * \param[out] FcnCode The function code from the message
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ * \retval #CFE_MSG_WRONG_MSG_TYPE \copybrief CFE_MSG_WRONG_MSG_TYPE
+ */
+CFE_Status_t CFE_MSG_GetFcnCode(const CFE_MSG_Message_t *MsgPtr, CFE_MSG_FcnCode_t *FcnCode);
+
+/*****************************************************************************/
+/**
+ * \brief Gets the time field from a message.
+ *
+ * \par Description
+ * This routine gets the time from a message.
+ *
+ * \par Assumptions, External Events, and Notes:
+ * - If the underlying implementation of messages does not
+ * include a time field, then this routine will set Time
+ * to zero and return #CFE_MSG_WRONG_MSG_TYPE
+ * - Note default implementation of command messages do not have a time field.
+ *
+ * \param[in] MsgPtr A pointer to the buffer that contains the message.
+ * \param[out] Time Time from the message
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ * \retval #CFE_MSG_WRONG_MSG_TYPE \copybrief CFE_MSG_WRONG_MSG_TYPE
+ */
+CFE_Status_t CFE_MSG_GetMsgTime(const CFE_MSG_Message_t *MsgPtr, CFE_TIME_SysTime_t *Time);
+
+/*****************************************************************************/
+/**
+ * \brief Sets the time field in a message.
+ *
+ * \par Description
+ * This routine sets the time of a message. Most applications
+ * will want to use #CFE_SB_TimeStampMsg instead of this function. But,
+ * when needed, this API can be used to set multiple messages
+ * with identical time stamps.
+ *
+ * \par Assumptions, External Events, and Notes:
+ * - If the underlying implementation of messages does not include
+ * a time field, then this routine will do nothing to the message contents
+ * and will return #CFE_MSG_WRONG_MSG_TYPE.
+ * - Note default implementation of command messages do not have a time field.
+ *
+ * \param[in, out] MsgPtr A pointer to the message.
+ * \param[in] Time The time to include in the message. This will usually be a time
+ * from #CFE_TIME_GetTime.
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ * \retval #CFE_MSG_WRONG_MSG_TYPE \copybrief CFE_MSG_WRONG_MSG_TYPE
+ */
+CFE_Status_t CFE_MSG_SetMsgTime(CFE_MSG_Message_t *MsgPtr, CFE_TIME_SysTime_t Time);
+
+/**\}*/
+
+/** \defgroup CFEAPIMSGMsgId cFE Message Id APIs
+ * \{
+ */
+
+/*****************************************************************************/
+/**
+ * \brief Gets the message id from a message.
+ *
+ * \par Description
+ * This routine gets the message id from a message. The message id
+ * is a hash of bits in the message header, used by the software bus for
+ * routing. Message id needs to be unique for each endpoint
+ * in the system.
+ *
+ * \param[in] MsgPtr A pointer to the buffer that contains the message.
+ * \param[out] MsgId Message id
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_GetMsgId(const CFE_MSG_Message_t *MsgPtr, CFE_SB_MsgId_t *MsgId);
+
+/*****************************************************************************/
+/**
+ * \brief Sets the message id bits in a message.
+ *
+ * \par Description
+ * This routine sets the message id bits in a message. The message id
+ * is a hash of bits in the message header, used by the software bus for
+ * routing. Message id needs to be unique for each endpoint
+ * in the system.
+ * \par Note
+ * This API only sets the bits in the header that make up the message ID.
+ * No other values in the header are modified.
+ *
+ * \param[in] MsgPtr A pointer to the buffer that contains the message.
+ * \param[out] MsgId Message id
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_SetMsgId(CFE_MSG_Message_t *MsgPtr, CFE_SB_MsgId_t MsgId);
+
+/*****************************************************************************/
+/**
+ * \brief Gets message type using message ID
+ *
+ * \par Description
+ * This routine gets the message type using the message ID
+ *
+ * \param[in] MsgId Message id
+ * \param[out] Type Message type
+ *
+ * \return Execution status, see \ref CFEReturnCodes
+ * \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+ * \retval #CFE_MSG_BAD_ARGUMENT \copybrief CFE_MSG_BAD_ARGUMENT
+ */
+CFE_Status_t CFE_MSG_GetTypeFromMsgId(CFE_SB_MsgId_t MsgId, CFE_MSG_Type_t *Type);
+
+/**\}*/
+
+#endif /* CFE_MSG_H */
diff --git a/modules/core_api/fsw/inc/cfe_msg_api_typedefs.h b/modules/core_api/fsw/inc/cfe_msg_api_typedefs.h
new file mode 100644
index 000000000..b91001bd6
--- /dev/null
+++ b/modules/core_api/fsw/inc/cfe_msg_api_typedefs.h
@@ -0,0 +1,116 @@
+/*
+** 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
+ *
+ * Typedefs for Message API
+ * - Separate from API so these can be adjusted for custom implementations
+ */
+
+#ifndef CFE_MSG_API_TYPEDEFS_H
+#define CFE_MSG_API_TYPEDEFS_H
+
+/*
+ * Includes
+ */
+#include "common_types.h"
+#include "cfe_error.h"
+
+/*
+ * Defines
+ */
+/* Error bits won't fit a new module so reuse SB error codes */
+#define CFE_MSG_BAD_ARGUMENT CFE_SB_BAD_ARGUMENT /**< \brief Error - bad argument */
+#define CFE_MSG_NOT_IMPLEMENTED CFE_SB_NOT_IMPLEMENTED /**< \brief Error - not implemented */
+#define CFE_MSG_WRONG_MSG_TYPE CFE_SB_WRONG_MSG_TYPE /**< \brief Error - wrong type */
+
+/*
+ * Types
+ */
+typedef size_t CFE_MSG_Size_t; /**< \brief Message size (CCSDS needs uint32 for max size) */
+typedef uint32 CFE_MSG_Checksum_t; /**< \brief Message checksum (Oversized to avoid redefine) */
+typedef uint16 CFE_MSG_FcnCode_t; /**< \brief Message function code */
+typedef uint16 CFE_MSG_HeaderVersion_t; /**< \brief Message header version */
+typedef uint16 CFE_MSG_ApId_t; /**< \brief Message application ID */
+typedef uint16 CFE_MSG_SequenceCount_t; /**< \brief Message sequence count */
+typedef uint16 CFE_MSG_EDSVersion_t; /**< \brief Message EDS version */
+typedef uint16 CFE_MSG_Subsystem_t; /**< \brief Message subsystem */
+typedef uint16 CFE_MSG_System_t; /**< \brief Message system */
+
+/** \brief Message type */
+typedef enum CFE_MSG_Type
+{
+ CFE_MSG_Type_Invalid, /**< \brief Message type invalid, undefined, not implemented */
+ CFE_MSG_Type_Cmd, /**< \brief Command message type */
+ CFE_MSG_Type_Tlm /**< \brief Telemetry message type */
+} CFE_MSG_Type_t;
+
+/** \brief Segmentation flags */
+typedef enum CFE_MSG_SegmentationFlag
+{
+ CFE_MSG_SegFlag_Invalid, /**< \brief Invalid segmentation flag */
+ CFE_MSG_SegFlag_Continue, /**< \brief Continuation segment of User Data */
+ CFE_MSG_SegFlag_First, /**< \brief First segment of User Data */
+ CFE_MSG_SegFlag_Last, /**< \brief Last segment of User Data */
+ CFE_MSG_SegFlag_Unsegmented /**< \brief Unsegemented data */
+} CFE_MSG_SegmentationFlag_t;
+
+/** \brief Endian flag */
+typedef enum CFE_MSG_Endian
+{
+ CFE_MSG_Endian_Invalid, /**< \brief Invalid endian setting */
+ CFE_MSG_Endian_Big, /**< \brief Big endian */
+ CFE_MSG_Endian_Little /**< \brief Little endian */
+} CFE_MSG_Endian_t;
+
+/** \brief Playback flag */
+typedef enum CFE_MSG_PlaybackFlag
+{
+ CFE_MSG_PlayFlag_Invalid, /**< \brief Invalid playback setting */
+ CFE_MSG_PlayFlag_Original, /**< \brief Original */
+ CFE_MSG_PlayFlag_Playback /**< \brief Playback */
+} CFE_MSG_PlaybackFlag_t;
+
+/*
+ * Abstract Message Base Types
+ *
+ * The concrete definition of these is provided by "cfe_msg_hdr.h" which is
+ * user-selectable depending on the actual desired message defintion. These
+ * abstract types are used in the API definition; the API is defined based
+ * on these abstract types, independent of the actual message definition.
+ */
+
+/**
+ * \brief cFS generic base message
+ */
+typedef union CFE_MSG_Message CFE_MSG_Message_t;
+
+/**
+ * \brief cFS command header
+ */
+typedef struct CFE_MSG_CommandHeader CFE_MSG_CommandHeader_t;
+
+/**
+ * \brief cFS telemetry header
+ */
+typedef struct CFE_MSG_TelemetryHeader CFE_MSG_TelemetryHeader_t;
+
+#endif /* CFE_MSG_API_TYPEDEFS_H */
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/msg/CMakeLists.txt b/modules/msg/CMakeLists.txt
new file mode 100644
index 000000000..9018021a1
--- /dev/null
+++ b/modules/msg/CMakeLists.txt
@@ -0,0 +1,68 @@
+##################################################################
+#
+# cFE message module CMake build recipe
+#
+# This CMakeLists.txt adds source files for
+# message 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.
+#
+##################################################################
+
+# Add the basic set of files which are always built
+# Defined as absolute so this list can also be used to build unit tests
+set(${DEP}_SRC
+ ${CMAKE_CURRENT_SOURCE_DIR}/fsw/src/cfe_msg_ccsdspri.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/fsw/src/cfe_msg_init.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/fsw/src/cfe_msg_msgid_shared.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/fsw/src/cfe_msg_sechdr_checksum.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/fsw/src/cfe_msg_sechdr_fc.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/fsw/src/cfe_msg_sechdr_time.c
+)
+
+# Source selection for if CCSDS extended header is included, and MsgId version use
+if (MISSION_INCLUDE_CCSDSEXT_HEADER)
+ message(STATUS "CCSDS primary and extended header included in message header")
+ list(APPEND ${DEP}_SRC
+ ${CMAKE_CURRENT_SOURCE_DIR}/fsw/src/cfe_msg_ccsdsext.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/fsw/src/cfe_msg_initdefaulthdr_priext.c)
+ if (MISSION_MSGID_V2) # MsgId v2 or v1 can be used with extended headers
+ message(STATUS "Message Id version 2 in use (MsgId V2)")
+ list(APPEND ${DEP}_SRC
+ ${CMAKE_CURRENT_SOURCE_DIR}/fsw/src/cfe_msg_msgid_v2.c)
+ else (MISSION_MSGID_V2)
+ message(STATUS "Message Id version 1 in use (MsgId V1)")
+ list(APPEND ${DEP}_SRC
+ ${CMAKE_CURRENT_SOURCE_DIR}/fsw/src/cfe_msg_msgid_v1.c)
+ endif (MISSION_MSGID_V2)
+else (MISSION_INCLUDE_CCSDSEXT_HEADER)
+ message(STATUS "CCSDS primary header included in message header (not including CCSDS extended header)")
+ message(STATUS "Message Id version 1 in use (MsgId V1)")
+ list(APPEND ${DEP}_SRC
+ ${CMAKE_CURRENT_SOURCE_DIR}/fsw/src/cfe_msg_initdefaulthdr_pri.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/fsw/src/cfe_msg_msgid_v1.c)
+ if (MISSION_MSGID_V2)
+ message(FATAL_ERROR "Message Id (MsgId) version 2 can only be used if MISSION_INCLUDE_CCSDSEXT_HEADER is set")
+ endif (MISSION_MSGID_V2)
+endif (MISSION_INCLUDE_CCSDSEXT_HEADER)
+
+# Module library
+add_library(${DEP} STATIC ${${DEP}_SRC})
+
+target_include_directories(${DEP} PUBLIC fsw/inc)
+
+target_link_libraries(${DEP} 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}
+ ccsds_hdr.h
+ cfe_msg_api_typedefs.h
+)
diff --git a/modules/msg/fsw/inc/ccsds_hdr.h b/modules/msg/fsw/inc/ccsds_hdr.h
new file mode 100644
index 000000000..9aaaa3b01
--- /dev/null
+++ b/modules/msg/fsw/inc/ccsds_hdr.h
@@ -0,0 +1,92 @@
+/*
+** 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
+ *
+ * Define CCSDS packet header types
+ * - Avoid direct access for portability, use APIs
+ * - Used to construct message structures
+ */
+
+#ifndef CCSDS_HDR_H
+#define CCSDS_HDR_H
+
+/*
+ * Include Files
+ */
+
+#include "common_types.h"
+
+/*
+ * Type Definitions
+ */
+
+/**********************************************************************
+ * Structure definitions for CCSDS headers.
+ *
+ * CCSDS headers must always be in network byte order per the standard.
+ * MSB at the lowest address which is commonly refered to as "BIG Endian"
+ *
+ */
+
+/**
+ * \brief CCSDS packet primary header
+ */
+typedef struct CCSDS_PrimaryHeader
+{
+
+ uint8 StreamId[2]; /**< \brief packet identifier word (stream ID) */
+ /* bits shift ------------ description ---------------- */
+ /* 0x07FF 0 : application ID */
+ /* 0x0800 11 : secondary header: 0 = absent, 1 = present */
+ /* 0x1000 12 : packet type: 0 = TLM, 1 = CMD */
+ /* 0xE000 13 : CCSDS version: 0 = ver 1, 1 = ver 2 */
+
+ uint8 Sequence[2]; /**< \brief packet sequence word */
+ /* bits shift ------------ description ---------------- */
+ /* 0x3FFF 0 : sequence count */
+ /* 0xC000 14 : segmentation flags: 3 = complete packet */
+
+ uint8 Length[2]; /**< \brief packet length word */
+ /* bits shift ------------ description ---------------- */
+ /* 0xFFFF 0 : (total packet length) - 7 */
+
+} CCSDS_PrimaryHeader_t;
+
+/**
+ * \brief CCSDS packet extended header
+ */
+typedef struct CCSDS_ExtendedHeader
+{
+
+ uint8 Subsystem[2]; /**< \brief subsystem qualifier */
+ /* bits shift ------------ description ---------------- */
+ /* 0x01FF 0 : Subsystem Id mission defined */
+ /* 0x0200 9 : Playback flag 0 = original, 1 = playback */
+ /* 0x0400 10 : Endian: Big = 0, Little (Intel) = 1 */
+ /* 0xF800 11 : EDS Version for packet definition used */
+
+ uint8 SystemId[2]; /**< \brief system qualifier */
+ /* 0xFFFF 0 : System Id mission defined */
+
+} CCSDS_ExtendedHeader_t;
+
+#endif /* CCSDS_HDR_H */
diff --git a/modules/msg/fsw/src/cfe_msg_ccsdsext.c b/modules/msg/fsw/src/cfe_msg_ccsdsext.c
new file mode 100644
index 000000000..e8b91684b
--- /dev/null
+++ b/modules/msg/fsw/src/cfe_msg_ccsdsext.c
@@ -0,0 +1,251 @@
+/*
+** 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.
+*/
+
+/******************************************************************************
+ * Message CCSDS extended header implementations
+ */
+#include "cfe_msg.h"
+#include "cfe_msg_priv.h"
+#include "cfe_msg_defaults.h"
+#include "cfe_error.h"
+#include "cfe_psp.h"
+
+/* CCSDS Extended definitions */
+#define CFE_MSG_EDSVER_SHIFT 11 /**< \brief CCSDS EDS version shift */
+#define CFE_MSG_EDSVER_MASK 0xF800 /**< \brief CCSDS EDS version mask */
+#define CFE_MSG_ENDIAN_MASK 0x0400 /**< \brief CCSDS endiam mask, little endian when set */
+#define CFE_MSG_PLAYBACK_MASK 0x0200 /**< \brief CCSDS playback flag, playback when set */
+#define CFE_MSG_SUBSYS_MASK 0x01FF /**< \brief CCSDS Subsystem mask */
+
+/******************************************************************************
+ * CCSDS extended header initialization - See header file for details
+ */
+void CFE_MSG_SetDefaultCCSDSExt(CFE_MSG_Message_t *MsgPtr)
+{
+
+ CFE_MSG_SetEDSVersion(MsgPtr, (CFE_MSG_EDSVersion_t)CFE_PLATFORM_EDSVER);
+
+#if (CFE_PLATFORM_ENDIAN == CCSDS_LITTLE_ENDIAN)
+ CFE_MSG_SetEndian(MsgPtr, CFE_MSG_Endian_Little);
+#else
+ CFE_MSG_SetEndian(MsgPtr, CFE_MSG_Endian_Big);
+#endif
+
+ /* Default bits of the subsystem, for whatever isn't set by MsgId */
+ CFE_MSG_SetSubsystem(MsgPtr, (CFE_MSG_Subsystem_t)CFE_PLATFORM_DEFAULT_SUBSYS);
+ CFE_MSG_SetSystem(MsgPtr, (CFE_MSG_System_t)CFE_PSP_GetSpacecraftId());
+}
+
+/******************************************************************************
+ * Get message EDS version - See API and header file for details
+ */
+int32 CFE_MSG_GetEDSVersion(const CFE_MSG_Message_t *MsgPtr, CFE_MSG_EDSVersion_t *Version)
+{
+
+ if (MsgPtr == NULL || Version == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ CFE_MSG_GetHeaderField(MsgPtr->CCSDS.Ext.Subsystem, Version, CFE_MSG_EDSVER_MASK);
+ *Version >>= CFE_MSG_EDSVER_SHIFT;
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+ * Set message EDS version - See API and header file for details
+ */
+int32 CFE_MSG_SetEDSVersion(CFE_MSG_Message_t *MsgPtr, CFE_MSG_EDSVersion_t Version)
+{
+ if (MsgPtr == NULL || (Version > (CFE_MSG_EDSVER_MASK >> CFE_MSG_EDSVER_SHIFT)))
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ CFE_MSG_SetHeaderField(MsgPtr->CCSDS.Ext.Subsystem, Version << CFE_MSG_EDSVER_SHIFT, CFE_MSG_EDSVER_MASK);
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+ * Get message endian - See API and header file for details
+ */
+int32 CFE_MSG_GetEndian(const CFE_MSG_Message_t *MsgPtr, CFE_MSG_Endian_t *Endian)
+{
+
+ if (MsgPtr == NULL || Endian == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ if ((MsgPtr->CCSDS.Ext.Subsystem[0] & (CFE_MSG_ENDIAN_MASK >> 8)) != 0)
+ {
+ *Endian = CFE_MSG_Endian_Little;
+ }
+ else
+ {
+ *Endian = CFE_MSG_Endian_Big;
+ }
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+ * Set message endian - See API and header file for details
+ */
+int32 CFE_MSG_SetEndian(CFE_MSG_Message_t *MsgPtr, CFE_MSG_Endian_t Endian)
+{
+ int32 status = CFE_SUCCESS;
+
+ if (MsgPtr == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ if (Endian == CFE_MSG_Endian_Little)
+ {
+ MsgPtr->CCSDS.Ext.Subsystem[0] |= CFE_MSG_ENDIAN_MASK >> 8;
+ }
+ else if (Endian == CFE_MSG_Endian_Big)
+ {
+ MsgPtr->CCSDS.Ext.Subsystem[0] &= ~(CFE_MSG_ENDIAN_MASK >> 8);
+ }
+ else
+ {
+ status = CFE_MSG_BAD_ARGUMENT;
+ }
+
+ return status;
+}
+
+/******************************************************************************
+ * Get message playback flag - See API and header file for details
+ */
+int32 CFE_MSG_GetPlaybackFlag(const CFE_MSG_Message_t *MsgPtr, CFE_MSG_PlaybackFlag_t *PlayFlag)
+{
+
+ if (MsgPtr == NULL || PlayFlag == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ if ((MsgPtr->CCSDS.Ext.Subsystem[0] & (CFE_MSG_PLAYBACK_MASK >> 8)) != 0)
+ {
+ *PlayFlag = CFE_MSG_PlayFlag_Playback;
+ }
+ else
+ {
+ *PlayFlag = CFE_MSG_PlayFlag_Original;
+ }
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+ * Set message playback flag - See API and header file for details
+ */
+int32 CFE_MSG_SetPlaybackFlag(CFE_MSG_Message_t *MsgPtr, CFE_MSG_PlaybackFlag_t PlayFlag)
+{
+ int32 status = CFE_SUCCESS;
+
+ if (MsgPtr == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ if (PlayFlag == CFE_MSG_PlayFlag_Playback)
+ {
+ MsgPtr->CCSDS.Ext.Subsystem[0] |= CFE_MSG_PLAYBACK_MASK >> 8;
+ }
+ else if (PlayFlag == CFE_MSG_PlayFlag_Original)
+ {
+ MsgPtr->CCSDS.Ext.Subsystem[0] &= ~(CFE_MSG_PLAYBACK_MASK >> 8);
+ }
+ else
+ {
+ status = CFE_MSG_BAD_ARGUMENT;
+ }
+
+ return status;
+}
+
+/******************************************************************************
+ * Get message subsystem - See API and header file for details
+ */
+int32 CFE_MSG_GetSubsystem(const CFE_MSG_Message_t *MsgPtr, CFE_MSG_Subsystem_t *Subsystem)
+{
+
+ if (MsgPtr == NULL || Subsystem == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ CFE_MSG_GetHeaderField(MsgPtr->CCSDS.Ext.Subsystem, Subsystem, CFE_MSG_SUBSYS_MASK);
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+ * Set message subsystem - See API and header file for details
+ */
+int32 CFE_MSG_SetSubsystem(CFE_MSG_Message_t *MsgPtr, CFE_MSG_Subsystem_t Subsystem)
+{
+ if (MsgPtr == NULL || ((Subsystem & ~CFE_MSG_SUBSYS_MASK) != 0))
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ CFE_MSG_SetHeaderField(MsgPtr->CCSDS.Ext.Subsystem, Subsystem, CFE_MSG_SUBSYS_MASK);
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+ * Get message system - See API and header file for details
+ */
+int32 CFE_MSG_GetSystem(const CFE_MSG_Message_t *MsgPtr, CFE_MSG_System_t *System)
+{
+
+ if (MsgPtr == NULL || System == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ *System = (MsgPtr->CCSDS.Ext.SystemId[0] << 8) + MsgPtr->CCSDS.Ext.SystemId[1];
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+ * Set message system - See API and header file for details
+ */
+int32 CFE_MSG_SetSystem(CFE_MSG_Message_t *MsgPtr, CFE_MSG_System_t System)
+{
+ if (MsgPtr == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ MsgPtr->CCSDS.Ext.SystemId[0] = (System >> 8) & 0xFF;
+ MsgPtr->CCSDS.Ext.SystemId[1] = System & 0xFF;
+
+ return CFE_SUCCESS;
+}
diff --git a/modules/msg/fsw/src/cfe_msg_ccsdspri.c b/modules/msg/fsw/src/cfe_msg_ccsdspri.c
new file mode 100644
index 000000000..780b93d23
--- /dev/null
+++ b/modules/msg/fsw/src/cfe_msg_ccsdspri.c
@@ -0,0 +1,352 @@
+/*
+** 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.
+*/
+
+/******************************************************************************
+ * Message CCSDS Primary header implementations
+ */
+#include "cfe_msg.h"
+#include "cfe_msg_priv.h"
+#include "cfe_msg_defaults.h"
+#include "cfe_error.h"
+
+/* CCSDS Primary Standard definitions */
+#define CFE_MSG_SIZE_OFFSET 7 /**< \brief CCSDS size offset */
+#define CFE_MSG_CCSDSVER_MASK 0xE000 /**< \brief CCSDS version mask */
+#define CFE_MSG_CCSDSVER_SHIFT 13 /**< \brief CCSDS version shift */
+#define CFE_MSG_TYPE_MASK 0x1000 /**< \brief CCSDS type mask, command when set */
+#define CFE_MSG_SHDR_MASK 0x0800 /**< \brief CCSDS secondary header mask, exists when set*/
+#define CFE_MSG_APID_MASK 0x07FF /**< \brief CCSDS ApID mask */
+#define CFE_MSG_SEGFLG_MASK 0xC000 /**< \brief CCSDS segmentation flag mask, all set = complete packet */
+#define CFE_MSG_SEGFLG_CNT 0x0000 /**< \brief CCSDS Segment continuation flag */
+#define CFE_MSG_SEGFLG_FIRST 0x4000 /**< \brief CCSDS Segment first flag */
+#define CFE_MSG_SEGFLG_LAST 0x8000 /**< \brief CCSDS Segment last flag */
+#define CFE_MSG_SEGFLG_UNSEG 0xC000 /**< \brief CCSDS Unsegmented flag */
+#define CFE_MSG_SEQCNT_MASK 0x3FFF /**< \brief CCSDS Sequence count mask */
+
+/******************************************************************************
+ * CCSDS Primary header initialization - See header file for details
+ */
+void CFE_MSG_SetDefaultCCSDSPri(CFE_MSG_Message_t *MsgPtr)
+{
+
+ /* cFS standard is for secondary header to be present */
+ CFE_MSG_SetHasSecondaryHeader(MsgPtr, true);
+
+ /* cFS standard for CCSDS Version */
+ CFE_MSG_SetHeaderVersion(MsgPtr, CFE_MISSION_CCSDSVER);
+
+ /* Default bits of the APID, for whatever isn't set by MsgId */
+ CFE_MSG_SetApId(MsgPtr, CFE_PLATFORM_DEFAULT_APID);
+
+ /* Default to complete packets */
+ CFE_MSG_SetSegmentationFlag(MsgPtr, CFE_MSG_SegFlag_Unsegmented);
+}
+
+/******************************************************************************
+ * Get message header version - See API and header file for details
+ */
+int32 CFE_MSG_GetHeaderVersion(const CFE_MSG_Message_t *MsgPtr, CFE_MSG_HeaderVersion_t *Version)
+{
+
+ if (MsgPtr == NULL || Version == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ CFE_MSG_GetHeaderField(MsgPtr->CCSDS.Pri.StreamId, Version, CFE_MSG_CCSDSVER_MASK);
+ *Version >>= CFE_MSG_CCSDSVER_SHIFT;
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+ * Set message header version - See API and header file for details
+ */
+int32 CFE_MSG_SetHeaderVersion(CFE_MSG_Message_t *MsgPtr, CFE_MSG_HeaderVersion_t Version)
+{
+ if (MsgPtr == NULL || (Version > (CFE_MSG_CCSDSVER_MASK >> CFE_MSG_CCSDSVER_SHIFT)))
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ CFE_MSG_SetHeaderField(MsgPtr->CCSDS.Pri.StreamId, Version << CFE_MSG_CCSDSVER_SHIFT, CFE_MSG_CCSDSVER_MASK);
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+ * Get message type - See API and header file for details
+ */
+int32 CFE_MSG_GetType(const CFE_MSG_Message_t *MsgPtr, CFE_MSG_Type_t *Type)
+{
+
+ if (MsgPtr == NULL || Type == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ if ((MsgPtr->CCSDS.Pri.StreamId[0] & (CFE_MSG_TYPE_MASK >> 8)) != 0)
+ {
+ *Type = CFE_MSG_Type_Cmd;
+ }
+ else
+ {
+ *Type = CFE_MSG_Type_Tlm;
+ }
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+ * Set message type - See API and header file for details
+ */
+int32 CFE_MSG_SetType(CFE_MSG_Message_t *MsgPtr, CFE_MSG_Type_t Type)
+{
+ int32 status = CFE_SUCCESS;
+
+ if (MsgPtr == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ if (Type == CFE_MSG_Type_Cmd)
+ {
+ MsgPtr->CCSDS.Pri.StreamId[0] |= CFE_MSG_TYPE_MASK >> 8;
+ }
+ else if (Type == CFE_MSG_Type_Tlm)
+ {
+ MsgPtr->CCSDS.Pri.StreamId[0] &= ~(CFE_MSG_TYPE_MASK >> 8);
+ }
+ else
+ {
+ status = CFE_MSG_BAD_ARGUMENT;
+ }
+
+ return status;
+}
+
+/******************************************************************************
+ * Get message has secondary header flag - See API and header file for details
+ */
+int32 CFE_MSG_GetHasSecondaryHeader(const CFE_MSG_Message_t *MsgPtr, bool *HasSecondary)
+{
+
+ if (MsgPtr == NULL || HasSecondary == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ *HasSecondary = (MsgPtr->CCSDS.Pri.StreamId[0] & (CFE_MSG_SHDR_MASK >> 8)) != 0;
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+ * Set message has secondary header flag - See API and header file for details
+ */
+int32 CFE_MSG_SetHasSecondaryHeader(CFE_MSG_Message_t *MsgPtr, bool HasSecondary)
+{
+ if (MsgPtr == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ if (HasSecondary)
+ {
+ MsgPtr->CCSDS.Pri.StreamId[0] |= CFE_MSG_SHDR_MASK >> 8;
+ }
+ else
+ {
+ MsgPtr->CCSDS.Pri.StreamId[0] &= ~(CFE_MSG_SHDR_MASK >> 8);
+ }
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+ * Get message application ID - See API and header file for details
+ */
+int32 CFE_MSG_GetApId(const CFE_MSG_Message_t *MsgPtr, CFE_MSG_ApId_t *ApId)
+{
+
+ if (MsgPtr == NULL || ApId == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ CFE_MSG_GetHeaderField(MsgPtr->CCSDS.Pri.StreamId, ApId, CFE_MSG_APID_MASK);
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+ * Set message application ID - See API and header file for details
+ */
+int32 CFE_MSG_SetApId(CFE_MSG_Message_t *MsgPtr, CFE_MSG_ApId_t ApId)
+{
+ if (MsgPtr == NULL || ((ApId & ~CFE_MSG_APID_MASK) != 0))
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ CFE_MSG_SetHeaderField(MsgPtr->CCSDS.Pri.StreamId, ApId, CFE_MSG_APID_MASK);
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+ * Get message segmentation flag - See API and header file for details
+ */
+int32 CFE_MSG_GetSegmentationFlag(const CFE_MSG_Message_t *MsgPtr, CFE_MSG_SegmentationFlag_t *SegFlag)
+{
+
+ uint16 rawval;
+
+ if (MsgPtr == NULL || SegFlag == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ CFE_MSG_GetHeaderField(MsgPtr->CCSDS.Pri.Sequence, &rawval, CFE_MSG_SEGFLG_MASK);
+
+ switch (rawval)
+ {
+ case CFE_MSG_SEGFLG_CNT:
+ *SegFlag = CFE_MSG_SegFlag_Continue;
+ break;
+ case CFE_MSG_SEGFLG_FIRST:
+ *SegFlag = CFE_MSG_SegFlag_First;
+ break;
+ case CFE_MSG_SEGFLG_LAST:
+ *SegFlag = CFE_MSG_SegFlag_Last;
+ break;
+ case CFE_MSG_SEGFLG_UNSEG:
+ default:
+ *SegFlag = CFE_MSG_SegFlag_Unsegmented;
+ }
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+ * Set message segmentation flag - See API and header file for details
+ */
+int32 CFE_MSG_SetSegmentationFlag(CFE_MSG_Message_t *MsgPtr, CFE_MSG_SegmentationFlag_t SegFlag)
+{
+ uint16 rawval = 0;
+ int32 status = CFE_SUCCESS;
+
+ if (MsgPtr == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ switch (SegFlag)
+ {
+ case CFE_MSG_SegFlag_Continue:
+ rawval = CFE_MSG_SEGFLG_CNT;
+ break;
+ case CFE_MSG_SegFlag_First:
+ rawval = CFE_MSG_SEGFLG_FIRST;
+ break;
+ case CFE_MSG_SegFlag_Last:
+ rawval = CFE_MSG_SEGFLG_LAST;
+ break;
+ case CFE_MSG_SegFlag_Unsegmented:
+ rawval = CFE_MSG_SEGFLG_UNSEG;
+ break;
+ case CFE_MSG_SegFlag_Invalid:
+ default:
+ status = CFE_MSG_BAD_ARGUMENT;
+ }
+
+ if (status == CFE_SUCCESS)
+ {
+ CFE_MSG_SetHeaderField(MsgPtr->CCSDS.Pri.Sequence, rawval, CFE_MSG_SEGFLG_MASK);
+ }
+
+ return status;
+}
+
+/******************************************************************************
+ * Get message sequence count - See API and header file for details
+ */
+int32 CFE_MSG_GetSequenceCount(const CFE_MSG_Message_t *MsgPtr, CFE_MSG_SequenceCount_t *SeqCnt)
+{
+
+ if (MsgPtr == NULL || SeqCnt == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ CFE_MSG_GetHeaderField(MsgPtr->CCSDS.Pri.Sequence, SeqCnt, CFE_MSG_SEQCNT_MASK);
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+ * Set message sequence count - See API and header file for details
+ */
+int32 CFE_MSG_SetSequenceCount(CFE_MSG_Message_t *MsgPtr, CFE_MSG_SequenceCount_t SeqCnt)
+{
+ if (MsgPtr == NULL || ((SeqCnt & ~CFE_MSG_SEQCNT_MASK) != 0))
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ CFE_MSG_SetHeaderField(MsgPtr->CCSDS.Pri.Sequence, SeqCnt, CFE_MSG_SEQCNT_MASK);
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+ * Get message size - See API and header file for details
+ */
+int32 CFE_MSG_GetSize(const CFE_MSG_Message_t *MsgPtr, CFE_MSG_Size_t *Size)
+{
+
+ if (MsgPtr == NULL || Size == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ *Size = (MsgPtr->CCSDS.Pri.Length[0] << 8) + MsgPtr->CCSDS.Pri.Length[1] + CFE_MSG_SIZE_OFFSET;
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+ * Set message size - See API and header file for details
+ */
+int32 CFE_MSG_SetSize(CFE_MSG_Message_t *MsgPtr, CFE_MSG_Size_t Size)
+{
+ if (MsgPtr == NULL || Size < CFE_MSG_SIZE_OFFSET || Size > (0xFFFF + CFE_MSG_SIZE_OFFSET))
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ /* Size is CCSDS header is total packet size - CFE_MSG_SIZE_OFFSET (7) */
+ Size -= CFE_MSG_SIZE_OFFSET;
+
+ MsgPtr->CCSDS.Pri.Length[0] = (Size >> 8) & 0xFF;
+ MsgPtr->CCSDS.Pri.Length[1] = Size & 0xFF;
+
+ return CFE_SUCCESS;
+}
diff --git a/modules/msg/fsw/src/cfe_msg_defaults.h b/modules/msg/fsw/src/cfe_msg_defaults.h
new file mode 100644
index 000000000..d667f6e5b
--- /dev/null
+++ b/modules/msg/fsw/src/cfe_msg_defaults.h
@@ -0,0 +1,83 @@
+/*
+** 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
+ *
+ * Message header defaults, used to initialize messages
+ * - Avoid including outside this module
+ */
+
+#ifndef CFE_MSG_DEFAULTS_H
+#define CFE_MSG_DEFAULTS_H
+
+/*
+ * Includes
+ */
+#include "cfe_platform_cfg.h"
+#include "cfe_mission_cfg.h"
+#include "cfe_msg_api_typedefs.h"
+
+/*
+ * Defines
+ */
+
+/* Backwards compatibility */
+#ifndef CFE_PLATFORM_DEFAULT_APID
+#define CFE_PLATFORM_DEFAULT_APID 0 /**< \brief Default APID, for bits not in MsgId */
+#endif
+
+#ifndef CFE_MISSION_CCSDSVER
+#define CFE_MISSION_CCSDSVER 0 /**< \brief Default CCSDS Version */
+#endif
+
+#ifndef CFE_PLATFORM_DEFAULT_SUBSYS
+#define CFE_PLATFORM_DEFAULT_SUBSYS 0 /**< \brief Default SubSystem, for bits not in MsgId */
+#endif
+
+#ifndef CFE_PLATFORM_EDSVER
+#define CFE_PLATFORM_EDSVER 1 /**< \brief Default EDS version, cFS historically = 1 */
+#endif
+
+/*****************************************************************************/
+/**
+ * \brief Set CCSDS Primary header defaults
+ *
+ * \par DESCRIPTION
+ * Only sets the constant defaults. Internal function assumes
+ * pointer is valid.
+ *
+ * \param[out] MsgPtr Message to set
+ */
+void CFE_MSG_SetDefaultCCSDSPri(CFE_MSG_Message_t *MsgPtr);
+
+/*****************************************************************************/
+/**
+ * \brief Set CCSDS Extended header defaults
+ *
+ * \par DESCRIPTION
+ * Only sets the constant defaults. Internal function assumes
+ * pointer is valid.
+ *
+ * \param[out] MsgPtr Message to set
+ */
+void CFE_MSG_SetDefaultCCSDSExt(CFE_MSG_Message_t *MsgPtr);
+
+#endif /* CFE_MSG_DEFAULTS_H */
diff --git a/modules/msg/fsw/src/cfe_msg_init.c b/modules/msg/fsw/src/cfe_msg_init.c
new file mode 100644
index 000000000..b116601d3
--- /dev/null
+++ b/modules/msg/fsw/src/cfe_msg_init.c
@@ -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.
+*/
+
+/******************************************************************************
+ * Message initialization
+ */
+#include "cfe_msg.h"
+#include "cfe_msg_priv.h"
+#include "cfe_msg_defaults.h"
+#include "string.h"
+
+/******************************************************************************
+ * Top level message initialization - See API and header file for details
+ */
+int32 CFE_MSG_Init(CFE_MSG_Message_t *MsgPtr, CFE_SB_MsgId_t MsgId, CFE_MSG_Size_t Size)
+{
+
+ int32 status;
+
+ if (MsgPtr == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ /* Clear and set defaults */
+ memset(MsgPtr, 0, Size);
+ CFE_MSG_InitDefaultHdr(MsgPtr);
+
+ /* Set values input */
+ status = CFE_MSG_SetMsgId(MsgPtr, MsgId);
+ if (status == CFE_SUCCESS)
+ {
+ status = CFE_MSG_SetSize(MsgPtr, Size);
+ }
+
+ return status;
+}
diff --git a/modules/msg/fsw/src/cfe_msg_initdefaulthdr_pri.c b/modules/msg/fsw/src/cfe_msg_initdefaulthdr_pri.c
new file mode 100644
index 000000000..2904ab1ef
--- /dev/null
+++ b/modules/msg/fsw/src/cfe_msg_initdefaulthdr_pri.c
@@ -0,0 +1,34 @@
+/*
+** 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.
+*/
+
+/******************************************************************************
+ * Message default header initialization - implementation without CCSDS
+ * extended header
+ */
+#include "cfe_msg_hdr.h"
+#include "cfe_msg_defaults.h"
+
+/******************************************************************************
+ * Top level message initialization - See header file for details
+ */
+void CFE_MSG_InitDefaultHdr(CFE_MSG_Message_t *MsgPtr)
+{
+ CFE_MSG_SetDefaultCCSDSPri(MsgPtr);
+}
diff --git a/modules/msg/fsw/src/cfe_msg_initdefaulthdr_priext.c b/modules/msg/fsw/src/cfe_msg_initdefaulthdr_priext.c
new file mode 100644
index 000000000..c11f15347
--- /dev/null
+++ b/modules/msg/fsw/src/cfe_msg_initdefaulthdr_priext.c
@@ -0,0 +1,35 @@
+/*
+** 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.
+*/
+
+/******************************************************************************
+ * Message default header initialization - implementation without CCSDS
+ * extended header
+ */
+#include "cfe_msg_hdr.h"
+#include "cfe_msg_defaults.h"
+
+/******************************************************************************
+ * Top level message initialization - See header file for details
+ */
+void CFE_MSG_InitDefaultHdr(CFE_MSG_Message_t *MsgPtr)
+{
+ CFE_MSG_SetDefaultCCSDSPri(MsgPtr);
+ CFE_MSG_SetDefaultCCSDSExt(MsgPtr);
+}
diff --git a/modules/msg/fsw/src/cfe_msg_msgid_shared.c b/modules/msg/fsw/src/cfe_msg_msgid_shared.c
new file mode 100644
index 000000000..5f721d677
--- /dev/null
+++ b/modules/msg/fsw/src/cfe_msg_msgid_shared.c
@@ -0,0 +1,49 @@
+/*
+** 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.
+*/
+
+/******************************************************************************
+ * Message id access functions, shared cFS implementation
+ */
+#include "cfe_msg.h"
+#include "cfe_msg_priv.h"
+#include "cfe_error.h"
+
+/******************************************************************************
+ * Get type from message id - See API and header file for details
+ * cFS default implementation
+ */
+int32 CFE_MSG_GetTypeFromMsgId(CFE_SB_MsgId_t MsgId, CFE_MSG_Type_t *Type)
+{
+
+ CFE_MSG_Message_t msg;
+
+ /* Memset to initialize avoids possible GCC bug 53119 */
+ memset(&msg, 0, sizeof(msg));
+
+ if (Type == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ CFE_MSG_SetMsgId(&msg, MsgId);
+ CFE_MSG_GetType(&msg, Type);
+
+ return CFE_SUCCESS;
+}
diff --git a/modules/msg/fsw/src/cfe_msg_msgid_v1.c b/modules/msg/fsw/src/cfe_msg_msgid_v1.c
new file mode 100644
index 000000000..fe8ef8156
--- /dev/null
+++ b/modules/msg/fsw/src/cfe_msg_msgid_v1.c
@@ -0,0 +1,73 @@
+/*
+** 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.
+*/
+
+/******************************************************************************
+ * Message id access functions, cFS version 1 implementation
+ */
+#include "cfe_msg.h"
+#include "cfe_msg_priv.h"
+#include "cfe_error.h"
+#include "cfe_platform_cfg.h"
+#include "cfe_sb.h"
+
+/******************************************************************************
+ * Get message id - See API and header file for details
+ * cFS default version 1 implementation using CCSDS headers
+ *
+ * Message Id = CCSDS Stream ID (in local endian)
+ */
+int32 CFE_MSG_GetMsgId(const CFE_MSG_Message_t *MsgPtr, CFE_SB_MsgId_t *MsgId)
+{
+
+ CFE_SB_MsgId_Atom_t msgidval;
+
+ if (MsgPtr == NULL || MsgId == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ msgidval = (MsgPtr->CCSDS.Pri.StreamId[0] << 8) + MsgPtr->CCSDS.Pri.StreamId[1];
+ *MsgId = CFE_SB_ValueToMsgId(msgidval);
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+ * Set message id - See API and header file for details
+ * cFS default version 1 implementations using CCSDS headers
+ *
+ * CCSDS Stream ID = Message Id converted to big endian
+ */
+int32 CFE_MSG_SetMsgId(CFE_MSG_Message_t *MsgPtr, CFE_SB_MsgId_t MsgId)
+{
+
+ CFE_SB_MsgId_Atom_t msgidval = CFE_SB_MsgIdToValue(MsgId);
+
+ if (MsgPtr == NULL || msgidval > CFE_PLATFORM_SB_HIGHEST_VALID_MSGID)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ /* Shift and mask bytes to be endian agnostic */
+ MsgPtr->CCSDS.Pri.StreamId[0] = (msgidval >> 8) & 0xFF;
+ MsgPtr->CCSDS.Pri.StreamId[1] = msgidval & 0xFF;
+
+ return CFE_SUCCESS;
+}
diff --git a/modules/msg/fsw/src/cfe_msg_msgid_v2.c b/modules/msg/fsw/src/cfe_msg_msgid_v2.c
new file mode 100644
index 000000000..4e2c3b3fc
--- /dev/null
+++ b/modules/msg/fsw/src/cfe_msg_msgid_v2.c
@@ -0,0 +1,111 @@
+/*
+** 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.
+*/
+
+/******************************************************************************
+ * Message id access functions
+ *
+ * cFS default version 2 implementation using CCSDS headers
+ *
+ * Message Id:
+ * 7 bits from the primary header APID (0x7F of 0x7FF)
+ * 1 bit for the command/telemetry flag
+ * 0 bits from the Playback flag
+ * 8 bits from the secondary header APID qualifier (Subsystem) (0xFF of 0x01FF)
+ * 0 bits from the secondary header APID qualifier as the System
+ * = 16 bits total
+ *
+ * Byte 1 Byte 0
+ * 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
+ * +-+-+-+-+-+-+-+-+|--------|+-+-+-+-+-+-+-+
+ * | APID Qualifier |C/T flg | Pri Hdr APID |
+ * +-+-+-+-+-+-+-+-+|--------|+-+-+-+-+-+-+-+
+ */
+#include "cfe_msg.h"
+#include "cfe_msg_priv.h"
+#include "cfe_error.h"
+#include "cfe_platform_cfg.h"
+
+/* cFS MsgId definitions */
+#define CFE_MSG_MSGID_APID_MASK 0x007F /**< \brief CCSDS ApId mask for MsgId */
+#define CFE_MSG_MSGID_TYPE_MASK 0x0080 /**< \brief Message type mask for MsgId, set = cmd */
+#define CFE_MSG_MSGID_SUBSYS_MASK 0xFF00 /**< \brief Subsystem mask for MsgId */
+
+/******************************************************************************
+ * Get message id - See API and header file for details
+ */
+int32 CFE_MSG_GetMsgId(const CFE_MSG_Message_t *MsgPtr, CFE_SB_MsgId_t *MsgId)
+{
+
+ CFE_SB_MsgId_Atom_t msgidval;
+ CFE_MSG_Type_t type;
+
+ if (MsgPtr == NULL || MsgId == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ /* Ignore return, assumes tlm if invalid */
+ CFE_MSG_GetType(MsgPtr, &type);
+
+ /* Set message ID bits from CCSDS header fields */
+ msgidval = MsgPtr->CCSDS.Pri.StreamId[1] & CFE_MSG_MSGID_APID_MASK;
+ if (type == CFE_MSG_Type_Cmd)
+ {
+ msgidval |= CFE_MSG_MSGID_TYPE_MASK;
+ }
+ msgidval |= (MsgPtr->CCSDS.Ext.Subsystem[1] << 8) & CFE_MSG_MSGID_SUBSYS_MASK;
+
+ *MsgId = CFE_SB_ValueToMsgId(msgidval);
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+ * Set message id - See API and header file for details
+ */
+int32 CFE_MSG_SetMsgId(CFE_MSG_Message_t *MsgPtr, CFE_SB_MsgId_t MsgId)
+{
+
+ CFE_SB_MsgId_Atom_t msgidval = CFE_SB_MsgIdToValue(MsgId);
+
+ if (MsgPtr == NULL || msgidval > CFE_PLATFORM_SB_HIGHEST_VALID_MSGID)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ /* Clear and set PID_MSGID_MASK bits */
+ MsgPtr->CCSDS.Pri.StreamId[1] =
+ (MsgPtr->CCSDS.Pri.StreamId[1] & ~CFE_MSG_MSGID_APID_MASK) | (msgidval & CFE_MSG_MSGID_APID_MASK);
+
+ /* Set APIDQ Subsystem bits */
+ MsgPtr->CCSDS.Ext.Subsystem[1] = ((msgidval & CFE_MSG_MSGID_SUBSYS_MASK) >> 8);
+
+ /* Set type, ignores return since no failure action */
+ if ((msgidval & CFE_MSG_MSGID_TYPE_MASK) != 0)
+ {
+ CFE_MSG_SetType(MsgPtr, CFE_MSG_Type_Cmd);
+ }
+ else
+ {
+ CFE_MSG_SetType(MsgPtr, CFE_MSG_Type_Tlm);
+ }
+
+ return CFE_SUCCESS;
+}
diff --git a/modules/msg/fsw/src/cfe_msg_priv.h b/modules/msg/fsw/src/cfe_msg_priv.h
new file mode 100644
index 000000000..6f992fa9c
--- /dev/null
+++ b/modules/msg/fsw/src/cfe_msg_priv.h
@@ -0,0 +1,84 @@
+/*
+** 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
+ *
+ * Message private header
+ * - Avoid including outside this module
+ */
+
+#ifndef CFE_MSG_PRIV_H
+#define CFE_MSG_PRIV_H
+
+/*
+ * Includes
+ */
+#include "common_types.h"
+#include "cfe_msg_hdr.h"
+
+/*****************************************************************************/
+/**
+ * \brief get generic header field (uint8 array[2])
+ *
+ * \par DESCRIPTION
+ * Big endian get of header field given mask. Only sets bits
+ * in value that are part of mask.
+ *
+ * \param[in] Word Header value to set
+ * \param[out] Val Value to set
+ * \param[in] Mask Mask used for set
+ */
+static inline void CFE_MSG_GetHeaderField(const uint8 *Word, uint16 *Val, uint16 Mask)
+{
+ *Val = (Word[0] << 8 | Word[1]) & Mask;
+}
+
+/*****************************************************************************/
+/**
+ * \brief Set generic header field (uint8 array[2])
+ *
+ * \par DESCRIPTION
+ * Big endian set of header field given value and mask. Only sets bits
+ * from value that are part of mask.
+ *
+ * \param[in, out] Word Header value to set
+ * \param[in] Val Value to set
+ * \param[in] Mask Mask used for set
+ */
+static inline void CFE_MSG_SetHeaderField(uint8 *Word, uint16 Val, uint16 Mask)
+{
+ Word[0] = (Word[0] & ~(Mask >> 8)) | ((Val & Mask) >> 8);
+ Word[1] = ((Word[1] & ~Mask) | (Val & Mask)) & 0xFF;
+}
+
+/*****************************************************************************/
+/**
+ * \brief Initialize default header - implemented based on selected header format
+ *
+ * \par DESCRIPTION
+ * Sets the constant defaults for the entire header. Internal function
+ * assumes pointer is valid.
+ *
+ * \param[out] MsgPtr Message to set
+ */
+void CFE_MSG_InitDefaultHdr(CFE_MSG_Message_t *MsgPtr);
+
+#endif /* CFE_MSG_PRIV_H */
diff --git a/modules/msg/fsw/src/cfe_msg_sechdr_checksum.c b/modules/msg/fsw/src/cfe_msg_sechdr_checksum.c
new file mode 100644
index 000000000..4a40d8ad5
--- /dev/null
+++ b/modules/msg/fsw/src/cfe_msg_sechdr_checksum.c
@@ -0,0 +1,117 @@
+/*
+** 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.
+*/
+
+/******************************************************************************
+ * Checksum field access functions
+ */
+#include "cfe_msg.h"
+#include "cfe_msg_priv.h"
+
+/******************************************************************************/
+/**
+ * \brief Compute checksum - internal utility
+ *
+ * \param[in] MsgPtr Message pointer to checksum
+ *
+ * \return Calculated checksum
+ */
+CFE_MSG_Checksum_t CFE_MSG_ComputeCheckSum(const CFE_MSG_Message_t *MsgPtr)
+{
+
+ CFE_MSG_Size_t PktLen = 0;
+ const uint8 * BytePtr = MsgPtr->Byte;
+ CFE_MSG_Checksum_t chksum = 0xFF;
+
+ /* Message already checked, no error case reachable */
+ CFE_MSG_GetSize(MsgPtr, &PktLen);
+
+ while (PktLen--)
+ {
+ chksum ^= *(BytePtr++);
+ }
+
+ return chksum;
+}
+
+/******************************************************************************
+ * Calculate and set checksum field - See API and header file for details
+ * Implementation supports cFS secondary definition or no secodary header
+ */
+int32 CFE_MSG_GenerateChecksum(CFE_MSG_Message_t *MsgPtr)
+{
+ uint32 status;
+ CFE_MSG_Type_t type;
+ bool hassechdr = false;
+ CFE_MSG_CommandHeader_t *cmd = (CFE_MSG_CommandHeader_t *)MsgPtr;
+
+ if (MsgPtr == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ /* Ignore return, pointer already checked */
+ CFE_MSG_GetHasSecondaryHeader(MsgPtr, &hassechdr);
+
+ status = CFE_MSG_GetType(MsgPtr, &type);
+ if (status != CFE_SUCCESS || type != CFE_MSG_Type_Cmd || !hassechdr)
+ {
+ return CFE_MSG_WRONG_MSG_TYPE;
+ }
+
+ /* Zero checksum so new checksum will be correct */
+ cmd->Sec.Checksum = 0;
+
+ /* Compute using aligned MsgPtr and set, suppress false style warning */
+ /* cppcheck-suppress redundantAssignment */
+ cmd->Sec.Checksum = CFE_MSG_ComputeCheckSum(MsgPtr);
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+ * Validate checksum - See API and header file for details
+ * Implementation supports cFS secondary definition or no secondary header
+ */
+int32 CFE_MSG_ValidateChecksum(const CFE_MSG_Message_t *MsgPtr, bool *IsValid)
+{
+
+ uint32 status;
+ CFE_MSG_Type_t type;
+ bool hassechdr = false;
+
+ if (MsgPtr == NULL || IsValid == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ /* Ignore return, pointer already checked */
+ CFE_MSG_GetHasSecondaryHeader(MsgPtr, &hassechdr);
+
+ status = CFE_MSG_GetType(MsgPtr, &type);
+ if (status != CFE_SUCCESS || type != CFE_MSG_Type_Cmd || !hassechdr)
+ {
+ return CFE_MSG_WRONG_MSG_TYPE;
+ }
+
+ /* Compute, valid if == 0 */
+ *IsValid = (CFE_MSG_ComputeCheckSum(MsgPtr) == 0);
+
+ return CFE_SUCCESS;
+}
diff --git a/modules/msg/fsw/src/cfe_msg_sechdr_fc.c b/modules/msg/fsw/src/cfe_msg_sechdr_fc.c
new file mode 100644
index 000000000..34cd53c21
--- /dev/null
+++ b/modules/msg/fsw/src/cfe_msg_sechdr_fc.c
@@ -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.
+*/
+
+/******************************************************************************
+ * Function code field access functions
+ */
+#include "cfe_msg.h"
+#include "cfe_msg_priv.h"
+
+#define CFE_MSG_FC_MASK 0x7F /**< \brief Function code mask */
+
+/******************************************************************************
+ * Get function code - See API and header file for details
+ * cFS default secondary header implementation
+ */
+int32 CFE_MSG_GetFcnCode(const CFE_MSG_Message_t *MsgPtr, CFE_MSG_FcnCode_t *FcnCode)
+{
+ uint32 status;
+ CFE_MSG_Type_t type;
+ bool hassechdr = false;
+ CFE_MSG_CommandHeader_t *cmd = (CFE_MSG_CommandHeader_t *)MsgPtr;
+
+ if (MsgPtr == NULL || FcnCode == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ /* Ignore return, pointer already checked */
+ CFE_MSG_GetHasSecondaryHeader(MsgPtr, &hassechdr);
+
+ status = CFE_MSG_GetType(MsgPtr, &type);
+ if (status != CFE_SUCCESS || type != CFE_MSG_Type_Cmd || !hassechdr)
+ {
+ *FcnCode = 0;
+ return CFE_MSG_WRONG_MSG_TYPE;
+ }
+
+ *FcnCode = cmd->Sec.FunctionCode & CFE_MSG_FC_MASK;
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+ * Set function code - See API and header file for details
+ * cFS default secondary header implementation
+ */
+int32 CFE_MSG_SetFcnCode(CFE_MSG_Message_t *MsgPtr, CFE_MSG_FcnCode_t FcnCode)
+{
+ uint32 status;
+ CFE_MSG_Type_t type;
+ bool hassechdr = false;
+ CFE_MSG_CommandHeader_t *cmd = (CFE_MSG_CommandHeader_t *)MsgPtr;
+
+ if (MsgPtr == NULL || (FcnCode > CFE_MSG_FC_MASK))
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ /* Ignore return, pointer already checked */
+ CFE_MSG_GetHasSecondaryHeader(MsgPtr, &hassechdr);
+
+ status = CFE_MSG_GetType(MsgPtr, &type);
+ if (status != CFE_SUCCESS || type != CFE_MSG_Type_Cmd || !hassechdr)
+ {
+ return CFE_MSG_WRONG_MSG_TYPE;
+ }
+
+ cmd->Sec.FunctionCode = FcnCode;
+
+ return CFE_SUCCESS;
+}
diff --git a/modules/msg/fsw/src/cfe_msg_sechdr_time.c b/modules/msg/fsw/src/cfe_msg_sechdr_time.c
new file mode 100644
index 000000000..314676709
--- /dev/null
+++ b/modules/msg/fsw/src/cfe_msg_sechdr_time.c
@@ -0,0 +1,97 @@
+/*
+** 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.
+*/
+
+/******************************************************************************
+ * Time field access functions - cFS default 32 bit seconds, 16 bit subseconds
+ * in big endian format
+ */
+#include "cfe_msg.h"
+#include "cfe_msg_priv.h"
+#include "cfe_error.h"
+#include
+
+/******************************************************************************
+ * Set message time - See API and header file for details
+ */
+int32 CFE_MSG_SetMsgTime(CFE_MSG_Message_t *MsgPtr, CFE_TIME_SysTime_t NewTime)
+{
+
+ uint32 status;
+ CFE_MSG_Type_t type;
+ bool hassechdr = false;
+ CFE_MSG_TelemetryHeader_t *tlm = (CFE_MSG_TelemetryHeader_t *)MsgPtr;
+
+ if (MsgPtr == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ /* Ignore return, pointer already checked */
+ CFE_MSG_GetHasSecondaryHeader(MsgPtr, &hassechdr);
+
+ status = CFE_MSG_GetType(MsgPtr, &type);
+ if (status != CFE_SUCCESS || type != CFE_MSG_Type_Tlm || !hassechdr)
+ {
+ return CFE_MSG_WRONG_MSG_TYPE;
+ }
+
+ /* Set big endian time field with default 32/16 layout */
+ tlm->Sec.Time[0] = (NewTime.Seconds >> 24) & 0xFF;
+ tlm->Sec.Time[1] = (NewTime.Seconds >> 16) & 0xFF;
+ tlm->Sec.Time[2] = (NewTime.Seconds >> 8) & 0xFF;
+ tlm->Sec.Time[3] = NewTime.Seconds & 0xFF;
+ tlm->Sec.Time[4] = (NewTime.Subseconds >> 24) & 0xFF;
+ tlm->Sec.Time[5] = (NewTime.Subseconds >> 16) & 0xFF;
+
+ return CFE_SUCCESS;
+}
+
+/******************************************************************************
+ * Get message time - See API and header file for details
+ */
+int32 CFE_MSG_GetMsgTime(const CFE_MSG_Message_t *MsgPtr, CFE_TIME_SysTime_t *Time)
+{
+
+ uint32 status;
+ CFE_MSG_Type_t type;
+ bool hassechdr = false;
+ CFE_MSG_TelemetryHeader_t *tlm = (CFE_MSG_TelemetryHeader_t *)MsgPtr;
+
+ if (MsgPtr == NULL || Time == NULL)
+ {
+ return CFE_MSG_BAD_ARGUMENT;
+ }
+
+ /* Ignore return, pointer already checked */
+ CFE_MSG_GetHasSecondaryHeader(MsgPtr, &hassechdr);
+
+ status = CFE_MSG_GetType(MsgPtr, &type);
+ if (status != CFE_SUCCESS || type != CFE_MSG_Type_Tlm || !hassechdr)
+ {
+ memset(Time, 0, sizeof(*Time));
+ return CFE_MSG_WRONG_MSG_TYPE;
+ }
+
+ /* Get big endian time fields with default 32/16 layout */
+ Time->Subseconds = (tlm->Sec.Time[4] << 24) + (tlm->Sec.Time[5] << 16);
+ Time->Seconds = (tlm->Sec.Time[0] << 24) + (tlm->Sec.Time[1] << 16) + (tlm->Sec.Time[2] << 8) + tlm->Sec.Time[3];
+
+ return CFE_SUCCESS;
+}
diff --git a/modules/msg/option_inc/default_cfe_msg_hdr_pri.h b/modules/msg/option_inc/default_cfe_msg_hdr_pri.h
new file mode 100644
index 000000000..ca27a0cd3
--- /dev/null
+++ b/modules/msg/option_inc/default_cfe_msg_hdr_pri.h
@@ -0,0 +1,94 @@
+/*
+** 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
+ *
+ * Define cFS standard full header
+ * - Avoid direct access for portability, use APIs
+ * - Used to construct message structures
+ */
+
+#ifndef DEFAULT_CFE_MSG_HDR_PRI_H
+#define DEFAULT_CFE_MSG_HDR_PRI_H
+
+/*
+ * Include Files
+ */
+
+#include "common_types.h"
+#include "ccsds_hdr.h"
+#include "cfe_msg_sechdr.h"
+#include "cfe_msg_api_typedefs.h"
+
+/*
+ * Type Definitions
+ */
+
+/**********************************************************************
+ * Structure definitions for full header
+ *
+ * These are based on historically supported definitions and not
+ * an open source standard.
+ */
+
+/**
+ * \brief Full CCSDS header
+ */
+typedef struct
+{
+ CCSDS_PrimaryHeader_t Pri; /**< \brief CCSDS Primary Header */
+} CCSDS_SpacePacket_t;
+
+/**
+ * \brief cFS generic base message
+ *
+ * This provides the definition of CFE_MSG_Message_t
+ */
+union CFE_MSG_Message
+{
+ CCSDS_SpacePacket_t CCSDS; /**< \brief CCSDS Header (Pri or Pri + Ext) */
+ uint8 Byte[sizeof(CCSDS_SpacePacket_t)]; /**< \brief Byte level access */
+};
+
+/**
+ * \brief cFS command header
+ *
+ * This provides the definition of CFE_MSG_CommandHeader_t
+ */
+struct CFE_MSG_CommandHeader
+{
+ CFE_MSG_Message_t Msg; /**< \brief Base message */
+ CFE_MSG_CommandSecondaryHeader_t Sec; /**< \brief Secondary header */
+};
+
+/**
+ * \brief cFS telemetry header
+ *
+ * This provides the definition of CFE_MSG_TelemetryHeader_t
+ */
+struct CFE_MSG_TelemetryHeader
+{
+ CFE_MSG_Message_t Msg; /**< \brief Base message */
+ CFE_MSG_TelemetrySecondaryHeader_t Sec; /**< \brief Secondary header */
+ uint8 Spare[4]; /**< \brief Padding to end on 64 bit boundary */
+};
+
+#endif /* DEFAULT_CFE_MSG_HDR_PRI_H */
diff --git a/modules/msg/option_inc/default_cfe_msg_hdr_priext.h b/modules/msg/option_inc/default_cfe_msg_hdr_priext.h
new file mode 100644
index 000000000..233f9c799
--- /dev/null
+++ b/modules/msg/option_inc/default_cfe_msg_hdr_priext.h
@@ -0,0 +1,92 @@
+/*
+** 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
+ *
+ * Define cFS standard full header
+ * - Avoid direct access for portability, use APIs
+ * - Used to construct message structures
+ */
+
+#ifndef DEFAULT_CFE_MSG_HDR_PRIEXT_H
+#define DEFAULT_CFE_MSG_HDR_PRIEXT_H
+
+/*
+ * Include Files
+ */
+
+#include "common_types.h"
+#include "ccsds_hdr.h"
+#include "cfe_msg_sechdr.h"
+
+/*
+ * Type Definitions
+ */
+
+/**********************************************************************
+ * Structure definitions for full header
+ *
+ * These are based on historically supported definitions and not
+ * an open source standard.
+ */
+
+/**
+ * \brief Full CCSDS header
+ */
+typedef struct
+{
+ CCSDS_PrimaryHeader_t Pri; /**< \brief CCSDS Primary Header */
+ CCSDS_ExtendedHeader_t Ext; /**< \brief CCSDS Extended Header */
+} CCSDS_SpacePacket_t;
+
+/**
+ * \brief cFS generic base message
+ */
+typedef union
+{
+ CCSDS_SpacePacket_t CCSDS; /**< \brief CCSDS Header (Pri or Pri + Ext) */
+ uint8 Byte[sizeof(CCSDS_SpacePacket_t)]; /**< \brief Byte level access */
+} CFE_MSG_Message_t;
+
+/**
+ * \brief cFS command header
+ */
+typedef struct
+{
+
+ CFE_MSG_Message_t Msg; /**< \brief Base message */
+ CFE_MSG_CommandSecondaryHeader_t Sec; /**< \brief Secondary header */
+ uint8 Spare[4]; /**< /brief Padding to end on 64 bit boundary */
+
+} CFE_MSG_CommandHeader_t;
+
+/**
+ * \brief cFS telemetry header
+ */
+typedef struct
+{
+
+ CFE_MSG_Message_t Msg; /**< \brief Base message */
+ CFE_MSG_TelemetrySecondaryHeader_t Sec; /**< \brief Secondary header */
+
+} CFE_MSG_TelemetryHeader_t;
+
+#endif /* DEFAULT_CFE_MSG_HDR_PRIEXT_H */
diff --git a/modules/msg/option_inc/default_cfe_msg_sechdr.h b/modules/msg/option_inc/default_cfe_msg_sechdr.h
new file mode 100644
index 000000000..a9356ecac
--- /dev/null
+++ b/modules/msg/option_inc/default_cfe_msg_sechdr.h
@@ -0,0 +1,79 @@
+/*
+** 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
+ *
+ * Define cFS standard secondary header
+ * - Avoid direct access for portability, use APIs
+ * - Used to construct message structures
+ */
+
+#ifndef DEFAULT_CFE_MSG_SECHDR_H
+#define DEFAULT_CFE_MSG_SECHDR_H
+
+/*
+ * Include Files
+ */
+
+#include "common_types.h"
+#include "cfe_mission_cfg.h"
+
+/*
+ * Defines
+ */
+
+/*
+ * Type Definitions
+ */
+
+/**********************************************************************
+ * Structure definitions for secondary headers
+ *
+ * These are based on historically supported definitions and not
+ * an open source standard.
+ */
+
+/**
+ * \brief cFS command secondary header
+ */
+typedef struct
+{
+
+ uint8 FunctionCode; /**< \brief Command Function Code */
+ /* bits shift ---------description-------- */
+ /* 0x7F 0 Command function code */
+ /* 0x80 7 Reserved */
+
+ uint8 Checksum; /**< \brief Command checksum (all bits, 0xFF) */
+
+} CFE_MSG_CommandSecondaryHeader_t;
+
+/**
+ * \brief cFS telemetry secondary header
+ */
+typedef struct
+{
+
+ uint8 Time[6]; /**< \brief Time, big endian: 4 byte seconds, 2 byte subseconds */
+
+} CFE_MSG_TelemetrySecondaryHeader_t;
+
+#endif /* DEFAULT_CFE_MSG_SECHDR_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);
+ }
+}