CCSDSPack
C++ Library for CCSDS Space Packet manipulation. i.e. generation, extraction, analisys and more
Loading...
Searching...
No Matches
exec_decoder.cpp
Go to the documentation of this file.
1
6#include <unordered_map>
7#include <string>
8#include <vector>
9#include <iostream>
10#include <chrono>
11#include <sstream>
12#include "CCSDSManager.h"
13#include "CCSDSHeader.h"
14#include "CCSDSResult.h"
15#include "CCSDSUtils.h"
16#include "exec_utils.h"
17
18
20 // ascii art generated on https://www.asciiart.eu/text-to-ascii-art
21 // with ANSI SHADOW Font, with 80 and Block frame
22
23 std::cout << std::endl <<
24 "▐▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▌\n"
25 "▐ ██████╗ ██████╗███████╗██████╗ ███████╗ ▌\n"
26 "▐ ██╔════╝██╔════╝██╔════╝██╔══██╗██╔════╝ ▌\n"
27 "▐ ██║ ██║ ███████╗██║ ██║███████╗ ▌\n"
28 "▐ ██║ ██║ ╚════██║██║ ██║╚════██║ █▀█░█▀█░█▀▀░█░█░ ▌\n"
29 "▐ ╚██████╗╚██████╗███████║██████╔╝███████║ █▀▀░█▀█░█░░░█▀▄░ ▌\n"
30 "▐ ╚═════╝ ╚═════╝╚══════╝╚═════╝ ╚══════╝ ▀░░░▀░▀░▀▀▀░▀░▀░ ▌\n"
31 "▐ ██████╗ ███████╗ ██████╗ ██████╗ ██████╗ ███████╗██████╗ ▌\n"
32 "▐ ██╔══██╗██╔════╝ ██╔════╝██╔═══██╗██╔══██╗██╔════╝██╔══██╗ ▌\n"
33 "▐ ██║ ██║█████╗ ██║ ██║ ██║██║ ██║█████╗ ██████╔╝ ▌\n"
34 "▐ ██║ ██║██╔══╝ ██║ ██║ ██║██║ ██║██╔══╝ ██╔══██╗ ▌\n"
35 "▐ ██████╔╝███████╗ ╚██████╗╚██████╔╝██████╔╝███████╗██║ ██║ ▌\n"
36 "▐ ╚═════╝ ╚══════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝ ▌\n"
37 "▐▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▌\n"
38 << std::endl;
39 std::cout << "Usage: ccsds_decoder [OPTIONS] - decode a ccsds binary file and generate a file from application data." << std::endl;
40 std::cout << "Mandatory parameters:" << std::endl;
41 std::cout << " -i or --input <filename> : input file to be encoded" << std::endl;;
42 std::cout << " -o or --output <filename> : Generated output file" << std::endl;;
43 std::cout << " -c or --config <filename> : Configuration file" << std::endl;
44 std::cout << std::endl;
45 std::cout << "Optionals:" << std::endl;
46 std::cout << " -h or --help : Show this help and message" << std::endl;
47 std::cout << " -v or --verbose : Show generated packets information" << std::endl;
48 std::cout << std::endl;
49 std::cout << "Template override: the template CCSDS packet read from the config file" << std::endl;
50 std::cout << "can be overwritten by using the following options. In the case not all" << std::endl;
51 std::cout << "parameters are used, the remaining parameters will be read from the" << std::endl;
52 std::cout << "configuration file." << std::endl;
53 std::cout << " -tv <int> : Template CCSDS version number (3 bits)" << std::endl;
54 std::cout << " -tt <bool> : Template CCSDS Type" << std::endl;
55 std::cout << " -ta <int> : Template CCSDS APID (11 bita)" << std::endl;
56 std::cout << " -th <bool> : Template CCSDS Secondary header presence" << std::endl;
57 std::cout << " -ts <bool> : Template CCSDS Segmented" << std::endl;
58 std::cout << std::endl;
59 std::cout << "For further information please visit: https://github.com/ExoSpaceLabs/CCSDSPack" << std::endl;
60}
61
62int main(const int argc, char* argv[]) {
63 std::string appName = "ccsds_decoder";
64
65 std::unordered_map<std::string, std::string> allowed;
66 allowed.insert({"h", "help"});
67 allowed.insert({"v", "verbose"});
68 allowed.insert({"i", "input"});
69 allowed.insert({"o", "output"});
70 allowed.insert({"c", "config"});
71
72 allowed.insert({"tv", "version_number"});
73 allowed.insert({"tt", "type"});
74 allowed.insert({"ta", "apid"});
75 allowed.insert({"th", "secondary_header"});
76 allowed.insert({"ts", "segmented"});
77
78 std::unordered_map<std::string, std::string> args;
79 args.insert({"verbose", "false"});
80 args.insert({"help", "false"});
81
82 const auto start = std::chrono::high_resolution_clock::now();
83 if (const auto exp = parseArguments(argc, argv, allowed, args); !exp.has_value()) {
84 std::cerr << "[ Error " << exp.error().code() << " ]: "<< exp.error().message() << std::endl ;
85 return exp.error().code();
86 }
87 // std::cout << "Parsed args:\n";
88 //for (const auto& [k, v] : args) {
89 // std::cout << " " << k << ": " << v << '\n';
90 //}
91 if (args["help"] == "true") {
93 return 0;
94 }
95 bool verbose{args["verbose"] == "true"};
96
97 if (args.find("input") == args.end()) {
98 std::cerr << "[ Error " << ARG_PARSE_ERROR << " ]: " << "Input file must be specified" << std::endl;
100 return ARG_PARSE_ERROR;
101 }
102
103 if (!fileExists(args["input"])) {
104 std::cerr << "[ Error " << ARG_PARSE_ERROR << " ]: " << "Input \"" << args["input"] << "\" does not exist" << std::endl;
105 return ARG_PARSE_ERROR;
106 }
107 const std::string input{args["input"]};
108 const std::string output{args["output"]};
109
110 if (output.empty()) {
111 std::cerr << "[ Error " << ARG_PARSE_ERROR << " ]: " << "Output file must be specified" << std::endl;
113 return ARG_PARSE_ERROR;
114 }
115
116 if (args.find("config") == args.end()) {
117 std::cerr << "[ Error " << ARG_PARSE_ERROR << " ]: " << "Config file must be specified" << std::endl;
119 return ARG_PARSE_ERROR;
120 }
121
122 if (!fileExists(args["config"])) {
123 std::cerr << "[ Error " << ARG_PARSE_ERROR << " ]: " << "Config \"" << args["config"] << "\" does not exist" << std::endl;
124 return ARG_PARSE_ERROR;
125 }
126 const std::string configFile{args["config"]};
127
128 // prepare template packet
129 customConsole(appName,"reading CCSDS configuration file: " + configFile);
130 Config cfg;
131 {
132 if (auto exp = cfg.load(configFile); !exp.has_value()) {
133 std::cerr << "[ Error " << exp.error().code() << " ]: "<< exp.error().message() << std::endl ;
134 return exp.error().code();
135 }
136 }
137
138 CCSDS::Header header;
139 uint8_t versionNumber;
140 uint8_t type;
141 uint8_t APID;
142 uint8_t dataFieldHeaderFlag;
143 uint16_t sequenceCount;
144 CCSDS::ESequenceFlag sequenceFlag;
145 uint16_t dataFieldSize;
146 bool segmented;
147 bool syncPatternEnable;
148 bool validationEnable;
149 uint32_t syncPattern;
150 if (args.find("version_number") == args.end()) {
151 if (!cfg.isKey("ccsds_version_number")) {
152 std::cerr << "[ Error " << CONFIG_MISSING_PARAMETER << " ]: " << "Config: Missing int field: ccsds_version_number"
153 << std::endl;
155 }
156 ASSIGN_OR_PRINT(versionNumber, cfg.get<int>("ccsds_version_number"));
157 }else {
158 versionNumber = std::stoi(args["version_number"]);
159 }
160
161 if (args.find("type") == args.end()) {
162 if (!cfg.isKey("ccsds_type")) {
163 std::cerr << "[ Error " << CONFIG_MISSING_PARAMETER << " ]: " << "Config: Missing bool field: ccsds_type" << std::endl;
165 }
166 ASSIGN_OR_PRINT(type, cfg.get<bool>("ccsds_type"));
167 }else {
168 type = args["type"] == "true";
169 }
170
171 if (args.find("secondary_header") == args.end()) {
172 if (!cfg.isKey("ccsds_data_field_header_flag")) {
173 std::cerr << "[ Error " << CONFIG_MISSING_PARAMETER << " ]: " << "Config: Missing bool field: ccsds_data_field_header_flag" << std::endl;
175 }
176 ASSIGN_OR_PRINT(dataFieldHeaderFlag, cfg.get<bool>("ccsds_data_field_header_flag"));
177 }else {
178 dataFieldHeaderFlag = args["secondary_header"] == "true";
179 }
180
181 if (args.find("apid") == args.end()) {
182 if (!cfg.isKey("ccsds_APID")) {
183 std::cerr << "[ Error " << CONFIG_MISSING_PARAMETER << " ]: " << "Config: Missing int field: ccsds_APID" << std::endl;
185 }
186 ASSIGN_OR_PRINT(APID, cfg.get<int>("ccsds_APID"));
187 }else {
188 APID = std::stoi(args["apid"]);
189 }
190
191 if (args.find("segmented") == args.end()) {
192 if (!cfg.isKey("ccsds_segmented")) {
193 std::cerr << "[ Error " << CONFIG_MISSING_PARAMETER << " ]: " << "Config: Missing bool field: ccsds_segmented" << std::endl;
195 }
196 ASSIGN_OR_PRINT(segmented, cfg.get<bool>("ccsds_segmented"));
197 }else {
198 segmented = args["segmented"] == "true";
199 }
200
201 if (!cfg.isKey("validation_enable")) {
202 std::cerr << "[ Error " << CONFIG_MISSING_PARAMETER << " ]: " << "Config: Missing bool field: validation_enable" << std::endl;
204 }
205
206 if (!cfg.isKey("data_field_size")) {
207 std::cerr << "[ Error " << CONFIG_MISSING_PARAMETER << " ]: " << "Config: Missing int field: data_field_size" << std::endl;
209 }
210
211 if (!cfg.isKey("sync_pattern_enable")) {
212 std::cerr << "[ Error " << CONFIG_MISSING_PARAMETER << " ]: " << "Config: Missing int field: sync_pattern_enable" << std::endl;
214 }
215
216 ASSIGN_OR_PRINT(dataFieldSize, cfg.get<int>("data_field_size"));
217 ASSIGN_OR_PRINT(syncPatternEnable, cfg.get<bool>("sync_pattern_enable"));
218 ASSIGN_OR_PRINT(validationEnable, cfg.get<bool>("validation_enable"));
219
220 { // optional definition of sync pattern
221 if (auto exp = cfg.get<int>("sync_pattern"); exp.has_value()) {
222 syncPattern = exp.value();
223 }
224 }
225
226 customConsole(appName,"creating CCSDS template packet");
227 if (segmented) {
228 sequenceCount = 1;
230 }else {
231 sequenceCount = 0;
233 }
234
235 header.setVersionNumber(versionNumber);
236 header.setType(type);
237 header.setAPID(APID);
238 header.setDataFieldHeaderFlag(dataFieldHeaderFlag);
239 header.setSequenceFlags(sequenceFlag);
240 header.setSequenceCount(sequenceCount);
241
242 CCSDS::Packet templatePacket;
243 templatePacket.setPrimaryHeader(header);
244
245 CCSDS::Manager manager(templatePacket);
246 manager.setDatFieldSize(dataFieldSize);
247 manager.setSyncPatternEnable(syncPatternEnable);
248 if (syncPatternEnable && cfg.isKey("sync_pattern")) {
249 manager.setSyncPattern(syncPattern);
250 }
251 std::vector<uint8_t> inputBytes;
252
253 customConsole(appName,"reading data from " + input);
254 if (const auto exp = readBinaryFile(input); !exp.has_value()) {
255 std::cerr << "[ Error " << exp.error().code() << " ]: "<< exp.error().message() << std::endl ;
256 return exp.error().code();
257 }else {
258 inputBytes = exp.value();
259 if (!segmented && inputBytes.size() > dataFieldSize){
260 std::cerr << "[ Error " << INVALID_INPUT_DATA << " ]: "<< "Input data is too big for unsegmented packets, data "
261 << inputBytes.size() << " must be less than defined data packet length of " << dataFieldSize << std::endl ;
262 return INVALID_INPUT_DATA;
263 }
264 }
265 customConsole(appName, "deserializing CCSDS packets from file");
266 if (const auto exp = manager.load(inputBytes); !exp.has_value()) {
267 std::cerr << "[ Error " << exp.error().code() << " ]: "<< exp.error().message() << std::endl ;
268 return exp.error().code();
269 }
270 if (verbose) customConsole(appName,"printing loaded packets data to screen:");
271 if (verbose) printPackets(manager);
272
273 customConsole(appName,"retrieving Application data from CCSDS packets");
274 manager.setAutoValidateEnable(validationEnable);
275 std::vector<uint8_t> outputData;
276 if (const auto exp = manager.getApplicationDataBuffer(); !exp.has_value()) {
277 std::cerr << "[ Error " << exp.error().code() << " ]: "<< exp.error().message() << std::endl ;
278 return exp.error().code();
279 }else {
280 outputData = exp.value();
281 }
282
283 customConsole(appName,"writing data to " + output);
284 if (const auto exp = writeBinaryFile(outputData, output); !exp.has_value()) {
285 std::cerr << "[ Error " << exp.error().code() << " ]: "<< exp.error().message() << std::endl ;
286 return exp.error().code();
287 }
288
289 const auto end = std::chrono::high_resolution_clock::now();
290 const auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
291 customConsole(appName,"execution time: " + std::to_string(duration.count()) + " [us]");
292 customConsole(appName,"[ Exit code 0 ]");
293 return 0;
294}
#define ASSIGN_OR_PRINT(var, result)
Macro to assign a result value or print an error message.
bool fileExists(const std::string &fileName)
filesystem check fore file existence prepared for both windows and linux.
CCSDS::ResultBuffer readBinaryFile(const std::string &filename)
Read a specified binary file and return its contents as a buffer.
CCSDS::ResultBool writeBinaryFile(const std::vector< 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.
Manages the decomposition and manipulation of CCSDS primary headers.
Definition CCSDSHeader.h:80
void setVersionNumber(const uint8_t &value)
3 bits
void setSequenceCount(const uint16_t &value)
14 bits
void setSequenceFlags(const uint8_t &value)
2 bits
void setAPID(const uint16_t &value)
11 bits
void setDataFieldHeaderFlag(const uint8_t &value)
1 bits
void setType(const uint8_t &value)
1 bits
Manages CCSDS packets and their templates.
void setDatFieldSize(uint16_t size)
Sets the size of the data field.
void setSyncPatternEnable(bool enable)
enable sync pattern utilization both in serialization, deserialization, read and write.
ResultBool load(const std::vector< Packet > &packets)
Load a vector of packets.
ResultBuffer getApplicationDataBuffer()
Retrieves the application data from the packets.
void setSyncPattern(uint32_t syncPattern)
set sync pattern that should indicate the start of a CCSDS packet.
void setAutoValidateEnable(bool enable)
Enables or disables automatic validation of packets.
Represents a CCSDS (Consultative Committee for Space Data Systems) packet.
Definition CCSDSPacket.h:60
void setPrimaryHeader(PrimaryHeader data)
Sets the primary header using the provided PrimaryHeader object.
bool has_value() const
Checks if the result contains a valid value.
Parses and stores config values from custom file format.
Definition CCSDSUtils.h:145
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 CCSDSUtils.h:154
int main(const int argc, char *argv[])
void printHelpDecoder()
This is the source file that holds the execution logic of ccsds_encoder binary file.
void customConsole(const std::string &appName, const std::string &message, const std::string &logLevel="INFO")
@ CONFIG_MISSING_PARAMETER
Definition exec_utils.h:11
@ ARG_PARSE_ERROR
Error Parsing argument.
Definition exec_utils.h:10
@ INVALID_INPUT_DATA
Definition exec_utils.h:12
CCSDS::ResultBool parseArguments(int argc, char *argv[], std::unordered_map< std::string, std::string > &allowedMap, std::unordered_map< std::string, std::string > &outArgs)
This is the source file that holds the execution logic of ccsds_encoder binary file.
ESequenceFlag
Represents the sequence flags used in CCSDS telemetry transfer frames.
Definition CCSDSHeader.h:19
@ UNSEGMENTED
11 Complete packet in a single frame.
Definition CCSDSHeader.h:23
@ FIRST_SEGMENT
01 First segment of a new packet.
Definition CCSDSHeader.h:21