CCSDSPack
C++ Library for CCSDS Space Packet manipulation. i.e. generation, extraction, analisys and more
Loading...
Searching...
No Matches
CCSDSPacket.cpp
Go to the documentation of this file.
1// Copyright 2025-2026 ExoSpaceLabs
2// SPDX-License-Identifier: Apache-2.0
3
4#include "CCSDSPacket.h"
5#include "CCSDSDataField.h"
6#include "CCSDSUtils.h"
7#include <algorithm>
8
9//exclude includes when building for MCU
10#ifndef CCSDS_MCU
11 #include "CCSDSConfig.h"
12#endif //CCSDS_MCU
13
16 const auto dataField = m_dataField.serialize();
17 const auto dataFiledSize = static_cast<std::uint16_t>(dataField.size());
18 const auto dataFieldHeaderFlag(m_dataField.getDataFieldHeaderFlag());
19 m_primaryHeader.setDataLength(dataFiledSize);
20 m_primaryHeader.setDataFieldHeaderFlag(dataFieldHeaderFlag);
21 // todo this part needs to be moved out of conditional updating
24 } else {
26 }
28 m_updateStatus = true;
29 }
30}
31
32#ifndef CCSDS_MCU
34 Config cfg;
35 cfg.load(configPath);
36 FORWARD_RESULT(loadFromConfig(cfg));
37 return true;
38}
39
41 std::uint8_t versionNumber;
42 std::uint8_t type;
43 std::uint8_t APID{0};
44 std::uint8_t dataFieldHeaderFlag;
45 std::uint16_t sequenceCount;
46 ESequenceFlag sequenceFlag{};
47 bool segmented{false};
48
49 RET_IF_ERR_MSG(!cfg.isKey( "ccsds_version_number"), ErrorCode::CONFIG_FILE_ERROR,
50 "Config: Missing int field: ccsds_version_number");
52 "Config: Missing bool field: ccsds_type");
53 RET_IF_ERR_MSG(!cfg.isKey("ccsds_data_field_header_flag"), ErrorCode::CONFIG_FILE_ERROR,
54 "Config: Missing bool field: ccsds_data_field_header_flag");
56 "Config: Missing int field: ccsds_APID");
57 RET_IF_ERR_MSG(!cfg.isKey( "ccsds_segmented"), ErrorCode::CONFIG_FILE_ERROR,
58 "Config: Missing bool field: ccsds_segmented");
59
60 ASSIGN_OR_PRINT(versionNumber, cfg.get< int>( "ccsds_version_number"));
61 ASSIGN_OR_PRINT(type, cfg.get<bool>( "ccsds_type"));
62 ASSIGN_OR_PRINT(dataFieldHeaderFlag, cfg.get<bool>("ccsds_data_field_header_flag"));
63 ASSIGN_OR_PRINT(APID, cfg.get< int>( "ccsds_APID"));
64 ASSIGN_OR_PRINT(segmented, cfg.get<bool>( "ccsds_segmented"));
65
66 m_primaryHeader.setVersionNumber(versionNumber);
67 m_primaryHeader.setType(type);
68 m_primaryHeader.setDataFieldHeaderFlag(dataFieldHeaderFlag);
69 m_primaryHeader.setAPID(APID);
70 if (segmented) {
71 sequenceCount = 1;
72 sequenceFlag = FIRST_SEGMENT;
73 }else {
74 sequenceCount = 0;
75 sequenceFlag = UNSEGMENTED;
76 }
77 m_primaryHeader.setSequenceFlags(sequenceFlag);
78 m_primaryHeader.setSequenceCount(sequenceCount);
79
80 if (cfg.isKey( "data_field_size")) { // optional field
81 std::uint16_t dataFieldSize;
82 ASSIGN_OR_PRINT(dataFieldSize, cfg.get< int>( "data_field_size"));
83 m_dataField.setDataPacketSize(dataFieldSize);
84 }
85
86 if (cfg.isKey("define_secondary_header")) { // optional field
87 bool secondaryHeaderFlag{false};
88 ASSIGN_OR_PRINT(secondaryHeaderFlag, cfg.get<bool>("define_secondary_header"));
89 if (secondaryHeaderFlag) {
90 FORWARD_RESULT( m_dataField.setDataFieldHeader(cfg));
91 }
92 }
93
94 if (cfg.isKey("application_data")) { // optional field
95 std::vector<std::uint8_t> applicationData{};
96 ASSIGN_OR_PRINT(applicationData, cfg.get<std::vector<std::uint8_t>>("application_data"));
97 FORWARD_RESULT( m_dataField.setApplicationData(applicationData));
98 }
99
100 return true;
101}
102#endif
103
105 update();
106 return m_CRC16;
107}
108
110 return m_dataField.getDataFieldAvailableBytesSize();
111}
112
114 update();
115 return m_primaryHeader.getDataFieldHeaderFlag();
116}
117
118std::vector<std::uint8_t> CCSDS::Packet::getCRCVectorBytes() {
119 std::vector<std::uint8_t> crc(2);
120 const auto crcVar = getCRC();
121 crc[0] = (crcVar >> 8) & 0xFF; // MSB (Most Significant Byte)
122 crc[1] = crcVar & 0xFF; // LSB (Least Significant Byte)
123 return crc;
124}
125
127 update();
128 return m_dataField;
129}
130
132 update();
133 return m_primaryHeader;
134}
135
137 update();
138 return m_primaryHeader.getFullHeader();
139};
140
141std::vector<std::uint8_t> CCSDS::Packet::getPrimaryHeaderBytes() {
142 update();
143 return m_primaryHeader.serialize();
144}
145
146std::vector<std::uint8_t> CCSDS::Packet::getDataFieldHeaderBytes() {
147 update();
148 return m_dataField.getDataFieldHeaderBytes();
149}
150
151std::vector<std::uint8_t> CCSDS::Packet::getApplicationDataBytes() {
152 update();
153 return m_dataField.getApplicationData();
154}
155
156std::vector<std::uint8_t> CCSDS::Packet::getFullDataFieldBytes() {
157 return m_dataField.serialize();
158}
159
160std::vector<std::uint8_t> CCSDS::Packet::serialize() {
161 auto header = getPrimaryHeaderBytes();
162 auto dataField = m_dataField.serialize();
163 const auto crc = getCRCVectorBytes();
164
165 std::vector<std::uint8_t> packet;
166 packet.reserve(header.size() + dataField.size() + crc.size());
167 packet.insert(packet.end(), header.begin(), header.end());
168 if (!getFullDataFieldBytes().empty()) {
169 packet.insert(packet.end(), dataField.begin(), dataField.end());
170 }
171 packet.insert(packet.end(), crc.begin(), crc.end());
172
173 return packet;
174}
175
176CCSDS::ResultBool CCSDS::Packet::deserialize(const std::vector<std::uint8_t> &data) {
178 "Cannot Deserialize Packet, Invalid Data provided data size must be at least 8 bytes");
179
180 std::vector<std::uint8_t> dataFieldVector;
181 std::copy(data.begin() + 6, data.end(), std::back_inserter(dataFieldVector));
182
183 FORWARD_RESULT(deserialize({data[0], data[1], data[2], data[3], data[4], data[5]}, dataFieldVector));
184
185 return true;
186}
187
188CCSDS::ResultBool CCSDS::Packet::deserialize(const std::vector<std::uint8_t> &data, const std::string &headerType, const std::int32_t headerSize) {
189 RET_IF_ERR_MSG(data.size() <= 8, ErrorCode::INVALID_DATA,
190 "Cannot Deserialize Packet, Invalid Data provided data size must be at least 8 bytes");
191 RET_IF_ERR_MSG(headerType == "BufferHeader", ErrorCode::INVALID_SECONDARY_HEADER_DATA,
192 "Cannot Deserialize Packet, BufferHeader is not of defined size");
193 RET_IF_ERR_MSG(!m_dataField.getDataFieldHeaderFactory().typeIsRegistered(headerType),
195 "Cannot Deserialize Packet, Unregistered Secondary header: " + headerType);
196 std::uint16_t headerDataSizeBytes{0};
197 const auto secondaryHeader = m_dataField.getDataFieldHeaderFactory().create(headerType);
198 if (headerType == "PusC" && headerSize > 0) {
199 headerDataSizeBytes = headerSize;
200 }else {
201 headerDataSizeBytes = secondaryHeader->getSize();
202 }
203
204 std::vector<std::uint8_t> dataFieldHeaderVector;
205 std::copy_n(data.begin() + 6, headerDataSizeBytes, std::back_inserter(dataFieldHeaderVector));
206 FORWARD_RESULT(secondaryHeader->deserialize(dataFieldHeaderVector ));
207 setDataFieldHeader(secondaryHeader);
208
209 std::vector<std::uint8_t> dataFieldVector;
210 if (data.size() > (6 + headerDataSizeBytes)) {
211 std::copy(data.begin() + 6 + headerDataSizeBytes, data.end(), std::back_inserter(dataFieldVector));
212 }
213 FORWARD_RESULT(deserialize({data[0], data[1], data[2], data[3], data[4], data[5]}, dataFieldVector));
214
215 return true;
216}
217
218CCSDS::ResultBool CCSDS::Packet::deserialize(const std::vector<std::uint8_t> &data, const std::uint16_t headerDataSizeBytes) {
219 RET_IF_ERR_MSG(data.size() < (8 + headerDataSizeBytes), ErrorCode::INVALID_DATA,
220 "Cannot Deserialize Packet, Invalid Data provided");
221
222 std::vector<std::uint8_t> secondaryHeader;
223 std::vector<std::uint8_t> dataFieldVector;
224 std::copy(data.begin() + 6, data.begin() + 6 + headerDataSizeBytes, std::back_inserter(secondaryHeader));
225 FORWARD_RESULT(m_dataField.setDataFieldHeader(secondaryHeader));
226 if (data.size() > (6 + headerDataSizeBytes)) {
227 std::copy(data.begin() + 6 + headerDataSizeBytes, data.end(), std::back_inserter(dataFieldVector));
228 }
229 FORWARD_RESULT(deserialize({data[0], data[1], data[2], data[3], data[4], data[5]}, dataFieldVector));
230 return true;
231}
232
233CCSDS::ResultBool CCSDS::Packet::deserialize(const std::vector<std::uint8_t> &headerData, const std::vector<std::uint8_t> &data) {
234 RET_IF_ERR_MSG(headerData.size() != 6, ErrorCode::INVALID_HEADER_DATA,
235 "Cannot Deserialize Packet, Invalid Header Data provided.");
236 FORWARD_RESULT(m_primaryHeader.deserialize( headerData ));
237 m_sequenceCounter = m_primaryHeader.getSequenceCount();
238
240 "Cannot Deserialize Packet, Invalid Data provided, at least CRC is required.");
241
242 std::vector<uint8_t> dataCopy;
243 m_CRC16 = (data[data.size() - 2] << 8) + data.back();
244
245 if (data.size() == 2) return true; // returns since no application data is to be written.
246
247 std::copy(data.begin(), data.end() - 2, std::back_inserter(dataCopy));
248 FORWARD_RESULT(m_dataField.setApplicationData(dataCopy));
249
250 return true;;
251}
252
254 // where 8 is derived from 6 bytes for Primary header and 2 bytes for CRC16.
255 return 8 + m_dataField.getDataFieldUsedBytesSize();
256}
257
259 FORWARD_RESULT(m_primaryHeader.setData( data ));
260 m_sequenceCounter = m_primaryHeader.getSequenceCount();
261 m_updateStatus = false;
262 return true;
263}
264
265CCSDS::ResultBool CCSDS::Packet::setPrimaryHeader(const std::vector<uint8_t> &data) {
266 FORWARD_RESULT(m_primaryHeader.deserialize( data ));
267 m_sequenceCounter = m_primaryHeader.getSequenceCount();
268 m_updateStatus = false;
269 return true;
270}
271
273 m_primaryHeader = header;
274}
275
277 m_primaryHeader.setData(data);
278 m_sequenceCounter = m_primaryHeader.getSequenceCount();
279 m_updateStatus = false;
280}
281
282void CCSDS::Packet::setDataFieldHeader(const std::shared_ptr<SecondaryHeaderAbstract> &header) {
283 m_dataField.setDataFieldHeader(header);
284 m_updateStatus = false;
285}
286
287CCSDS::ResultBool CCSDS::Packet::setDataFieldHeader(const std::vector<uint8_t> &data, const std::string &headerType) {
288 FORWARD_RESULT(m_dataField.setDataFieldHeader( data, headerType ));
289 m_updateStatus = false;
290 return true;
291}
292
293CCSDS::ResultBool CCSDS::Packet::setDataFieldHeader(const std::uint8_t *pData, const size_t sizeData,
294 const std::string &headerType) {
295 FORWARD_RESULT(m_dataField.setDataFieldHeader( pData, sizeData, headerType ));
296 m_updateStatus = false;
297 return true;
298}
299
300CCSDS::ResultBool CCSDS::Packet::setDataFieldHeader(const std::vector<uint8_t> &data) {
301 FORWARD_RESULT(m_dataField.setDataFieldHeader( data ));
302 m_updateStatus = false;
303 return true;
304}
305
306CCSDS::ResultBool CCSDS::Packet::setDataFieldHeader(const std::uint8_t *pData, const size_t sizeData) {
307 FORWARD_RESULT(m_dataField.setDataFieldHeader( pData,sizeData ));
308 m_updateStatus = false;
309 return true;;
310}
311
312CCSDS::ResultBool CCSDS::Packet::setApplicationData(const std::vector<std::uint8_t> &data) {
313 FORWARD_RESULT(m_dataField.setApplicationData( data ));
314 m_updateStatus = false;
315 return true;
316}
317
318CCSDS::ResultBool CCSDS::Packet::setApplicationData(const std::uint8_t *pData, const size_t sizeData) {
319 FORWARD_RESULT(m_dataField.setApplicationData( pData,sizeData ));
320 m_updateStatus = false;
321 return true;
322}
323
325 m_primaryHeader.setSequenceFlags(flags);
326 m_updateStatus = false;
327}
328
330 RET_IF_ERR_MSG(m_primaryHeader.getSequenceFlags() == UNSEGMENTED && count != 0, ErrorCode::INVALID_DATA,
331 "Unable to set non 0 value for UNSEGMENTED packet");
332 m_sequenceCounter = count;
333 m_updateStatus = false;
334 return true;
335}
336
337void CCSDS::Packet::setDataFieldSize(const std::uint16_t size) {
338 m_dataField.setDataPacketSize(size);
339}
340
342 m_enableUpdatePacket = enable;
343 m_dataField.setDataFieldHeaderAutoUpdateStatus(enable);
344}
#define RET_IF_ERR_MSG(condition, errorCode, message)
Macro to return an error with an error message if a condition is met.
#define ASSIGN_OR_PRINT(var, result)
Macro to assign a result value or print an error message.
#define FORWARD_RESULT(result)
Macro to return a result as-is (for functions returning Result<T>).
uint16_t crc16(const std::vector< std::uint8_t > &data, std::uint16_t polynomial=0x1021, std::uint16_t initialValue=0xFFFF, std::uint16_t finalXorValue=0x0000)
Computes the CRC-16 checksum for a given data vector with configurable parameters.
Represents the data field of a CCSDS packet.
std::vector< std::uint8_t > serialize()
Retrieves the full data field by combining the data field header and application data.
bool getDataFieldHeaderFlag() const
retrieves true if a known secondary header has been set
Manages the decomposition and manipulation of CCSDS primary headers.
Definition CCSDSHeader.h:83
void setDataLength(const std::uint16_t &value)
16 bits
void setSequenceCount(const std::uint16_t &value)
14 bits
void setDataFieldHeaderFlag(const std::uint8_t &value)
1 bits
std::uint8_t getSequenceFlags() const
2 bits
Definition CCSDSHeader.h:91
ResultBool setData(const std::uint64_t &data)
Sets the header data from a 64-bit integer representation.
bool m_updateStatus
When setting data thus value should be set to false.
std::vector< uint8_t > getPrimaryHeaderBytes()
Retrieves the primary header of the packet as a vector of bytes.
void update()
Updates Primary headers data field size.
std::vector< uint8_t > getCRCVectorBytes()
Retrieves the CRC-16 checksum as a vector of bytes.
void setUpdatePacketEnable(bool enable)
needs to be called as soon as possible, probably also from constructor.
ResultBool setSequenceCount(std::uint16_t count)
Sets the sequence count for the packet.
bool getDataFieldHeaderFlag()
@ returns the data field header flag
void setDataFieldHeader(const std::shared_ptr< SecondaryHeaderAbstract > &header)
Sets the data field header using the provided SecondaryHeaderAbstract derived header.
std::uint16_t m_sequenceCounter
Header m_primaryHeader
6 bytes / 48 bits / 12 hex
std::uint64_t getPrimaryHeader64bit()
Retrieves the primary header of the packet.
DataField m_dataField
variable
ResultBool loadFromConfig(const Config &cfg)
Loads a packet from a configuration object, including secondary header if present.
std::uint16_t getCRC()
Computes and retrieves the CRC-16 checksum of the packet.
std::uint16_t getDataFieldMaximumSize() const
returns the maximum data field size
void setSequenceFlags(ESequenceFlag flags)
Sets the sequence flags for the packet's primary header.
std::vector< uint8_t > getFullDataFieldBytes()
Retrieves the full data field data.
std::vector< uint8_t > serialize()
Retrieves the full packet as a vector of bytes.
ResultBool loadFromConfigFile(const std::string &configPath)
Loads a packet from a configuration file, including secondary header if present.
ResultBool setApplicationData(const std::vector< std::uint8_t > &data)
Sets the application data for the packet.
std::uint16_t m_CRC16
Cyclic Redundancy check 16 bits.
std::vector< uint8_t > getDataFieldHeaderBytes()
Retrieves the secondary header data from the data field.
void setPrimaryHeader(PrimaryHeader data)
Sets the primary header using the provided PrimaryHeader object.
ResultBool deserialize(const std::vector< std::uint8_t > &data)
Deserializes a vector of bytes into a CCSDS packet.
std::uint16_t getFullPacketLength()
Retrieves the current size of the CCSDS Packet.
Header & getPrimaryHeader()
returns the CCSDS packet's Primary Header.
std::vector< uint8_t > getApplicationDataBytes()
Retrieves the application data from the data field.
DataField & getDataField()
returns the CCSDS packet's DataField.
bool m_enableUpdatePacket
Enables primary header and secondary header update.
void setDataFieldSize(std::uint16_t size)
Sets the maximum data packet size for the CCSDS DataField.
CRC16Config m_CRC16Config
structure holding configuration of crc calculation.
Encapsulates a result that can hold either a value or an Error.
Definition CCSDSResult.h:85
Parses and stores config values from custom file format.
Definition CCSDSConfig.h:14
bool isKey(const std::string &key) const
CCSDS::ResultBool load(const std::string &filename)
Load config file.
CCSDS::Result< T > get(const std::string &key) const
Get value by key and type.
Definition CCSDSConfig.h:23
@ INVALID_DATA
Data is invalid.
Definition CCSDSResult.h:27
@ INVALID_HEADER_DATA
Header data is invalid.
Definition CCSDSResult.h:28
@ CONFIG_FILE_ERROR
Configuration file error.
Definition CCSDSResult.h:37
@ INVALID_SECONDARY_HEADER_DATA
Secondary header data is invalid.
Definition CCSDSResult.h:29
ESequenceFlag
Represents the sequence flags used in CCSDS telemetry transfer frames.
Definition CCSDSHeader.h:22
@ UNSEGMENTED
11 Complete packet in a single frame.
Definition CCSDSHeader.h:26
@ FIRST_SEGMENT
01 First segment of a new packet.
Definition CCSDSHeader.h:24
std::uint16_t initialValue
Definition CCSDSPacket.h:40
std::uint16_t polynomial
Definition CCSDSPacket.h:39
std::uint16_t finalXorValue
Definition CCSDSPacket.h:41
Represents the primary header of a CCSDS packet.
Definition CCSDSHeader.h:44