diff --git a/cmake/mission_build.cmake b/cmake/mission_build.cmake index c807836ec..83eb21b4b 100644 --- a/cmake/mission_build.cmake +++ b/cmake/mission_build.cmake @@ -131,7 +131,7 @@ function(prepare) # Each of those may in turn have a "mission_build" file that calls out additional dependencies for that app, # so this is run in a loop until the list of unfound apps is empty string(REPLACE ":" ";" CFS_APP_PATH "$ENV{CFS_APP_PATH}") - list(APPEND CFS_APP_PATH "apps" "apps/CFS" "libs" "psp/fsw/modules") + list(APPEND CFS_APP_PATH "apps" "apps/CFS" "libs" "psp/fsw/modules" "cfe/fsw/libs") set(MISSION_DEPS "cfe-core" "osal" ${MISSION_CORE_MODULES}) set(APP_MISSING_COUNT 0) diff --git a/fsw/libs/ccsds_msgformat/CMakeLists.txt b/fsw/libs/ccsds_msgformat/CMakeLists.txt new file mode 100644 index 000000000..509faee87 --- /dev/null +++ b/fsw/libs/ccsds_msgformat/CMakeLists.txt @@ -0,0 +1,15 @@ + +# Create the static module +add_library(ccsds_msgformat STATIC + src/ccsds_msgformat.c +) + +target_include_directories(ccsds_msgformat PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/inc +) + +# If UT is enabled, then add the tests from the subdirectory +if (ENABLE_UNIT_TESTS) +# add_subdirectory(unit-test) +endif (ENABLE_UNIT_TESTS) + diff --git a/fsw/libs/ccsds_msgformat/inc/ccsds_msgformat_accessors.h b/fsw/libs/ccsds_msgformat/inc/ccsds_msgformat_accessors.h new file mode 100644 index 000000000..cd7254ebb --- /dev/null +++ b/fsw/libs/ccsds_msgformat/inc/ccsds_msgformat_accessors.h @@ -0,0 +1,360 @@ +/* +** 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. +*/ + +#ifndef INCLUDE_CCSDS_MSGFORMAT_ACCESSORS_H +#define INCLUDE_CCSDS_MSGFORMAT_ACCESSORS_H + +/* + * the SB "extern typedefs" defines the CFE_SB_MsgAddress_t type, among others. + * This header should have minimal external dependencies. + */ +#include "cfe_sb_extern_typedefs.h" + +/* + * The "types" header defines the data structures specific to this format. + */ +#include "ccsds_msgformat_types.h" + +/* + * The "cfe_sb.h" file defines the header structures actually used in the CFE software bus. + * In particular it provides the "CCSDS_MsgFormat_BaseHeader_t" type, which may in turn include + * structures defined by the types header above. + */ +#include "cfe_sb.h" + + +/* ------------------------------------------------------------------------------ + * + * FIELD CONVERSION HELPERS + * + * These are invoked from CFE/FSW to convert between the abstract CFE representation of + * various field values and the representation defined/required by the message format + * + * Standard fields required by CFE: + * - MsgId: Address/endpoint/route designation, CFE_SB_MsgId_t + * - Size: Total size of the entire packet structure in memory, uint32 value + * - Sequence: Sequential packet counter, uint32 value + * - Time: Timestamp, Telemetry packets only, CFE_TIME_SysTime_t + * - FunctionCode: command/function identifier, Command packets only, uint16 value + * - Checksum: Error control field. Historically a uint16 in CFE SB API, but should + * be a completely abstract type to allow arbitrary error control data. + * + * ------------------------------------------------------------------------------ */ + + +/* Conversion of message address/APID field to a CFE_SB_MsgId_t */ +static inline void CCSDS_MsgFormat_AddressToMsgId(const CCSDS_MsgFormat_MsgAddress_t *MsgAddressBuf, CFE_SB_MsgId_t *MsgIdBuf) +{ + /* for backward compatibility, reconstruct the CFE_SB_MsgId_t number value with the bit meanings the same as CCSDSv1 */ + CFE_SB_MsgId_Atom_t MsgIdVal = (MsgAddressBuf->CmdFlag << 12) | (MsgAddressBuf->Apid & 0x7FF); + *MsgIdBuf = CFE_SB_ValueToMsgId(MsgIdVal); +} + +/* Conversion of CFE_SB_MsgId_t to message address/APID field */ +static inline void CCSDS_MsgFormat_MsgIdToAddress(const CFE_SB_MsgId_t *MsgIdBuf, CCSDS_MsgFormat_MsgAddress_t *MsgAddressBuf) +{ + /* for backward compatibility, deconstruct the CFE_SB_MsgId_t number value with the bit meanings the same as CCSDSv1 */ + CFE_SB_MsgId_Atom_t MsgIdVal = CFE_SB_MsgIdToValue(*MsgIdBuf); + MsgAddressBuf->Apid = (MsgIdVal & 0x7FF); + MsgAddressBuf->CmdFlag = (MsgIdVal >> 12) & 0x1; +} + +/* Convert the message length into a CFE abstract value */ +static inline void CCSDS_MsgFormat_MsgLengthToSize(const CCSDS_MsgFormat_Length_t *MsgLengthBuf, uint32 *SysSizeBuf) +{ + *SysSizeBuf = MsgLengthBuf->ExtraByteCount + 7; +} + +static inline void CCSDS_MsgFormat_SizeToMsgLength(const uint32 *SysSizeBuf, CCSDS_MsgFormat_Length_t *MsgLengthBuf) +{ + MsgLengthBuf->ExtraByteCount = *SysSizeBuf - 7; +} + +/* Convert the message sequence number into a CFE abstract value (pass through) */ +static inline void CCSDS_MsgFormat_MsgSequenceToValue(const CCSDS_MsgFormat_Sequence_t *MsgSeqBuf, uint32 *ValueBuf) +{ + *ValueBuf = MsgSeqBuf->Number; +} + +static inline void CCSDS_MsgFormat_ValueToMsgSequence(const uint32 *ValueBuf, CCSDS_MsgFormat_Sequence_t *MsgSeqBuf) +{ + MsgSeqBuf->Number = *ValueBuf; +} + +/* Convert the message time into a CFE time representation */ +static inline void CCSDS_MsgFormat_MsgTimeToSysTime(const CCSDS_MsgFormat_Time_t *MsgTimeBuf, CFE_TIME_SysTime_t *SysTimeBuf) +{ + SysTimeBuf->Seconds = MsgTimeBuf->Seconds; + SysTimeBuf->Subseconds = MsgTimeBuf->Subseconds16 << 16; +} + +static inline void CCSDS_MsgFormat_SysTimeToMsgTime(const CFE_TIME_SysTime_t *SysTimeBuf, CCSDS_MsgFormat_Time_t *MsgTimeBuf) +{ + MsgTimeBuf->Seconds = SysTimeBuf->Seconds; + MsgTimeBuf->Subseconds16 = SysTimeBuf->Subseconds >> 16; +} + +/* Convert the message function code into a CFE abstract value (pass through) */ +static inline void CCSDS_MsgFormat_MsgFunctionCodeToValue(const CCSDS_MsgFormat_FunctionCode_t *MsgFunctionCodeBuf, uint16 *ValueBuf) +{ + *ValueBuf = MsgFunctionCodeBuf->Code; +} + +static inline void CCSDS_MsgFormat_ValueToMsgFunctionCode(const uint16 *ValueBuf, CCSDS_MsgFormat_FunctionCode_t *MsgFunctionCodeBuf) +{ + MsgFunctionCodeBuf->Code = *ValueBuf; +} + + + +/** + * Calculate the difference between two sequence number values + * This takes into account the increment+modulo behavior of the sequence number field. + * + * When applied to two equal sequence numbers, the result is 0. + * If SequenceBuf1 represents 1 greater than SequenceBuf2, the result is 1. + * + * The result is positive if the SequenceBuf1 value is sequentially greater than SequenceBuf2. + * The result is negative if the SequenceBuf1 value is sequentially less than SequenceBuf2. + * (this is not a simple comparison, as the modulo/wrap-around has to be considered). + * + * @returns the difference between the two sequence numbers as a signed int + */ +static inline int32 CCSDS_MsgFormat_SequenceDifference(const CCSDS_MsgFormat_Sequence_t *SequenceBuf1, const CCSDS_MsgFormat_Sequence_t *SequenceBuf2) +{ + uint32 diff = SequenceBuf1->Number - SequenceBuf2->Number; + int32 result; + + /* sign-extend the result */ + result = (diff & 0x1FFF); + result -= (diff & 0x2000); + + return result; +} + +/** + * Check if two checksum values are equal + * One value is typically from the field within the packet, the other value is calculated from message content + * + * @returns true if the two checksum values are equal + */ +static inline bool CCSDS_MsgFormat_ChecksumCompare(const CCSDS_MsgFormat_Checksum_t *CheckBuf1, const CCSDS_MsgFormat_Checksum_t *CheckBuf2) +{ + return CheckBuf1->Checksum == CheckBuf2->Checksum; +} + +/** + * Convert error control field value to uint16 + * + * This is for backward compatibility with the CFE API that represents it this way. + * There is no reverse operation from a uint16. + * + * @returns the error control field info as a uint16. + */ +static inline uint16 CCSDS_MsgFormat_MsgChecksumToValue(const CCSDS_MsgFormat_Checksum_t *CheckBuf) +{ + return CheckBuf->Checksum; +} + + +/* ------------------------------------------------------------------------------ + * + * QUERY HELPERS + * + * These are invoked from CFE/FSW to query information about a given message. + * + * These are generally only "get" operations, as it is based on various other metadata + * within the message, these fields cannot be set directly. + * + * ------------------------------------------------------------------------------ */ + +/** + * Quickly determine whether a given message buffer is a telemetry type. + * @returns true if buffer represents a telemetry message with a TLM header. + */ +static inline bool CCSDS_MsgFormat_GetIsTelemetry(const CCSDS_MsgFormat_BaseHeader_t *BasePtr) +{ + return ((BasePtr->JStreamId[0] & CCSDS_MSGFORMAT_STREAMID_TYPE_MASK) == CCSDS_MSGFORMAT_STREAMID_TYPE_TELEMETRY); +} + +/** + * Quickly determine whether a given message buffer is a command type. + * @returns true if buffer represents a command message with a CMD header. + */ +static inline bool CCSDS_MsgFormat_GetIsCommand(const CCSDS_MsgFormat_BaseHeader_t *BasePtr) +{ + return ((BasePtr->JStreamId[0] & CCSDS_MSGFORMAT_STREAMID_TYPE_MASK) == CCSDS_MSGFORMAT_STREAMID_TYPE_COMMAND); +} + + +/* ------------------------------------------------------------------------------ + * + * GETTER/SETTER HELPERS + * + * These are invoked from CFE/FSW to actually read/write the values within a + * message structure. The I/O buffer should be of the type prescribed by the + * message format. A separate conversion function (above) can translate to the + * CFE abstract value where necessary. + * + * The return value should be an int32 status code, nominally CFE_SUCCESS. + * ------------------------------------------------------------------------------ */ + +/** + * Set all header fields in the message buffer to their initial state + */ +int32 CCSDS_MsgFormat_SetInitialFields(CCSDS_MsgFormat_BaseHeader_t *BasePtr, + uint32 TotalLength, + bool Clear); + +/** + * Get the message ID (abstract SB endpoint) from the message header + */ +int32 CCSDS_MsgFormat_GetMsgAddress(const CCSDS_MsgFormat_BaseHeader_t *BasePtr, CCSDS_MsgFormat_MsgAddress_t *MsgAddressBuf); + +/** + * Set the message ID (abstract SB endpoint) in the message header + */ +int32 CCSDS_MsgFormat_SetMsgAddress(CCSDS_MsgFormat_BaseHeader_t *BasePtr, const CCSDS_MsgFormat_MsgAddress_t *MsgAddressBuf); + +/** + * Get the size of the header data. + * This is not settable, it is fixed based on the message header format and type of message. + * + * This outputs the size of the actual header data, not including any alignment padding. + */ +int32 CCSDS_MsgFormat_GetHeaderLength(const CCSDS_MsgFormat_BaseHeader_t *BasePtr, uint32 *SizeBuf); + + +/** + * Get the total size of the complete message. + * + * This is the total size including all padding, from start of header to the end of the trailer. + * It should reflect the sizeof() of the C structure that represents the entire message + */ +int32 CCSDS_MsgFormat_GetTotalSize(const CCSDS_MsgFormat_BaseHeader_t *BasePtr, CCSDS_MsgFormat_Length_t *SizeBuf); + +/** + * Set the size of the payload data. + * + * This is the total size including all padding, from start of header to the end of the trailer. + * It should reflect the sizeof() of the C structure that represents the entire message + */ +int32 CCSDS_MsgFormat_SetTotalSize(CCSDS_MsgFormat_BaseHeader_t *BasePtr, const CCSDS_MsgFormat_Length_t *SizeBuf); + +/** + * Get the sequence number from the message header + */ +int32 CCSDS_MsgFormat_GetSequence(const CCSDS_MsgFormat_BaseHeader_t *BasePtr, CCSDS_MsgFormat_Sequence_t *SequenceBuf); + +/** + * Set the sequence number in the message header + */ +int32 CCSDS_MsgFormat_SetSequence(CCSDS_MsgFormat_BaseHeader_t *BasePtr, const CCSDS_MsgFormat_Sequence_t *SequenceBuf); + + +/** + * Get the timestamp of the telemetry message + */ +int32 CCSDS_MsgFormat_GetTlmTimestamp(const CCSDS_MsgFormat_TlmSecHdr_t *TlmPtr, CCSDS_MsgFormat_Time_t *TimeBuf); + +/** + * Get the timestamp of the message, if applicable. + * + * If the message header contains a timestamp, this gets the timestamp. + * Returns an error code if message format does not contain a timestamp. + */ +int32 CCSDS_MsgFormat_GetTimestamp(const CCSDS_MsgFormat_BaseHeader_t *BasePtr, CCSDS_MsgFormat_Time_t *TimeBuf); + +/** + * Set the timestamp of the telemetry message + */ +int32 CCSDS_MsgFormat_SetTlmTimestamp(CCSDS_MsgFormat_TlmSecHdr_t *TlmPtr, const CCSDS_MsgFormat_Time_t *TimeBuf); + +/** + * Set the timestamp of the message, if applicable. + * + * If the message header contains a timestamp, this sets the field to the given value + * Returns an error code if message format does not contain a timestamp. + */ +int32 CCSDS_MsgFormat_SetTimestamp(CCSDS_MsgFormat_BaseHeader_t *BasePtr, const CCSDS_MsgFormat_Time_t *TimeBuf); + +/** + * Get the Function Code of the command message + */ +int32 CCSDS_MsgFormat_GetCmdFunctionCode(const CCSDS_MsgFormat_CmdSecHdr_t *CmdPtr, CCSDS_MsgFormat_FunctionCode_t *CodeBuf); + +/** + * Get the Function Code of the message, if applicable. + * + * If the message header contains a function or command code number, this sets the field to the given value + * Returns an error code if message format does not contain a function code. + */ +int32 CCSDS_MsgFormat_GetFunctionCode(const CCSDS_MsgFormat_BaseHeader_t *BasePtr, CCSDS_MsgFormat_FunctionCode_t *CodeBuf); + +/** + * Set the Function Code of the command message + */ +int32 CCSDS_MsgFormat_SetCmdFunctionCode(CCSDS_MsgFormat_CmdSecHdr_t *CmdPtr, const CCSDS_MsgFormat_FunctionCode_t *CodeBuf); + +/** + * Set the Function Code of the message, if applicable. + * + * If the message header contains a function or command code number, this sets the field to the given value + * Returns an error code if message format does not contain a function code. + */ +int32 CCSDS_MsgFormat_SetFunctionCode(CCSDS_MsgFormat_BaseHeader_t *BasePtr, const CCSDS_MsgFormat_FunctionCode_t *CodeBuf); + +/** + * Reads the error control / checksum field of the command message + */ +int32 CCSDS_MsgFormat_GetCmdChecksum(const CCSDS_MsgFormat_CmdSecHdr_t *CmdPtr, CCSDS_MsgFormat_Checksum_t *ChecksumBuf); + +/** + * Reads the error control / checksum field, if applicable + * + * If the message header contains an error control field, this retrieves the value of that field + * Returns an error code if message format does not contain an error control field. + */ +int32 CCSDS_MsgFormat_GetChecksum(const CCSDS_MsgFormat_BaseHeader_t *BasePtr, CCSDS_MsgFormat_Checksum_t *ChecksumBuf); + +/** + * Reads the error control / checksum field of the command message + */ +int32 CCSDS_MsgFormat_SetCmdChecksum(CCSDS_MsgFormat_CmdSecHdr_t *CmdPtr, const CCSDS_MsgFormat_Checksum_t *ChecksumBuf); + +/** + * Reads the error control / checksum field, if applicable + * + * If the message header contains an error control field, this retrieves the value of that field + * Returns an error code if message format does not contain an error control field. + */ +int32 CCSDS_MsgFormat_SetChecksum(CCSDS_MsgFormat_BaseHeader_t *BasePtr, const CCSDS_MsgFormat_Checksum_t *ChecksumBuf); + +/** + * Compute the value for the error control / checksum field + */ +CCSDS_MsgFormat_Checksum_t CCSDS_MsgFormat_ComputeChecksum_Impl(const CCSDS_MsgFormat_BaseHeader_t *BasePtr, uint32 ChecksumOffset); + +/** + * Compute the error control / checksum field, if applicable + */ +int32 CCSDS_MsgFormat_GetComputedChecksum(const CCSDS_MsgFormat_BaseHeader_t *BasePtr, CCSDS_MsgFormat_Checksum_t *ChecksumBuf); + +#endif /* INCLUDE_CCSDS_MSGFORMAT_ACCESSORS_H */ diff --git a/fsw/libs/ccsds_msgformat/inc/ccsds_msgformat_types.h b/fsw/libs/ccsds_msgformat/inc/ccsds_msgformat_types.h new file mode 100644 index 000000000..aa6f37e96 --- /dev/null +++ b/fsw/libs/ccsds_msgformat/inc/ccsds_msgformat_types.h @@ -0,0 +1,138 @@ +/* +** 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. +*/ + +#ifndef INCLUDE_CCSDS_MSGFORMAT_TYPES_H +#define INCLUDE_CCSDS_MSGFORMAT_TYPES_H + +#include + +/* +** Type Definitions +*/ + +typedef struct +{ + uint8 Checksum; +} CCSDS_MsgFormat_Checksum_t; + + +typedef struct +{ + uint8 Code; +} CCSDS_MsgFormat_FunctionCode_t; + +typedef struct +{ + uint16 Number; +} CCSDS_MsgFormat_Sequence_t; + + +typedef struct +{ + uint16 ExtraByteCount; +} CCSDS_MsgFormat_Length_t; + + +typedef struct +{ + uint32 Seconds; + uint16 Subseconds16; +} CCSDS_MsgFormat_Time_t; + +typedef struct +{ + uint16 Apid; + uint8 CmdFlag; /* set to 1 for command address, 0 for telemetry address */ +} CCSDS_MsgFormat_MsgAddress_t; + + + +/*----- CCSDS packet primary header. -----*/ + +typedef struct { + + uint8 JStreamId[2]; /* 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 JSequence[2]; /* packet sequence word */ + /* bits shift ------------ description ---------------- */ + /* 0x3FFF 0 : sequence count */ + /* 0xC000 14 : segmentation flags: 3 = complete packet */ + + uint8 JLength[2]; /* packet length word */ + /* bits shift ------------ description ---------------- */ + /* 0xFFFF 0 : (total packet length) - 7 */ + +} CCSDS_MsgFormat_BaseHeader_t; + +/* + * Macros to aid in checking the type bits within StreamId[0] + */ +#define CCSDS_MSGFORMAT_STREAMID_TYPE_MASK 0xF8 +#define CCSDS_MSGFORMAT_STREAMID_TYPE_COMMAND 0x18 +#define CCSDS_MSGFORMAT_STREAMID_TYPE_TELEMETRY 0x08 + + + +/*----- CCSDS command secondary header. -----*/ + +typedef struct { + + uint8 JFunctionCode; /* Command Function Code */ + /* bits shift ---------description-------- */ + /* 0x7F 0 Command function code */ + /* 0x80 7 Reserved */ + + uint8 JChecksum; /* Command checksum (all bits, 0xFF) */ + +} CCSDS_MsgFormat_CmdSecHdr_t; + +/*----- CCSDS telemetry secondary header. -----*/ + +typedef struct { + + uint8 JTime[8]; + +} CCSDS_MsgFormat_TlmSecHdr_t; + + +/*----- Generic combined command header. -----*/ + +typedef struct +{ + CCSDS_MsgFormat_BaseHeader_t Base; /**< \brief Standard Header on all packets */ + CCSDS_MsgFormat_CmdSecHdr_t Sec; +} CCSDS_MsgFormat_CommandPacket_t; + +/*----- Generic combined telemetry header. -----*/ + +typedef struct +{ + CCSDS_MsgFormat_BaseHeader_t Base; /**< \brief Standard Header on all packets */ + CCSDS_MsgFormat_TlmSecHdr_t Sec; +} CCSDS_MsgFormat_TelemetryPacket_t; + + + +#endif /* INCLUDE_CCSDS_MSGFORMAT_TYPES_H */ diff --git a/fsw/libs/ccsds_msgformat/src/ccsds_msgformat.c b/fsw/libs/ccsds_msgformat/src/ccsds_msgformat.c new file mode 100644 index 000000000..19c17b711 --- /dev/null +++ b/fsw/libs/ccsds_msgformat/src/ccsds_msgformat.c @@ -0,0 +1,565 @@ +/* +** 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 +#include + +#include "ccsds_msgformat_accessors.h" +#include "cfe_error.h" + + +int32 CCSDS_MsgFormat_SetInitialFields(CCSDS_MsgFormat_BaseHeader_t *BasePtr, + uint32 TotalLength, + bool Clear) +{ + CCSDS_MsgFormat_Sequence_t PreservedSeq; + CCSDS_MsgFormat_Length_t MsgLen; + uint32 SysMsgSize; + + /* Zero the entire packet if needed. */ + if (Clear) + { + memset(BasePtr, 0, TotalLength); + } + else /* Clear only the primary header. */ + { + /* Save the sequence count in case it must be preserved. */ + CCSDS_MsgFormat_GetSequence(BasePtr, &PreservedSeq); + + memset(BasePtr, 0, sizeof(*BasePtr)); + } + + /* Set the length fields in the primary header. */ + SysMsgSize = TotalLength; + CCSDS_MsgFormat_SizeToMsgLength(&SysMsgSize, &MsgLen); + CCSDS_MsgFormat_SetTotalSize(BasePtr, &MsgLen); + + /* Restore the sequence count if needed. */ + if (!Clear) + { + CCSDS_MsgFormat_SetSequence(BasePtr, &PreservedSeq); + } + + return CFE_SUCCESS; +} + + +/* + * GETTER/SETTER Functions --- + * The general pattern should be to use an IO buffer parameter (pointer) for the value to get/set + * The return value should be an int32 status code, nominally CFE_SUCCESS. + */ + +/** + * Get the message ID (abstract SB endpoint) from the message header + */ +int32 CCSDS_MsgFormat_GetMsgAddress(const CCSDS_MsgFormat_BaseHeader_t *BasePtr, CCSDS_MsgFormat_MsgAddress_t *MsgAddressBuf) +{ + uint32 LocalReg; + + LocalReg = BasePtr->JStreamId[0]; + + /* Extract the CMD/TLM flag bits from this byte */ + if ((LocalReg & CCSDS_MSGFORMAT_STREAMID_TYPE_MASK) == CCSDS_MSGFORMAT_STREAMID_TYPE_TELEMETRY) + { + MsgAddressBuf->CmdFlag = 0; + } + else if ((LocalReg & CCSDS_MSGFORMAT_STREAMID_TYPE_MASK) == CCSDS_MSGFORMAT_STREAMID_TYPE_TELEMETRY) + { + MsgAddressBuf->CmdFlag = 1; + } + else + { + /* unrecognized first byte - bad version or other unacceptable value */ + return CFE_SB_NOT_IMPLEMENTED; + } + + LocalReg <<= 8; + LocalReg |= BasePtr->JStreamId[1]; + MsgAddressBuf->Apid = LocalReg & 0x07FF; + + return CFE_SUCCESS; +} + +/** + * Set the message ID (abstract SB endpoint) in the message header + */ +int32 CCSDS_MsgFormat_SetMsgAddress(CCSDS_MsgFormat_BaseHeader_t *BasePtr, const CCSDS_MsgFormat_MsgAddress_t *MsgAddressBuf) +{ + uint32 LocalReg; + + LocalReg = MsgAddressBuf->Apid; + BasePtr->JStreamId[1] = LocalReg & 0xFF; + LocalReg >>= 8; + + /* merge the CMD/TLM flag bits into the next byte */ + if (MsgAddressBuf->CmdFlag) + { + LocalReg |= CCSDS_MSGFORMAT_STREAMID_TYPE_COMMAND; + } + else + { + LocalReg |= CCSDS_MSGFORMAT_STREAMID_TYPE_TELEMETRY; + } + + BasePtr->JStreamId[0] = (BasePtr->JStreamId[0] & 0xE0) | (LocalReg & 0x1F); + + return CFE_SUCCESS; +} + +/** + * Get the sequence number from the message header + */ +int32 CCSDS_MsgFormat_GetSequence(const CCSDS_MsgFormat_BaseHeader_t *BasePtr, CCSDS_MsgFormat_Sequence_t *SequenceBuf) +{ + uint32 LocalReg; + + LocalReg = BasePtr->JSequence[0]; + LocalReg <<= 8; + LocalReg |= BasePtr->JSequence[1]; + SequenceBuf->Number = LocalReg & 0x3FFF; + + return -1; +} + +/** + * Set the sequence number in the message header + */ +int32 CCSDS_MsgFormat_SetSequence(CCSDS_MsgFormat_BaseHeader_t *BasePtr, const CCSDS_MsgFormat_Sequence_t *SequenceBuf) +{ + uint32 LocalReg; + + LocalReg = SequenceBuf->Number; + BasePtr->JSequence[1] = LocalReg & 0xFF; + LocalReg >>= 8; + BasePtr->JSequence[0] = (BasePtr->JStreamId[0] & ~0x3F) | (LocalReg & 0x3F); + + return CFE_SUCCESS; +} + + +/** + * Get the size of the header data. + * This is not settable, it is fixed based on the message header format and type of message. + * + * This outputs the size of the actual header data, not including any alignment padding. + */ +int32 CCSDS_MsgFormat_GetHeaderLength(const CCSDS_MsgFormat_BaseHeader_t *BasePtr, uint32 *SizeBuf) +{ + if (CCSDS_MsgFormat_GetIsCommand(BasePtr)) + { + *SizeBuf = sizeof(CCSDS_MsgFormat_CommandPacket_t); + } + else if (CCSDS_MsgFormat_GetIsTelemetry(BasePtr)) + { + *SizeBuf = sizeof(CCSDS_MsgFormat_TelemetryPacket_t); + } + else + { + /* fallback - should not be possible in CFE */ + *SizeBuf = sizeof(CCSDS_MsgFormat_BaseHeader_t); + } + + return CFE_SUCCESS; +} + + +/** + * Get the offset of the payload data. + * This is not settable, it is fixed based on the message header format and type of message. + * + * Note this is not necessarily the same as "GetHdrSize", as padding may need to exist + * between the header and payload to satisfy local CPU architecture requirements. + * + * This outputs the offset at which the actual payload data starts within the data structure. + */ +int32 CCSDS_MsgFormat_GetPayloadOffset(const CCSDS_MsgFormat_BaseHeader_t *BasePtr, uint32 *OffsetBuf) +{ + return -1; +} + + +/** + * Get the size of the payload data. + * + * This outputs the size of the actual payload data, not including any alignment padding. + */ +int32 CCSDS_MsgFormat_GetPayloadLength(const CCSDS_MsgFormat_BaseHeader_t *BasePtr, uint32 *SizeBuf) +{ + return -1; +} + + +/** + * Set the size of the payload data. + * + * This should be the size of the actual payload data, not including any alignment padding + */ +int32 CCSDS_MsgFormat_SetPayloadLength(CCSDS_MsgFormat_BaseHeader_t *BasePtr, uint32 Size) +{ + return -1; +} + +int32 CCSDS_MsgFormat_GetPayloadArea(const CCSDS_MsgFormat_BaseHeader_t *BasePtr, uint32 *PayloadOffsetBuf, uint32 *PayloadLenBuf) +{ + return -1; +} + + +/** + * Get the total size of the complete message. + * + * This is the total size including all padding, from start of header to the end of the trailer. + * It should reflect the sizeof() of the C structure that represents the entire message + */ +int32 CCSDS_MsgFormat_GetTotalSize(const CCSDS_MsgFormat_BaseHeader_t *BasePtr, CCSDS_MsgFormat_Length_t *SizeBuf) +{ + uint32 LocalReg; + + LocalReg = BasePtr->JLength[0]; + LocalReg <<= 8; + LocalReg |= BasePtr->JLength[1]; + SizeBuf->ExtraByteCount = LocalReg; + + return CFE_SUCCESS; +} + + +/** + * Set the size of the payload data. + * + * This is the total size including all padding, from start of header to the end of the trailer. + * It should reflect the sizeof() of the C structure that represents the entire message + */ +int32 CCSDS_MsgFormat_SetTotalSize(CCSDS_MsgFormat_BaseHeader_t *BasePtr, const CCSDS_MsgFormat_Length_t *SizeBuf) +{ + uint32 LocalReg; + + LocalReg = SizeBuf->ExtraByteCount; + BasePtr->JLength[1] = LocalReg & 0xFF; + LocalReg >>= 8; + BasePtr->JLength[0] = LocalReg & 0xFF; + + return CFE_SUCCESS; +} + + +/** + * Get the timestamp of the message, if applicable. + * + * If the message header contains a timestamp, this gets the timestamp. + * Returns an error code if message format does not contain a timestamp. + */ +int32 CCSDS_MsgFormat_GetTlmTimestamp(const CCSDS_MsgFormat_TlmSecHdr_t *TlmPtr, CCSDS_MsgFormat_Time_t *TimeBuf) +{ + uint32 LocalReg; + + LocalReg = TlmPtr->JTime[0]; + LocalReg <<= 8; + LocalReg |= TlmPtr->JTime[1]; + LocalReg <<= 8; + LocalReg |= TlmPtr->JTime[2]; + LocalReg <<= 8; + LocalReg |= TlmPtr->JTime[3]; + TimeBuf->Seconds = LocalReg; + + LocalReg = TlmPtr->JTime[4]; + LocalReg <<= 8; + LocalReg |= TlmPtr->JTime[5]; + TimeBuf->Subseconds16 = LocalReg; + + return CFE_SUCCESS; +} + + +/** + * Get the timestamp of the message, if applicable. + * + * If the message header contains a timestamp, this gets the timestamp. + * Returns an error code if message format does not contain a timestamp. + */ +int32 CCSDS_MsgFormat_GetTimestamp(const CCSDS_MsgFormat_BaseHeader_t *BasePtr, CCSDS_MsgFormat_Time_t *TimeBuf) +{ + const CCSDS_MsgFormat_TelemetryPacket_t* TlmMsg; + + /* Check that the msg is a TLM type */ + if (!CCSDS_MsgFormat_GetIsTelemetry(BasePtr)) + { + return CFE_SB_WRONG_MSG_TYPE; + } + + TlmMsg = (const CCSDS_MsgFormat_TelemetryPacket_t*)BasePtr; + + return CCSDS_MsgFormat_GetTlmTimestamp(&TlmMsg->Sec, TimeBuf); +} + +/** + * Set the timestamp of the message, if applicable. + * + * If the message header contains a timestamp, this sets the field to the given value + * Returns an error code if message format does not contain a timestamp. + */ +int32 CCSDS_MsgFormat_SetTlmTimestamp(CCSDS_MsgFormat_TlmSecHdr_t *TlmPtr, const CCSDS_MsgFormat_Time_t *Time) +{ + uint32 LocalReg; + + LocalReg = Time->Subseconds16; + TlmPtr->JTime[5] = LocalReg & 0xFF; + LocalReg >>= 8; + TlmPtr->JTime[4] = LocalReg & 0xFF; + + LocalReg = Time->Seconds; + TlmPtr->JTime[3] = LocalReg & 0xFF; + LocalReg >>= 8; + TlmPtr->JTime[2] = LocalReg & 0xFF; + LocalReg >>= 8; + TlmPtr->JTime[1] = LocalReg & 0xFF; + LocalReg >>= 8; + TlmPtr->JTime[0] = LocalReg & 0xFF; + + return CFE_SUCCESS; +} + +/** + * Set the timestamp of the message, if applicable. + * + * If the message header contains a timestamp, this sets the field to the given value + * Returns an error code if message format does not contain a timestamp. + */ +int32 CCSDS_MsgFormat_SetTimestamp(CCSDS_MsgFormat_BaseHeader_t *BasePtr, const CCSDS_MsgFormat_Time_t *Time) +{ + CCSDS_MsgFormat_TelemetryPacket_t* TlmMsg; + + /* Check that the msg is a TLM type */ + if (!CCSDS_MsgFormat_GetIsTelemetry(BasePtr)) + { + return CFE_SB_WRONG_MSG_TYPE; + } + + TlmMsg = (CCSDS_MsgFormat_TelemetryPacket_t*)BasePtr; + + return CCSDS_MsgFormat_SetTlmTimestamp(&TlmMsg->Sec, Time); +} + +/** + * Get the Function Code of the message, if applicable. + * + * If the message header contains a function or command code number, this sets the field to the given value + * Returns an error code if message format does not contain a function code. + */ +int32 CCSDS_MsgFormat_GetCmdFunctionCode(const CCSDS_MsgFormat_CmdSecHdr_t *CmdPtr, CCSDS_MsgFormat_FunctionCode_t *CodeBuf) +{ + CodeBuf->Code = CmdPtr->JFunctionCode & 0x7F; + return CFE_SUCCESS; +} + +/** + * Get the Function Code of the message, if applicable. + * + * If the message header contains a function or command code number, this sets the field to the given value + * Returns an error code if message format does not contain a function code. + */ +int32 CCSDS_MsgFormat_GetFunctionCode(const CCSDS_MsgFormat_BaseHeader_t *BasePtr, CCSDS_MsgFormat_FunctionCode_t *CodeBuf) +{ + CCSDS_MsgFormat_CommandPacket_t* CmdMsg; + + /* Check that the msg is a CMD type */ + if (!CCSDS_MsgFormat_GetIsCommand(BasePtr)) + { + return CFE_SB_WRONG_MSG_TYPE; + } + + CmdMsg = (CCSDS_MsgFormat_CommandPacket_t*)BasePtr; + + return CCSDS_MsgFormat_GetCmdFunctionCode(&CmdMsg->Sec, CodeBuf); +} + +/** + * Set the Function Code of the message, if applicable. + * + * If the message header contains a function or command code number, this sets the field to the given value + * Returns an error code if message format does not contain a function code. + */ +int32 CCSDS_MsgFormat_SetCmdFunctionCode(CCSDS_MsgFormat_CmdSecHdr_t *CmdPtr, const CCSDS_MsgFormat_FunctionCode_t *CodeBuf) +{ + CmdPtr->JFunctionCode = (CmdPtr->JFunctionCode & 0x80) | (CodeBuf->Code & 0x7F); + return CFE_SUCCESS; +} + + +/** + * Set the Function Code of the message, if applicable. + * + * If the message header contains a function or command code number, this sets the field to the given value + * Returns an error code if message format does not contain a function code. + */ +int32 CCSDS_MsgFormat_SetFunctionCode(CCSDS_MsgFormat_BaseHeader_t *BasePtr, const CCSDS_MsgFormat_FunctionCode_t *CodeBuf) +{ + CCSDS_MsgFormat_CommandPacket_t* CmdMsg; + + /* Check that the msg is a CMD type */ + if (!CCSDS_MsgFormat_GetIsCommand(BasePtr)) + { + return CFE_SB_WRONG_MSG_TYPE; + } + + CmdMsg = (CCSDS_MsgFormat_CommandPacket_t*)BasePtr; + + return CCSDS_MsgFormat_SetCmdFunctionCode(&CmdMsg->Sec, CodeBuf); +} + + +CCSDS_MsgFormat_Checksum_t CCSDS_MsgFormat_ComputeChecksum_Impl(const CCSDS_MsgFormat_BaseHeader_t *BasePtr, uint32 ChecksumOffset) +{ + const uint8 *PacketData; + CCSDS_MsgFormat_Length_t LengthBuf; + uint32 TotalLength; + uint32 Pos; + uint8 Byte; + CCSDS_MsgFormat_Checksum_t Val; + + PacketData = (const uint8*)BasePtr; + Val.Checksum = 0xFF; + + if (CCSDS_MsgFormat_GetTotalSize(BasePtr, &LengthBuf) == CFE_SUCCESS) + { + CCSDS_MsgFormat_MsgLengthToSize(&LengthBuf, &TotalLength); + } + else + { + TotalLength = 0; + } + + for (Pos = 0; Pos < TotalLength; ++Pos, ++PacketData) + { + /* + * When computing the checksum value, + * pad the checksum field itself with a zero. + */ + if (Pos == ChecksumOffset) + { + Byte = 0; + } + else + { + Byte = *PacketData; + } + + Val.Checksum ^= Byte; + } + + return Val; +} + +/** + * Reads the error control / checksum command field + */ +int32 CCSDS_MsgFormat_GetCmdChecksum(const CCSDS_MsgFormat_CmdSecHdr_t *CmdPtr, CCSDS_MsgFormat_Checksum_t *ChecksumBuf) +{ + ChecksumBuf->Checksum = CmdPtr->JChecksum; + return CFE_SUCCESS; +} + +/** + * Reads the error control / checksum field, if applicable + * + * If the message header contains an error control field, this retrieves the value of that field + * Returns an error code if message format does not contain an error control field. + */ +int32 CCSDS_MsgFormat_GetChecksum(const CCSDS_MsgFormat_BaseHeader_t *BasePtr, CCSDS_MsgFormat_Checksum_t *ChecksumBuf) +{ + const CCSDS_MsgFormat_CommandPacket_t* CmdMsg; + + /* Check that the msg is a CMD type */ + if (!CCSDS_MsgFormat_GetIsCommand(BasePtr)) + { + return CFE_SB_WRONG_MSG_TYPE; + } + + CmdMsg = (const CCSDS_MsgFormat_CommandPacket_t*)BasePtr; + + return CCSDS_MsgFormat_GetCmdChecksum(&CmdMsg->Sec, ChecksumBuf); +} + +/** + * Reads the error control / checksum field of the command message + */ +int32 CCSDS_MsgFormat_SetCmdChecksum(CCSDS_MsgFormat_CmdSecHdr_t *CmdPtr, const CCSDS_MsgFormat_Checksum_t *ChecksumBuf) +{ + CmdPtr->JChecksum = ChecksumBuf->Checksum; + return CFE_SUCCESS; +} + +/** + * Reads the error control / checksum field, if applicable + * + * If the message header contains an error control field, this retrieves the value of that field + * Returns an error code if message format does not contain an error control field. + */ +int32 CCSDS_MsgFormat_SetChecksum(CCSDS_MsgFormat_BaseHeader_t *BasePtr, const CCSDS_MsgFormat_Checksum_t *ChecksumBuf) +{ + CCSDS_MsgFormat_CommandPacket_t* CmdMsg; + + /* Check that the msg is a CMD type */ + if (!CCSDS_MsgFormat_GetIsCommand(BasePtr)) + { + return CFE_SB_WRONG_MSG_TYPE; + } + + CmdMsg = (CCSDS_MsgFormat_CommandPacket_t*)BasePtr; + + return CCSDS_MsgFormat_SetCmdChecksum(&CmdMsg->Sec, ChecksumBuf); +} + + +/** + * Compute the error control / checksum field, if applicable + */ +int32 CCSDS_MsgFormat_GetComputedChecksum(const CCSDS_MsgFormat_BaseHeader_t *BasePtr, CCSDS_MsgFormat_Checksum_t *ChecksumBuf) +{ + /* Check that the msg is a CMD type */ + if (!CCSDS_MsgFormat_GetIsCommand(BasePtr)) + { + /* no checksum field, nothing to do */ + return CFE_SB_WRONG_MSG_TYPE; + } + + *ChecksumBuf = CCSDS_MsgFormat_ComputeChecksum_Impl(BasePtr, + offsetof(CCSDS_MsgFormat_CommandPacket_t, Sec.JChecksum)); + + return CFE_SUCCESS; +} + diff --git a/fsw/libs/exthdr_msgformat/CMakeLists.txt b/fsw/libs/exthdr_msgformat/CMakeLists.txt new file mode 100644 index 000000000..8303648da --- /dev/null +++ b/fsw/libs/exthdr_msgformat/CMakeLists.txt @@ -0,0 +1,15 @@ + +# Create the static module +add_library(exthdr_msgformat STATIC + src/exthdr_msgformat.c +) + +target_include_directories(exthdr_msgformat PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/inc +) + +# If UT is enabled, then add the tests from the subdirectory +if (ENABLE_UNIT_TESTS) +# add_subdirectory(unit-test) +endif (ENABLE_UNIT_TESTS) + diff --git a/fsw/libs/exthdr_msgformat/inc/exthdr_msgformat_accessors.h b/fsw/libs/exthdr_msgformat/inc/exthdr_msgformat_accessors.h new file mode 100644 index 000000000..2b07716c1 --- /dev/null +++ b/fsw/libs/exthdr_msgformat/inc/exthdr_msgformat_accessors.h @@ -0,0 +1,355 @@ +/* +** 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. +*/ + +#ifndef INCLUDE_JPH_EXTHDR_MSGFORMAT_ACCESSORS_H +#define INCLUDE_JPH_EXTHDR_MSGFORMAT_ACCESSORS_H + +/* + * the SB "extern typedefs" defines the CFE_SB_MsgAddress_t type, among others. + * This header should have minimal external dependencies. + */ +#include "cfe_sb_extern_typedefs.h" + +/* + * The "types" header defines the data structures specific to this format. + */ +#include "exthdr_msgformat_types.h" +#include "ccsds_msgformat_accessors.h" + +/* + * The "cfe_sb.h" file defines the header structures actually used in the CFE software bus. + * In particular it provides the "ExtHdr_MsgFormat_BaseHeader_t" type, which may in turn include + * structures defined by the types header above. + */ +#include "cfe_sb.h" + + +/* ------------------------------------------------------------------------------ + * + * FIELD CONVERSION HELPERS + * + * These are invoked from CFE/FSW to convert between the abstract CFE representation of + * various field values and the representation defined/required by the message format + * + * Standard fields required by CFE: + * - MsgId: Address/endpoint/route designation, CFE_SB_MsgId_t + * - Size: Total size of the entire packet structure in memory, uint32 value + * - Sequence: Sequential packet counter, uint32 value + * - Time: Timestamp, Telemetry packets only, CFE_TIME_SysTime_t + * - FunctionCode: command/function identifier, Command packets only, uint16 value + * - Checksum: Error control field. Historically a uint16 in CFE SB API, but should + * be a completely abstract type to allow arbitrary error control data. + * + * ------------------------------------------------------------------------------ */ + + +/* Conversion of message address/APID field to a CFE_SB_MsgId_t */ +static inline void ExtHdr_MsgFormat_AddressToMsgId(const ExtHdr_MsgFormat_MsgAddress_t *MsgAddressBuf, CFE_SB_MsgId_t *MsgIdBuf) +{ + CFE_SB_MsgId_Atom_t MsgIdVal; + + /* + * In order to keep within the original 16 bit size, the MsgId bits are organized as: + * - 0x00FF - Bits [7:0] of APID from primary (base) header + * - 0x0F00 - Bits [3:0] of SubSystemId from APIDQ (extended) header + * - 0x1000 - Command (1) / Telemetry (0) flag bit. Kept in the "traditional" location for now. + * - 0xE000 - Bits [6:4] of SubSystemId from APIDQ (extended) header + * + * The "SystemId" bits are not currently used, but could be used as needed. + */ + + MsgIdVal = MsgAddressBuf->Base.Apid & 0x7FF; + MsgIdVal |= ((CFE_SB_MsgId_Atom_t)MsgAddressBuf->SubSysId & 0x0F) << 8; + MsgIdVal |= ((CFE_SB_MsgId_Atom_t)MsgAddressBuf->Base.CmdFlag & 0x01) << 12; + MsgIdVal |= ((CFE_SB_MsgId_Atom_t)MsgAddressBuf->SubSysId & 0x70) << 9; + + *MsgIdBuf = CFE_SB_ValueToMsgId(MsgIdVal); +} + +/* Conversion of CFE_SB_MsgId_t to message address/APID field */ +static inline void ExtHdr_MsgFormat_MsgIdToAddress(const CFE_SB_MsgId_t *MsgIdBuf, ExtHdr_MsgFormat_MsgAddress_t *MsgAddressBuf) +{ + CFE_SB_MsgId_Atom_t MsgIdVal; + + MsgIdVal = CFE_SB_MsgIdToValue(*MsgIdBuf); + + MsgAddressBuf->Base.Apid = MsgIdVal & 0x7FF; + MsgAddressBuf->Base.CmdFlag = (MsgIdVal >> 12) & 0x01; + MsgAddressBuf->SubSysId = (MsgIdVal >> 8) & 0x0F; + MsgAddressBuf->SubSysId |= (MsgIdVal >> 9) & 0x70; + MsgAddressBuf->SystemId = 0; /* not in MsgId for now */ +} + +/* Convert the message length into a CFE abstract value */ +static inline void ExtHdr_MsgFormat_MsgLengthToSize(const ExtHdr_MsgFormat_Length_t *MsgLengthBuf, uint32 *SysSizeBuf) +{ + /* pass through */ + CCSDS_MsgFormat_MsgLengthToSize(MsgLengthBuf, SysSizeBuf); +} + +static inline void ExtHdr_MsgFormat_SizeToMsgLength(const uint32 *SysSizeBuf, ExtHdr_MsgFormat_Length_t *MsgLengthBuf) +{ + CCSDS_MsgFormat_SizeToMsgLength(SysSizeBuf, MsgLengthBuf); +} + +/* Convert the message sequence number into a CFE abstract value (pass through) */ +static inline void ExtHdr_MsgFormat_MsgSequenceToValue(const ExtHdr_MsgFormat_Sequence_t *MsgSeqBuf, uint32 *ValueBuf) +{ + CCSDS_MsgFormat_MsgSequenceToValue(MsgSeqBuf, ValueBuf); +} + +static inline void ExtHdr_MsgFormat_ValueToMsgSequence(const uint32 *ValueBuf, ExtHdr_MsgFormat_Sequence_t *MsgSeqBuf) +{ + CCSDS_MsgFormat_ValueToMsgSequence(ValueBuf, MsgSeqBuf); +} + +/* Convert the message time into a CFE time representation */ +static inline void ExtHdr_MsgFormat_MsgTimeToSysTime(const ExtHdr_MsgFormat_Time_t *MsgTimeBuf, CFE_TIME_SysTime_t *SysTimeBuf) +{ + CCSDS_MsgFormat_MsgTimeToSysTime(MsgTimeBuf, SysTimeBuf); +} + +static inline void ExtHdr_MsgFormat_SysTimeToMsgTime(const CFE_TIME_SysTime_t *SysTimeBuf, ExtHdr_MsgFormat_Time_t *MsgTimeBuf) +{ + CCSDS_MsgFormat_SysTimeToMsgTime(SysTimeBuf, MsgTimeBuf); +} + +/* Convert the message function code into a CFE abstract value (pass through) */ +static inline void ExtHdr_MsgFormat_MsgFunctionCodeToValue(const ExtHdr_MsgFormat_FunctionCode_t *MsgFunctionCodeBuf, uint16 *ValueBuf) +{ + CCSDS_MsgFormat_MsgFunctionCodeToValue(MsgFunctionCodeBuf, ValueBuf); +} + +static inline void ExtHdr_MsgFormat_ValueToMsgFunctionCode(const uint16 *ValueBuf, ExtHdr_MsgFormat_FunctionCode_t *MsgFunctionCodeBuf) +{ + CCSDS_MsgFormat_ValueToMsgFunctionCode(ValueBuf, MsgFunctionCodeBuf); +} + + + +/** + * Calculate the difference between two sequence number values + * This takes into account the increment+modulo behavior of the sequence number field. + * + * When applied to two equal sequence numbers, the result is 0. + * If SequenceBuf1 represents 1 greater than SequenceBuf2, the result is 1. + * + * The result is positive if the SequenceBuf1 value is sequentially greater than SequenceBuf2. + * The result is negative if the SequenceBuf1 value is sequentially less than SequenceBuf2. + * (this is not a simple comparison, as the modulo/wrap-around has to be considered). + * + * @returns the difference between the two sequence numbers as a signed int + */ +static inline int32 ExtHdr_MsgFormat_SequenceDifference(const ExtHdr_MsgFormat_Sequence_t *SequenceBuf1, const ExtHdr_MsgFormat_Sequence_t *SequenceBuf2) +{ + return CCSDS_MsgFormat_SequenceDifference(SequenceBuf1, SequenceBuf2); +} + +/** + * Check if two checksum values are equal + * One value is typically from the field within the packet, the other value is calculated from message content + * + * @returns true if the two checksum values are equal + */ +static inline bool ExtHdr_MsgFormat_ChecksumCompare(const ExtHdr_MsgFormat_Checksum_t *CheckBuf1, const ExtHdr_MsgFormat_Checksum_t *CheckBuf2) +{ + return CCSDS_MsgFormat_ChecksumCompare(CheckBuf1, CheckBuf2); +} + +/** + * Convert error control field value to uint16 + * + * This is for backward compatibility with the CFE API that represents it this way. + * There is no reverse operation from a uint16. + * + * @returns the error control field info as a uint16. + */ +static inline uint16 ExtHdr_MsgFormat_MsgChecksumToValue(const ExtHdr_MsgFormat_Checksum_t *CheckBuf) +{ + return CCSDS_MsgFormat_MsgChecksumToValue(CheckBuf); +} + + +/* ------------------------------------------------------------------------------ + * + * QUERY HELPERS + * + * These are invoked from CFE/FSW to query information about a given message. + * + * These are generally only "get" operations, as it is based on various other metadata + * within the message, these fields cannot be set directly. + * + * ------------------------------------------------------------------------------ */ + +/** + * Quickly determine whether a given message buffer is a telemetry type. + * @returns true if buffer represents a telemetry message with a TLM header. + */ +static inline bool ExtHdr_MsgFormat_GetIsTelemetry(const ExtHdr_MsgFormat_BaseHeader_t *BasePtr) +{ + return CCSDS_MsgFormat_GetIsTelemetry(&BasePtr->Base); +} + +/** + * Quickly determine whether a given message buffer is a command type. + * @returns true if buffer represents a command message with a CMD header. + */ +static inline bool ExtHdr_MsgFormat_GetIsCommand(const ExtHdr_MsgFormat_BaseHeader_t *BasePtr) +{ + return CCSDS_MsgFormat_GetIsCommand(&BasePtr->Base); +} + + +/* ------------------------------------------------------------------------------ + * + * GETTER/SETTER HELPERS + * + * These are invoked from CFE/FSW to actually read/write the values within a + * message structure. The I/O buffer should be of the type prescribed by the + * message format. A separate conversion function (above) can translate to the + * CFE abstract value where necessary. + * + * The return value should be an int32 status code, nominally CFE_SUCCESS. + * ------------------------------------------------------------------------------ */ + +/** + * Set all header fields in the message buffer to their initial state + */ +int32 ExtHdr_MsgFormat_SetInitialFields(ExtHdr_MsgFormat_BaseHeader_t *BasePtr, + uint32 TotalLength, + bool Clear); + +/** + * Get the message ID (abstract SB endpoint) from the message header + */ +int32 ExtHdr_MsgFormat_GetMsgAddress(const ExtHdr_MsgFormat_BaseHeader_t *BasePtr, ExtHdr_MsgFormat_MsgAddress_t *MsgAddressBuf); + +/** + * Set the message ID (abstract SB endpoint) in the message header + */ +int32 ExtHdr_MsgFormat_SetMsgAddress(ExtHdr_MsgFormat_BaseHeader_t *BasePtr, const ExtHdr_MsgFormat_MsgAddress_t *MsgAddressBuf); + +/** + * Get the size of the header data. + * This is not settable, it is fixed based on the message header format and type of message. + * + * This outputs the size of the actual header data, not including any alignment padding. + */ +int32 ExtHdr_MsgFormat_GetHeaderLength(const ExtHdr_MsgFormat_BaseHeader_t *BasePtr, uint32 *SizeBuf); + + +/** + * Get the total size of the complete message. + * + * This is the total size including all padding, from start of header to the end of the trailer. + * It should reflect the sizeof() of the C structure that represents the entire message + */ +static inline int32 ExtHdr_MsgFormat_GetTotalSize(const ExtHdr_MsgFormat_BaseHeader_t *BasePtr, ExtHdr_MsgFormat_Length_t *SizeBuf) +{ + /* pass through to basic framing */ + return CCSDS_MsgFormat_GetTotalSize(&BasePtr->Base, SizeBuf); +} + +/** + * Set the size of the payload data. + * + * This is the total size including all padding, from start of header to the end of the trailer. + * It should reflect the sizeof() of the C structure that represents the entire message + */ +static inline int32 ExtHdr_MsgFormat_SetTotalSize(ExtHdr_MsgFormat_BaseHeader_t *BasePtr, const ExtHdr_MsgFormat_Length_t *SizeBuf) +{ + /* pass through to basic framing */ + return CCSDS_MsgFormat_SetTotalSize(&BasePtr->Base, SizeBuf); +} + +/** + * Get the sequence number from the message header + */ +static inline int32 ExtHdr_MsgFormat_GetSequence(const ExtHdr_MsgFormat_BaseHeader_t *BasePtr, ExtHdr_MsgFormat_Sequence_t *SequenceBuf) +{ + /* pass through to basic framing */ + return CCSDS_MsgFormat_GetSequence(&BasePtr->Base, SequenceBuf); +} + +/** + * Set the sequence number in the message header + */ +static inline int32 ExtHdr_MsgFormat_SetSequence(ExtHdr_MsgFormat_BaseHeader_t *BasePtr, const ExtHdr_MsgFormat_Sequence_t *SequenceBuf) +{ + /* pass through to basic framing */ + return CCSDS_MsgFormat_SetSequence(&BasePtr->Base, SequenceBuf); +} + + +/** + * Get the timestamp of the message, if applicable. + * + * If the message header contains a timestamp, this gets the timestamp. + * Returns an error code if message format does not contain a timestamp. + */ +int32 ExtHdr_MsgFormat_GetTimestamp(const ExtHdr_MsgFormat_BaseHeader_t *BasePtr, ExtHdr_MsgFormat_Time_t *TimeBuf); + +/** + * Set the timestamp of the message, if applicable. + * + * If the message header contains a timestamp, this sets the field to the given value + * Returns an error code if message format does not contain a timestamp. + */ +int32 ExtHdr_MsgFormat_SetTimestamp(ExtHdr_MsgFormat_BaseHeader_t *BasePtr, const ExtHdr_MsgFormat_Time_t *TimeBuf); + +/** + * Get the Function Code of the message, if applicable. + * + * If the message header contains a function or command code number, this sets the field to the given value + * Returns an error code if message format does not contain a function code. + */ +int32 ExtHdr_MsgFormat_GetFunctionCode(const ExtHdr_MsgFormat_BaseHeader_t *BasePtr, ExtHdr_MsgFormat_FunctionCode_t *CodeBuf); + +/** + * Set the Function Code of the message, if applicable. + * + * If the message header contains a function or command code number, this sets the field to the given value + * Returns an error code if message format does not contain a function code. + */ +int32 ExtHdr_MsgFormat_SetFunctionCode(ExtHdr_MsgFormat_BaseHeader_t *BasePtr, const ExtHdr_MsgFormat_FunctionCode_t *CodeBuf); + +/** + * Reads the error control / checksum field, if applicable + * + * If the message header contains an error control field, this retrieves the value of that field + * Returns an error code if message format does not contain an error control field. + */ +int32 ExtHdr_MsgFormat_GetChecksum(const ExtHdr_MsgFormat_BaseHeader_t *BasePtr, ExtHdr_MsgFormat_Checksum_t *ChecksumBuf); + +/** + * Reads the error control / checksum field, if applicable + * + * If the message header contains an error control field, this retrieves the value of that field + * Returns an error code if message format does not contain an error control field. + */ +int32 ExtHdr_MsgFormat_SetChecksum(ExtHdr_MsgFormat_BaseHeader_t *BasePtr, const ExtHdr_MsgFormat_Checksum_t *ChecksumBuf); + +/** + * Compute the error control / checksum field, if applicable + */ +int32 ExtHdr_MsgFormat_GetComputedChecksum(const ExtHdr_MsgFormat_BaseHeader_t *BasePtr, ExtHdr_MsgFormat_Checksum_t *ChecksumBuf); + + +#endif /* INCLUDE_JPH_EXTHDR_MSGFORMAT_ACCESSORS_H */ diff --git a/fsw/libs/exthdr_msgformat/inc/exthdr_msgformat_types.h b/fsw/libs/exthdr_msgformat/inc/exthdr_msgformat_types.h new file mode 100644 index 000000000..3503f7e0a --- /dev/null +++ b/fsw/libs/exthdr_msgformat/inc/exthdr_msgformat_types.h @@ -0,0 +1,106 @@ +/* +** 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. +*/ + +#ifndef INCLUDE_EXTHDR_MSGFORMAT_TYPES_H +#define INCLUDE_EXTHDR_MSGFORMAT_TYPES_H + +#include +#include + +/* +** Type Definitions +*/ + +/* + * Field encodings for sequence, length, function codes, time, are all the same as basic format + */ +typedef CCSDS_MsgFormat_Checksum_t ExtHdr_MsgFormat_Checksum_t; +typedef CCSDS_MsgFormat_FunctionCode_t ExtHdr_MsgFormat_FunctionCode_t; +typedef CCSDS_MsgFormat_Sequence_t ExtHdr_MsgFormat_Sequence_t; +typedef CCSDS_MsgFormat_Length_t ExtHdr_MsgFormat_Length_t; +typedef CCSDS_MsgFormat_Time_t ExtHdr_MsgFormat_Time_t; + +/* + * Address has additional qualifiers + */ +typedef struct +{ + CCSDS_MsgFormat_MsgAddress_t Base; + uint16 SubSysId; + uint16 SystemId; +} ExtHdr_MsgFormat_MsgAddress_t; + +/*----- CCSDS Secondary Header APID Qualifers ----*/ +typedef struct +{ + + uint8 APIDQSubsystem[2]; + + /* 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 APIDQSystemId[2]; + /* 0xFFFF 0 : System Id mission defined */ + +} ExtHdr_MsgFormat_APIDqualifiers_t; + + + +/*----- CCSDS packet primary header. -----*/ + +typedef struct +{ + /* + * This extends the basic header + */ + CCSDS_MsgFormat_BaseHeader_t Base; + + /* + * In Version 2 mode, the extended / APID qualified header is used for all packets + */ + ExtHdr_MsgFormat_APIDqualifiers_t ApidQ;/**< \brief CCSDS APID Qualifier Secondary Header #CCSDS_APIDqualifiers_t */ + +} ExtHdr_MsgFormat_BaseHeader_t; + + +/*----- Generic combined command header. -----*/ + +/* This uses the same tertiary headers as the basic (non-extended) format */ + +typedef struct +{ + ExtHdr_MsgFormat_BaseHeader_t Base; /**< \brief Standard Header on all packets */ + CCSDS_MsgFormat_CmdSecHdr_t Sec; +} ExtHdr_MsgFormat_CommandPacket_t; + +/*----- Generic combined telemetry header. -----*/ + +typedef struct +{ + ExtHdr_MsgFormat_BaseHeader_t Base; /**< \brief Standard Header on all packets */ + CCSDS_MsgFormat_TlmSecHdr_t Sec; +} ExtHdr_MsgFormat_TelemetryPacket_t; + + + +#endif /* INCLUDE_EXTHDR_MSGFORMAT_TYPES_H */ diff --git a/fsw/libs/exthdr_msgformat/src/exthdr_msgformat.c b/fsw/libs/exthdr_msgformat/src/exthdr_msgformat.c new file mode 100644 index 000000000..4422f584b --- /dev/null +++ b/fsw/libs/exthdr_msgformat/src/exthdr_msgformat.c @@ -0,0 +1,304 @@ +/* +** 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 +#include + +#include "exthdr_msgformat_accessors.h" +#include "ccsds_msgformat_accessors.h" +#include "cfe_error.h" + + +int32 ExtHdr_MsgFormat_SetInitialFields(ExtHdr_MsgFormat_BaseHeader_t *BasePtr, + uint32 TotalLength, + bool Clear) +{ + ExtHdr_MsgFormat_Sequence_t PreservedSeq; + ExtHdr_MsgFormat_Length_t MsgLen; + uint32 SysMsgSize; + + /* Zero the entire packet if needed. */ + if (Clear) + { + memset(BasePtr, 0, TotalLength); + } + else /* Clear only the primary header. */ + { + /* Save the sequence count in case it must be preserved. */ + ExtHdr_MsgFormat_GetSequence(BasePtr, &PreservedSeq); + + memset(BasePtr, 0, sizeof(*BasePtr)); + } + + /* Set the length fields in the primary header. */ + SysMsgSize = TotalLength; + ExtHdr_MsgFormat_SizeToMsgLength(&SysMsgSize, &MsgLen); + ExtHdr_MsgFormat_SetTotalSize(BasePtr, &MsgLen); + + /* Restore the sequence count if needed. */ + if (!Clear) + { + ExtHdr_MsgFormat_SetSequence(BasePtr, &PreservedSeq); + } + + return CFE_SUCCESS; +} + + +/* + * GETTER/SETTER Functions --- + * The general pattern should be to use an IO buffer parameter (pointer) for the value to get/set + * The return value should be an int32 status code, nominally CFE_SUCCESS. + */ + +/** + * Get the message ID (abstract SB endpoint) from the message header + */ +int32 ExtHdr_MsgFormat_GetMsgAddress(const ExtHdr_MsgFormat_BaseHeader_t *BasePtr, ExtHdr_MsgFormat_MsgAddress_t *MsgAddressBuf) +{ + /* get APID data from base message */ + CCSDS_MsgFormat_GetMsgAddress(&BasePtr->Base, &MsgAddressBuf->Base); + uint32 LocalReg; + + /* append with extra information from APIDQ header */ + LocalReg = BasePtr->ApidQ.APIDQSubsystem[0]; + LocalReg <<= 8; + LocalReg |= BasePtr->ApidQ.APIDQSubsystem[1]; + MsgAddressBuf->SubSysId = LocalReg & 0x1FF; + + LocalReg = BasePtr->ApidQ.APIDQSystemId[0]; + LocalReg <<= 8; + LocalReg |= BasePtr->ApidQ.APIDQSystemId[1]; + MsgAddressBuf->SystemId = LocalReg & 0xFFFF; + + return CFE_SUCCESS; +} + +/** + * Set the message ID (abstract SB endpoint) in the message header + */ +int32 ExtHdr_MsgFormat_SetMsgAddress(ExtHdr_MsgFormat_BaseHeader_t *BasePtr, const ExtHdr_MsgFormat_MsgAddress_t *MsgAddressBuf) +{ + /* set APID data in base message */ + CCSDS_MsgFormat_SetMsgAddress(&BasePtr->Base, &MsgAddressBuf->Base); + uint32 LocalReg; + + /* append with extra information in APIDQ header */ + LocalReg = MsgAddressBuf->SubSysId; + BasePtr->ApidQ.APIDQSubsystem[1] = LocalReg & 0xFF; + LocalReg >>= 8; + BasePtr->ApidQ.APIDQSubsystem[0] = (BasePtr->ApidQ.APIDQSubsystem[0] & 0xFE) | (LocalReg & 0x1); + + LocalReg = MsgAddressBuf->SystemId; + BasePtr->ApidQ.APIDQSystemId[1] = LocalReg & 0xFF; + LocalReg >>= 8; + BasePtr->ApidQ.APIDQSystemId[0] = LocalReg & 0xFF; + + return CFE_SUCCESS; +} + +/** + * Get the size of the header data. + * This is not settable, it is fixed based on the message header format and type of message. + * + * This outputs the size of the actual header data, not including any alignment padding. + */ +int32 ExtHdr_MsgFormat_GetHeaderLength(const ExtHdr_MsgFormat_BaseHeader_t *BasePtr, uint32 *SizeBuf) +{ + if (ExtHdr_MsgFormat_GetIsCommand(BasePtr)) + { + *SizeBuf = sizeof(ExtHdr_MsgFormat_CommandPacket_t); + } + else if (ExtHdr_MsgFormat_GetIsTelemetry(BasePtr)) + { + *SizeBuf = sizeof(ExtHdr_MsgFormat_TelemetryPacket_t); + } + else + { + /* fallback - should not be possible in CFE */ + *SizeBuf = sizeof(ExtHdr_MsgFormat_BaseHeader_t); + } + + return CFE_SUCCESS; +} + + +/** + * Get the timestamp of the message, if applicable. + * + * If the message header contains a timestamp, this gets the timestamp. + * Returns an error code if message format does not contain a timestamp. + */ +int32 ExtHdr_MsgFormat_GetTimestamp(const ExtHdr_MsgFormat_BaseHeader_t *BasePtr, ExtHdr_MsgFormat_Time_t *TimeBuf) +{ + const ExtHdr_MsgFormat_TelemetryPacket_t* TlmMsg; + + /* Check that the msg is a TLM type */ + if (!CCSDS_MsgFormat_GetIsTelemetry(&BasePtr->Base)) + { + return CFE_SB_WRONG_MSG_TYPE; + } + + TlmMsg = (const ExtHdr_MsgFormat_TelemetryPacket_t*)BasePtr; + + return CCSDS_MsgFormat_GetTlmTimestamp(&TlmMsg->Sec, TimeBuf); +} + +/** + * Set the timestamp of the message, if applicable. + * + * If the message header contains a timestamp, this sets the field to the given value + * Returns an error code if message format does not contain a timestamp. + */ +int32 ExtHdr_MsgFormat_SetTimestamp(ExtHdr_MsgFormat_BaseHeader_t *BasePtr, const ExtHdr_MsgFormat_Time_t *Time) +{ + ExtHdr_MsgFormat_TelemetryPacket_t* TlmMsg; + + /* Check that the msg is a TLM type */ + if (!CCSDS_MsgFormat_GetIsTelemetry(&BasePtr->Base)) + { + return CFE_SB_WRONG_MSG_TYPE; + } + + TlmMsg = (ExtHdr_MsgFormat_TelemetryPacket_t*)BasePtr; + + return CCSDS_MsgFormat_SetTlmTimestamp(&TlmMsg->Sec, Time); +} + +/** + * Get the Function Code of the message, if applicable. + * + * If the message header contains a function or command code number, this sets the field to the given value + * Returns an error code if message format does not contain a function code. + */ +int32 ExtHdr_MsgFormat_GetFunctionCode(const ExtHdr_MsgFormat_BaseHeader_t *BasePtr, ExtHdr_MsgFormat_FunctionCode_t *CodeBuf) +{ + ExtHdr_MsgFormat_CommandPacket_t* CmdMsg; + + /* Check that the msg is a CMD type */ + if (!CCSDS_MsgFormat_GetIsCommand(&BasePtr->Base)) + { + return CFE_SB_WRONG_MSG_TYPE; + } + + CmdMsg = (ExtHdr_MsgFormat_CommandPacket_t*)BasePtr; + + return CCSDS_MsgFormat_GetCmdFunctionCode(&CmdMsg->Sec, CodeBuf); +} + +/** + * Set the Function Code of the message, if applicable. + * + * If the message header contains a function or command code number, this sets the field to the given value + * Returns an error code if message format does not contain a function code. + */ +int32 ExtHdr_MsgFormat_SetFunctionCode(ExtHdr_MsgFormat_BaseHeader_t *BasePtr, const ExtHdr_MsgFormat_FunctionCode_t *CodeBuf) +{ + ExtHdr_MsgFormat_CommandPacket_t* CmdMsg; + + /* Check that the msg is a CMD type */ + if (!CCSDS_MsgFormat_GetIsCommand(&BasePtr->Base)) + { + return CFE_SB_WRONG_MSG_TYPE; + } + + CmdMsg = (ExtHdr_MsgFormat_CommandPacket_t*)BasePtr; + + return CCSDS_MsgFormat_SetCmdFunctionCode(&CmdMsg->Sec, CodeBuf); +} + + +/** + * Reads the error control / checksum field, if applicable + * + * If the message header contains an error control field, this retrieves the value of that field + * Returns an error code if message format does not contain an error control field. + */ +int32 ExtHdr_MsgFormat_GetChecksum(const ExtHdr_MsgFormat_BaseHeader_t *BasePtr, ExtHdr_MsgFormat_Checksum_t *ChecksumBuf) +{ + const ExtHdr_MsgFormat_CommandPacket_t* CmdMsg; + + /* Check that the msg is a CMD type */ + if (!CCSDS_MsgFormat_GetIsCommand(&BasePtr->Base)) + { + return CFE_SB_WRONG_MSG_TYPE; + } + + CmdMsg = (const ExtHdr_MsgFormat_CommandPacket_t*)BasePtr; + + return CCSDS_MsgFormat_GetCmdChecksum(&CmdMsg->Sec, ChecksumBuf); +} + +/** + * Reads the error control / checksum field, if applicable + * + * If the message header contains an error control field, this retrieves the value of that field + * Returns an error code if message format does not contain an error control field. + */ +int32 ExtHdr_MsgFormat_SetChecksum(ExtHdr_MsgFormat_BaseHeader_t *BasePtr, const ExtHdr_MsgFormat_Checksum_t *ChecksumBuf) +{ + ExtHdr_MsgFormat_CommandPacket_t* CmdMsg; + + /* Check that the msg is a CMD type */ + if (!CCSDS_MsgFormat_GetIsCommand(&BasePtr->Base)) + { + return CFE_SB_WRONG_MSG_TYPE; + } + + CmdMsg = (ExtHdr_MsgFormat_CommandPacket_t*)BasePtr; + + return CCSDS_MsgFormat_SetCmdChecksum(&CmdMsg->Sec, ChecksumBuf); +} + + +/** + * Compute the error control / checksum field, if applicable + */ +int32 ExtHdr_MsgFormat_GetComputedChecksum(const ExtHdr_MsgFormat_BaseHeader_t *BasePtr, ExtHdr_MsgFormat_Checksum_t *ChecksumBuf) +{ + /* Check that the msg is a CMD type */ + if (!CCSDS_MsgFormat_GetIsCommand(&BasePtr->Base)) + { + /* no checksum field, nothing to do */ + return CFE_SB_WRONG_MSG_TYPE; + } + + *ChecksumBuf = CCSDS_MsgFormat_ComputeChecksum_Impl(&BasePtr->Base, + offsetof(ExtHdr_MsgFormat_CommandPacket_t, Sec.JChecksum)); + + return CFE_SUCCESS; +} +