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#include "CCSDSUtils.h"
2#include <cstddef>
3#include <iomanip>
4
5//exclude includes when building for MCU
6#ifndef CCSDS_MCU
7 #include <fstream>
8 #include <iostream>
9#else
10 #include <string>
11#endif //CCSDS_MCU
12
13//###########################################################################
14#define VERBOSE 1
15
16
17uint16_t crc16(
18 const std::vector<std::uint8_t> &data, const std::uint16_t polynomial, const std::uint16_t initialValue,
19 const std::uint16_t finalXorValue) {
20 std::uint16_t crc = initialValue;
21
22 for (const auto &byte: data) {
23 crc ^= static_cast<std::uint16_t>(byte) << 8; // Align byte with MSB of 16-bit CRC
24 for (std::int32_t i = 0; i < 8; ++i) {
25 // Process each bit
26 if (crc & 0x8000) {
27 // Check if MSB is set
28 crc = (crc << 1) ^ polynomial; // Shift and XOR with polynomial
29 } else {
30 crc = crc << 1; // Shift only
31 }
32 }
33 }
34
35 return crc ^ finalXorValue; // Apply final XOR
36}
37
38bool stringEndsWith(const std::string& str, const std::string& suffix) {
39 return str.size() >= suffix.size() &&
40 str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
41}
42
43std::string getBinaryString(const std::uint32_t value, const std::int32_t bits) {
44 std::string binaryString;
45 // Calculate the minimum number of bits required to represent in groups of 4
46 const std::int32_t paddedBits = ((bits + 3) / 4) * 4; // Round up to the nearest multiple of 4
47
48 for (std::int32_t i = paddedBits - 1; i >= 0; --i) {
49 binaryString += ((value >> i) & 1) ? '1' : '0';
50
51 // Add a space after every 4 bits, except at the end
52 if (i % 4 == 0 && i != 0) {
53 binaryString += ' ';
54 }
55 }
56 return binaryString;
57}
58
59std::string getBitsSpaces(const std::int32_t num) {
60 std::string spaces;
61
62 for (std::int32_t i = num - 1; i >= 0; --i) {
63 spaces += ' ';
64 }
65
66 return spaces;
67}
68#ifndef CCSDS_MCU
69void printBufferData(const std::vector<std::uint8_t> &buffer, const std::int32_t limitBytes) {
70 std::cout << "[ ";
71 if (buffer.size() > limitBytes) {
72 for (size_t i= 0 ; i < static_cast<int>(limitBytes / 2); i++) {
73 std::cout << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>(buffer[i]) << " ";
74 }
75 std::cout << "... ";
76 for (size_t i = buffer.size() - static_cast<int>(limitBytes / 2) ; i < buffer.size(); i++) {
77 std::cout << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>(buffer[i]) << " ";
78 }
79 } else {
80 for (const unsigned char i: buffer) {
81 std::cout << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>(i) << " ";
82 }
83 }
84 std::cout << "]" << std::endl;
85}
86
87void printData(CCSDS::DataField dataField) {
88 const auto dataFieldHeader = dataField.getDataFieldHeaderBytes();
89 auto applicationData = dataField.getApplicationData();
90 const std::uint16_t maxSize = (applicationData.size() > dataFieldHeader.size())
91 ? applicationData.size()
92 : dataFieldHeader.size();
93
94 std::cout << " [CCSDS DATA] Data Field Length : " << applicationData.size() + dataFieldHeader.size() << " bytes" << std::endl;
95 std::cout << " [CCSDS DATA] Secondary Header Present : [ " << (dataField.getDataFieldHeaderFlag()
96 ? "True"
97 : "False") << " ]" << std::endl;
98 if (!dataFieldHeader.empty()) {
99 std::cout << " [CCSDS DATA] Secondary Header [Hex] : " << getBitsSpaces(
100 (maxSize - static_cast<std::uint16_t>(dataFieldHeader.size())) * 4);
101 printBufferData(dataFieldHeader);
102 }
103
104 std::cout << " [CCSDS DATA] Application Data [Hex] : ";
105 printBufferData(applicationData);
106 std::cout << std::endl;
107}
108
110 std::cout << " [CCSDS HEADER] Full Primary Header [Hex] : [ " << getBitsSpaces(17 - 12) << "0x" << std::hex <<
111 header.getFullHeader() << " ]" << std::endl;
112 std::cout << std::endl;
113
114 std::cout << " [CCSDS HEADER] Version Number : [ " << getBitsSpaces(19 - 4) <<
115 getBinaryString(header.getVersionNumber(), 3) << " ]";
116 std::cout << " - [Dec] : "<< std::dec << static_cast<int>( header.getVersionNumber()) << std::endl;
117
118 std::cout << " [CCSDS HEADER] Type : [ " << getBitsSpaces(19 - 4) <<
119 getBinaryString(header.getType(), 1) << " ]";
120 std::cout << " - [Dec] : "<< std::dec << static_cast<int>( header.getType()) << std::endl;
121
122 std::cout << " [CCSDS HEADER] Data Field Header Flag : [ " << getBitsSpaces(19 - 4) << getBinaryString(
123 header.getDataFieldHeaderFlag(), 1) << " ]";
124 std::cout << " - : " << (header.getDataFieldHeaderFlag() ? "True" : "False") << std::endl;
125
126 std::cout << " [CCSDS HEADER] APID : [ " << getBitsSpaces(17 - 12) <<
127 getBinaryString(header.getAPID(), 11) << " ]";
128 std::cout << " - [Dec] : " << std::dec << header.getAPID() << std::endl;
129
130 std::cout << " [CCSDS HEADER] Sequence Flags : [ " << getBitsSpaces(19 - 4) <<
131 getBinaryString(header.getSequenceFlags(), 2) << " ]";
132 std::cout << " - : ";
133 switch(header.getSequenceFlags()) {
134 case 0:
135 std::cout << "CONTINUING_SEGMENT";
136 break;
137 case 1:
138 std::cout << "FIRST_SEGMENT";
139 break;
140 case 2:
141 std::cout << "LAST_SEGMENT";
142 break;
143 case 3:
144 std::cout << "UNSEGMENTED";
145 break;
146 default:
147 break;
148 }
149 std::cout << std::endl;
150
151 std::cout << " [CCSDS HEADER] Sequence Count : [ " << getBitsSpaces(0) << getBinaryString(
152 header.getSequenceCount(), 14) << " ]";
153 std::cout << " - [Dec] : "<< std::dec << header.getSequenceCount() << std::endl;
154
155 std::cout << " [CCSDS HEADER] DataLength : [ " << getBinaryString(header.getDataLength(), 16) <<
156 " ]";
157 std::cout << " - [Dec] : "<< std::dec << header.getDataLength() << std::endl;
158
159 std::cout << std::endl;
160}
161
162
164 CCSDS::Header header;
165 FORWARD_RESULT(header.deserialize({packet.getPrimaryHeaderBytes()}));
166 printHeader(header);
167 return true;
168}
169
171 auto dataField = packet.getDataField();
172
173 printData(dataField);
174 std::cout << "[ CCSDSPack ] CRC-16 [Hex] : [ " << "0x" << std::hex << packet.getCRC() << " ]";
175 std::cout << " - [Dec] : "<< std::dec << packet.getCRC() << std::endl;
176
177}
178
180 printPrimaryHeader(packet);
181 printDataField(packet);
182}
183
185 std::cout << "[ CCSDS Manager ] Number of Packets : " << manager.getTotalPackets() << std::endl;
186 std::cout << "[ CCSDS Manager ] Sync Pattern Enabled : " << (manager.getSyncPatternEnable() ? "True" : "False") << std::endl;
187 std::cout << "[ CCSDS Manager ] Sync Pattern : 0x" << std::hex << manager.getSyncPattern() << std::dec << std::endl;
188
189 auto templatePacket = manager.getTemplate();
190 std::cout << "[ CCSDS Manager ] Template : " << std::endl ;
191 printPrimaryHeader(templatePacket);
192
193 std::int32_t idx = 1;
194 for (auto &packet: manager.getPacketsReference()) {
195 std::cout << "__________________________________________________________________________________________________________________" << std::endl;
196 std::cout << "[ CCSDS Manager ] Printing Packet [ " << idx << " ]:" << std::endl;
197 std::cout << "[ CCSDS Manager ] Packet Length : " << packet.getFullPacketLength() << " bytes" << std::endl;
198 std::cout << "[ CCSDS Manager ] Data ";
199 printBufferData(packet.serialize(), 20);
200 printPacket(packet);
201 idx++;
202 }
203}
204
205CCSDS::ResultBool writeBinaryFile(const std::vector<std::uint8_t>& data, const std::string& filename) {
206 RET_IF_ERR_MSG(filename.empty(),CCSDS::ErrorCode::FILE_WRITE_ERROR, "No filename provided");
207 RET_IF_ERR_MSG(data.empty(),CCSDS::ErrorCode::FILE_WRITE_ERROR, "No data provided");
208 std::ofstream out(filename, std::ios::binary);
209
210 RET_IF_ERR_MSG(!out,CCSDS::ErrorCode::FILE_WRITE_ERROR, "Failed to open file for writing");
211
212 // Write the entire vector data to the file in one go
213 out.write(reinterpret_cast<const char*>(data.data()), static_cast<std::streamsize>(data.size()));
214 RET_IF_ERR_MSG(!out,CCSDS::ErrorCode::FILE_WRITE_ERROR, "Failed to write the data to the file");
215
216 return true;
217}
218
219CCSDS::ResultBuffer readBinaryFile(const std::string& filename) {
220 RET_IF_ERR_MSG(filename.empty(),CCSDS::ErrorCode::FILE_READ_ERROR, "No filename provided");
221
222 std::ifstream in(filename, std::ios::binary | std::ios::ate);
223 RET_IF_ERR_MSG(!in,CCSDS::ErrorCode::FILE_READ_ERROR, "Failed to open file for reading");
224
225 // Get the file size using the 'ate' flag (seeks to the end automatically)
226 const std::streamsize size = in.tellg();
227 in.seekg(0, std::ios::beg);
228
229 // Read the entire file content into the vector
230 std::vector<std::uint8_t> data(size);
231 in.read(reinterpret_cast<char*>(data.data()), size);
232
233 RET_IF_ERR_MSG(!in,CCSDS::ErrorCode::FILE_READ_ERROR, "Failed to read the entire file");
234 return data;
235}
236
237bool fileExists(const std::string &fileName) {
238 auto res = readBinaryFile(fileName);
239 if ( res.has_value()) {
240 return true;
241 }
242 return false;
243}
244#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:80
std::uint16_t getAPID() const
11 bits
Definition CCSDSHeader.h:87
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:85
std::uint8_t getSequenceFlags() const
2 bits
Definition CCSDSHeader.h:88
std::uint16_t getSequenceCount() const
14 bits
Definition CCSDSHeader.h:89
std::uint8_t getVersionNumber() const
3 bits
Definition CCSDSHeader.h:84
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:86
std::uint16_t getDataLength() const
16 bits
Definition CCSDSHeader.h:90
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:59
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:82
@ FILE_READ_ERROR
Reading from file failure.
Definition CCSDSResult.h:32
@ FILE_WRITE_ERROR
Writing to file failure.
Definition CCSDSResult.h:33