CCSDSPack
C++ Library for CCSDS Space Packet manipulation. i.e. generation, extraction, analisys and more
Loading...
Searching...
No Matches
CCSDSUtils.cpp
Go to the documentation of this file.
1// Copyright 2025-2026 ExoSpaceLabs
2// SPDX-License-Identifier: Apache-2.0
3
4#include "CCSDSUtils.h"
5#include <cstddef>
6#include <iomanip>
7
8//exclude includes when building for MCU
9#ifndef CCSDS_MCU
10 #include <fstream>
11 #include <iostream>
12#else
13 #include <string>
14#endif //CCSDS_MCU
15
16//###########################################################################
17#define VERBOSE 1
18
19
20uint16_t crc16(
21 const std::vector<std::uint8_t> &data, const std::uint16_t polynomial, const std::uint16_t initialValue,
22 const std::uint16_t finalXorValue) {
23 std::uint16_t crc = initialValue;
24
25 for (const auto &byte: data) {
26 crc ^= static_cast<std::uint16_t>(byte) << 8; // Align byte with MSB of 16-bit CRC
27 for (std::int32_t i = 0; i < 8; ++i) {
28 // Process each bit
29 if (crc & 0x8000) {
30 // Check if MSB is set
31 crc = (crc << 1) ^ polynomial; // Shift and XOR with polynomial
32 } else {
33 crc = crc << 1; // Shift only
34 }
35 }
36 }
37
38 return crc ^ finalXorValue; // Apply final XOR
39}
40
41bool stringEndsWith(const std::string& str, const std::string& suffix) {
42 return str.size() >= suffix.size() &&
43 str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
44}
45
46std::string getBinaryString(const std::uint32_t value, const std::int32_t bits) {
47 std::string binaryString;
48 // Calculate the minimum number of bits required to represent in groups of 4
49 const std::int32_t paddedBits = ((bits + 3) / 4) * 4; // Round up to the nearest multiple of 4
50
51 for (std::int32_t i = paddedBits - 1; i >= 0; --i) {
52 binaryString += ((value >> i) & 1) ? '1' : '0';
53
54 // Add a space after every 4 bits, except at the end
55 if (i % 4 == 0 && i != 0) {
56 binaryString += ' ';
57 }
58 }
59 return binaryString;
60}
61
62std::string getBitsSpaces(const std::int32_t num) {
63 std::string spaces;
64
65 for (std::int32_t i = num - 1; i >= 0; --i) {
66 spaces += ' ';
67 }
68
69 return spaces;
70}
71#ifndef CCSDS_MCU
72void printBufferData(const std::vector<std::uint8_t> &buffer, const std::int32_t limitBytes) {
73 std::cout << "[ ";
74 if (buffer.size() > limitBytes) {
75 for (size_t i= 0 ; i < static_cast<int>(limitBytes / 2); i++) {
76 std::cout << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>(buffer[i]) << " ";
77 }
78 std::cout << "... ";
79 for (size_t i = buffer.size() - static_cast<int>(limitBytes / 2) ; i < buffer.size(); i++) {
80 std::cout << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>(buffer[i]) << " ";
81 }
82 } else {
83 for (const unsigned char i: buffer) {
84 std::cout << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>(i) << " ";
85 }
86 }
87 std::cout << "]" << std::endl;
88}
89
90void printData(CCSDS::DataField dataField) {
91 const auto dataFieldHeader = dataField.getDataFieldHeaderBytes();
92 auto applicationData = dataField.getApplicationData();
93 const std::uint16_t maxSize = (applicationData.size() > dataFieldHeader.size())
94 ? applicationData.size()
95 : dataFieldHeader.size();
96
97 std::cout << " [CCSDS DATA] Data Field Length : " << applicationData.size() + dataFieldHeader.size() << " bytes" << std::endl;
98 std::cout << " [CCSDS DATA] Secondary Header Present : [ " << (dataField.getDataFieldHeaderFlag()
99 ? "True"
100 : "False") << " ]" << std::endl;
101 if (!dataFieldHeader.empty()) {
102 std::cout << " [CCSDS DATA] Secondary Header [Hex] : " << getBitsSpaces(
103 (maxSize - static_cast<std::uint16_t>(dataFieldHeader.size())) * 4);
104 printBufferData(dataFieldHeader);
105 }
106
107 std::cout << " [CCSDS DATA] Application Data [Hex] : ";
108 printBufferData(applicationData);
109 std::cout << std::endl;
110}
111
113 std::cout << " [CCSDS HEADER] Full Primary Header [Hex] : [ " << getBitsSpaces(17 - 12) << "0x" << std::hex <<
114 header.getFullHeader() << " ]" << std::endl;
115 std::cout << std::endl;
116
117 std::cout << " [CCSDS HEADER] Version Number : [ " << getBitsSpaces(19 - 4) <<
118 getBinaryString(header.getVersionNumber(), 3) << " ]";
119 std::cout << " - [Dec] : "<< std::dec << static_cast<int>( header.getVersionNumber()) << std::endl;
120
121 std::cout << " [CCSDS HEADER] Type : [ " << getBitsSpaces(19 - 4) <<
122 getBinaryString(header.getType(), 1) << " ]";
123 std::cout << " - [Dec] : "<< std::dec << static_cast<int>( header.getType()) << std::endl;
124
125 std::cout << " [CCSDS HEADER] Data Field Header Flag : [ " << getBitsSpaces(19 - 4) << getBinaryString(
126 header.getDataFieldHeaderFlag(), 1) << " ]";
127 std::cout << " - : " << (header.getDataFieldHeaderFlag() ? "True" : "False") << std::endl;
128
129 std::cout << " [CCSDS HEADER] APID : [ " << getBitsSpaces(17 - 12) <<
130 getBinaryString(header.getAPID(), 11) << " ]";
131 std::cout << " - [Dec] : " << std::dec << header.getAPID() << std::endl;
132
133 std::cout << " [CCSDS HEADER] Sequence Flags : [ " << getBitsSpaces(19 - 4) <<
134 getBinaryString(header.getSequenceFlags(), 2) << " ]";
135 std::cout << " - : ";
136 switch(header.getSequenceFlags()) {
137 case 0:
138 std::cout << "CONTINUING_SEGMENT";
139 break;
140 case 1:
141 std::cout << "FIRST_SEGMENT";
142 break;
143 case 2:
144 std::cout << "LAST_SEGMENT";
145 break;
146 case 3:
147 std::cout << "UNSEGMENTED";
148 break;
149 default:
150 break;
151 }
152 std::cout << std::endl;
153
154 std::cout << " [CCSDS HEADER] Sequence Count : [ " << getBitsSpaces(0) << getBinaryString(
155 header.getSequenceCount(), 14) << " ]";
156 std::cout << " - [Dec] : "<< std::dec << header.getSequenceCount() << std::endl;
157
158 std::cout << " [CCSDS HEADER] DataLength : [ " << getBinaryString(header.getDataLength(), 16) <<
159 " ]";
160 std::cout << " - [Dec] : "<< std::dec << header.getDataLength() << std::endl;
161
162 std::cout << std::endl;
163}
164
165
167 CCSDS::Header header;
168 FORWARD_RESULT(header.deserialize({packet.getPrimaryHeaderBytes()}));
169 printHeader(header);
170 return true;
171}
172
174 auto dataField = packet.getDataField();
175
176 printData(dataField);
177 std::cout << "[ CCSDSPack ] CRC-16 [Hex] : [ " << "0x" << std::hex << packet.getCRC() << " ]";
178 std::cout << " - [Dec] : "<< std::dec << packet.getCRC() << std::endl;
179
180}
181
183 printPrimaryHeader(packet);
184 printDataField(packet);
185}
186
188 std::cout << "[ CCSDS Manager ] Number of Packets : " << manager.getTotalPackets() << std::endl;
189 std::cout << "[ CCSDS Manager ] Sync Pattern Enabled : " << (manager.getSyncPatternEnable() ? "True" : "False") << std::endl;
190 std::cout << "[ CCSDS Manager ] Sync Pattern : 0x" << std::hex << manager.getSyncPattern() << std::dec << std::endl;
191
192 auto templatePacket = manager.getTemplate();
193 std::cout << "[ CCSDS Manager ] Template : " << std::endl ;
194 printPrimaryHeader(templatePacket);
195
196 std::int32_t idx = 1;
197 for (auto &packet: manager.getPacketsReference()) {
198 std::cout << "__________________________________________________________________________________________________________________" << std::endl;
199 std::cout << "[ CCSDS Manager ] Printing Packet [ " << idx << " ]:" << std::endl;
200 std::cout << "[ CCSDS Manager ] Packet Length : " << packet.getFullPacketLength() << " bytes" << std::endl;
201 std::cout << "[ CCSDS Manager ] Data ";
202 printBufferData(packet.serialize(), 20);
203 printPacket(packet);
204 idx++;
205 }
206}
207
208CCSDS::ResultBool writeBinaryFile(const std::vector<std::uint8_t>& data, const std::string& filename) {
209 RET_IF_ERR_MSG(filename.empty(),CCSDS::ErrorCode::FILE_WRITE_ERROR, "No filename provided");
210 RET_IF_ERR_MSG(data.empty(),CCSDS::ErrorCode::FILE_WRITE_ERROR, "No data provided");
211 std::ofstream out(filename, std::ios::binary);
212
213 RET_IF_ERR_MSG(!out,CCSDS::ErrorCode::FILE_WRITE_ERROR, "Failed to open file for writing");
214
215 // Write the entire vector data to the file in one go
216 out.write(reinterpret_cast<const char*>(data.data()), static_cast<std::streamsize>(data.size()));
217 RET_IF_ERR_MSG(!out,CCSDS::ErrorCode::FILE_WRITE_ERROR, "Failed to write the data to the file");
218
219 return true;
220}
221
222CCSDS::ResultBuffer readBinaryFile(const std::string& filename) {
223 RET_IF_ERR_MSG(filename.empty(),CCSDS::ErrorCode::FILE_READ_ERROR, "No filename provided");
224
225 std::ifstream in(filename, std::ios::binary | std::ios::ate);
226 RET_IF_ERR_MSG(!in,CCSDS::ErrorCode::FILE_READ_ERROR, "Failed to open file for reading");
227
228 // Get the file size using the 'ate' flag (seeks to the end automatically)
229 const std::streamsize size = in.tellg();
230 in.seekg(0, std::ios::beg);
231
232 // Read the entire file content into the vector
233 std::vector<std::uint8_t> data(size);
234 in.read(reinterpret_cast<char*>(data.data()), size);
235
236 RET_IF_ERR_MSG(!in,CCSDS::ErrorCode::FILE_READ_ERROR, "Failed to read the entire file");
237 return data;
238}
239
240bool fileExists(const std::string &fileName) {
241 auto res = readBinaryFile(fileName);
242 if ( res.has_value()) {
243 return true;
244 }
245 return false;
246}
247#endif
#define RET_IF_ERR_MSG(condition, errorCode, message)
Macro to return an error with an error message if a condition is met.
#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, const std::uint16_t polynomial, const std::uint16_t initialValue, const std::uint16_t finalXorValue)
Computes the CRC-16 checksum for a given data vector with configurable parameters.
bool fileExists(const std::string &fileName)
filesystem check fore file existence prepared for both windows and linux.
void printPacket(CCSDS::Packet &packet)
Prints to console a CCSDS Packets, breaking it down to Primary header and Data field.
bool stringEndsWith(const std::string &str, const std::string &suffix)
Tests if str ends with suffix.
CCSDS::ResultBool printPrimaryHeader(CCSDS::Packet &packet)
Prints to console the primary header of a provided CCSDS packet.
std::string getBinaryString(const std::uint32_t value, const std::int32_t bits)
Converts a given value to its binary representation as a string, with spaces every 4 bits.
void printData(CCSDS::DataField dataField)
Prints the data field details, including the secondary header and application data.
std::string getBitsSpaces(const std::int32_t num)
Generates a string of spaces for formatting binary outputs.
CCSDS::ResultBuffer readBinaryFile(const std::string &filename)
Read a specified binary file and return its contents as a buffer.
void printHeader(CCSDS::Header &header)
Prints the header fields and their binary or hexadecimal representations.
void printBufferData(const std::vector< std::uint8_t > &buffer, const std::int32_t limitBytes)
Prints to console the HEX data from the bytes vector.
CCSDS::ResultBool writeBinaryFile(const std::vector< std::uint8_t > &data, const std::string &filename)
This function takes in a buffer of data and a file name.
void printPackets(CCSDS::Manager &manager)
Prints to console a series of CCSDS Packets contained in the manager.
void printDataField(CCSDS::Packet &packet)
Prints the data field and the CRC-16 checksum of the packet.
Represents the data field of a CCSDS packet.
bool getDataFieldHeaderFlag() const
retrieves true if a known secondary header has been set
std::vector< std::uint8_t > getDataFieldHeaderBytes()
Retrieves the secondary header data as a vector of bytes.
std::vector< std::uint8_t > getApplicationData()
Retrieves the application data from the data field.
Manages the decomposition and manipulation of CCSDS primary headers.
Definition CCSDSHeader.h:83
std::uint16_t getAPID() const
11 bits
Definition CCSDSHeader.h:90
std::uint64_t getFullHeader()
Computes and retrieves the full header as a 64-bit value.
std::uint8_t getType() const
1 bits
Definition CCSDSHeader.h:88
std::uint8_t getSequenceFlags() const
2 bits
Definition CCSDSHeader.h:91
std::uint16_t getSequenceCount() const
14 bits
Definition CCSDSHeader.h:92
std::uint8_t getVersionNumber() const
3 bits
Definition CCSDSHeader.h:87
ResultBool deserialize(const std::vector< std::uint8_t > &data)
Sets the header data from a 64-bit integer representation.
std::uint8_t getDataFieldHeaderFlag() const
1 bits
Definition CCSDSHeader.h:89
std::uint16_t getDataLength() const
16 bits
Definition CCSDSHeader.h:93
Manages CCSDS packets and their templates.
std::vector< Packet > & getPacketsReference()
Returns a reference to the packets vector.
std::uint32_t getSyncPattern() const
returns the currently set sync pattern.
std::uint16_t getTotalPackets() const
Retrieves the total number of packets managed.
Packet getTemplate()
Retrieves the packet template.
bool getSyncPatternEnable() const
returns the current settings of the sync pattern enable
Represents a CCSDS (Consultative Committee for Space Data Systems) packet.
Definition CCSDSPacket.h:62
std::uint16_t getCRC()
Computes and retrieves the CRC-16 checksum of the packet.
DataField & getDataField()
returns the CCSDS packet's DataField.
Encapsulates a result that can hold either a value or an Error.
Definition CCSDSResult.h:85
@ FILE_READ_ERROR
Reading from file failure.
Definition CCSDSResult.h:35
@ FILE_WRITE_ERROR
Writing to file failure.
Definition CCSDSResult.h:36