Skyward boardcore
Loading...
Searching...
No Matches
Deserializer.h
Go to the documentation of this file.
1/* Copyright (c) 2015-2025 Skyward Experimental Rocketry
2 * Authors: Luca Erbetta, Alberto Nidasio, Pietro Bortolus, Niccolò Betto
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#pragma once
24
25#include <filesystem>
26#include <format>
27#include <fstream>
28#include <iostream>
29#include <limits>
30#include <stdexcept>
31#include <string>
32#include <unordered_map>
33#include <vector>
34
35#include "Logger.h"
36
37namespace Boardcore
38{
39
40using float32_t = float;
41using float64_t = double;
42
43namespace detail
44{
45template <typename T>
46void deserializeField(std::ifstream& in, std::ofstream& out)
47{
48 auto value = T{};
49 in.read(reinterpret_cast<char*>(&value), sizeof(T));
50
51 // Formatting with std::format is >2x faster than std::ostream
52 if constexpr (std::is_same_v<T, int8_t>)
53 out << std::format("{}", static_cast<int>(value));
54 else if constexpr (std::is_same_v<T, uint8_t>)
55 out << std::format("{}", static_cast<unsigned int>(value));
56 else
57 out << std::format("{}", value);
58}
59} // namespace detail
60
66{
67public:
71 Deserializer(std::filesystem::path fileName);
72
76 std::filesystem::path outputDirectory() const
77 {
78 return filename.parent_path() / filename.stem();
79 }
80
86 bool deserialize();
87
88private:
89 using FieldDeserializer =
90 std::function<void(std::ifstream&, std::ofstream&)>;
91
92 using DeserializeInstructions = std::vector<FieldDeserializer>;
93
104 std::ofstream createCSV(const std::string& typeName);
105
116 void registerType(const std::string& typeName, std::ifstream& file);
117
118 struct MappingRecord
119 {
120 std::ofstream file;
121 DeserializeInstructions instructions;
122 };
123
124 std::unordered_map<std::string, MappingRecord> typeMap;
125
126 std::filesystem::path filename;
127};
128
129Deserializer::Deserializer(std::filesystem::path filename)
130 : filename(std::move(filename))
131{
132}
133
134std::ofstream Deserializer::createCSV(const std::string& typeName)
135{
136 auto outputFile = outputDirectory() / (typeName + ".csv");
137 std::ofstream stream(outputFile);
138
139 if (!stream)
140 {
141 std::cerr << "Error opening file " << outputFile << std::endl;
142 throw std::runtime_error("Error opening file " + outputFile.string());
143 }
144
145 return stream;
146}
147
151void Deserializer::registerType(const std::string& typeName,
152 std::ifstream& file)
153{
154 // Create a new csv file for this type
155 auto outFile = createCSV(typeName);
156
157 // Read the number of fields
158 uint8_t fieldCount = file.get();
159 // Dummy null read
160 file.ignore();
161
162 // create an array to store the field types
163 DeserializeInstructions deserializeInstructions;
164 deserializeInstructions.reserve(fieldCount);
165 std::string header;
166
167 for (int i = 0; i < fieldCount; i++)
168 {
169 // get the name of the field
170 std::string fieldName;
171 std::getline(file, fieldName, '\0'); // Read until null terminator
172
173 header += fieldName + ",";
174
175 // Read the field type
176 char fieldType = file.get();
177 // Dummy null read
178 file.ignore();
179
180 switch (fieldType)
181 {
182 case TypeIDByte::Bool:
183 deserializeInstructions.push_back(
184 detail::deserializeField<bool>);
185 break;
186 case TypeIDByte::Char:
187 deserializeInstructions.push_back(
188 detail::deserializeField<char>);
189 break;
190 case TypeIDByte::Int8:
191 deserializeInstructions.push_back(
192 detail::deserializeField<int8_t>);
193 break;
195 deserializeInstructions.push_back(
196 detail::deserializeField<uint8_t>);
197 break;
199 deserializeInstructions.push_back(
200 detail::deserializeField<int16_t>);
201 break;
203 deserializeInstructions.push_back(
204 detail::deserializeField<uint16_t>);
205 break;
207 deserializeInstructions.push_back(
208 detail::deserializeField<int32_t>);
209 break;
211 deserializeInstructions.push_back(
212 detail::deserializeField<uint32_t>);
213 break;
215 deserializeInstructions.push_back(
216 detail::deserializeField<int64_t>);
217 break;
219 deserializeInstructions.push_back(
220 detail::deserializeField<uint64_t>);
221 break;
223 deserializeInstructions.push_back(
224 detail::deserializeField<float32_t>);
225 break;
227 deserializeInstructions.push_back(
228 detail::deserializeField<float64_t>);
229 break;
230 default:
231 std::cerr << "Unknown field type: " << fieldType << std::endl
232 << "Aborting deserialization" << std::endl;
233 throw std::runtime_error("Unknown field type: " +
234 std::to_string(fieldType));
235 }
236 }
237
238 // print the header to the CSV and remove the trailing comma
239 outFile << header.substr(0, header.size() - 1) << '\n';
240
241 auto result = typeMap.emplace(
242 typeName,
243 MappingRecord{std::move(outFile), std::move(deserializeInstructions)});
244
245 if (!result.second)
246 {
247 std::cerr << "Duplicate type: " << typeName << std::endl;
248 throw std::runtime_error("Duplicate type: " + typeName);
249 }
250
251 // Indent to reduce output clutter
252 std::cout << "\tFound type " << typeName << " with " << (int)fieldCount
253 << " fields" << std::endl;
254
255 return;
256}
257
259{
260 std::ifstream file(filename, std::ios::binary);
261 if (!file)
262 {
263 std::cerr << filename << " does not exists." << std::endl;
264 return false;
265 }
266
267 std::filesystem::create_directory(outputDirectory());
268
269 while (true)
270 {
271 std::string typeName;
272 std::getline(file, typeName, '\0'); // Read until null terminator
273
274 // Check if we reached end of file while trying to read the next type
275 if (file.eof())
276 break;
277
278 try
279 {
280 // if the first char of the type name is the mapping marker then
281 // this is the definition of a mapping and not data to be
282 // deserialized
283 if (typeName[0] == MappingMarker)
284 {
285 registerType(typeName.substr(1), file);
286 continue;
287 }
288
289 // get the correct parser for this type
290 auto& type = typeMap.at(typeName);
291
292 for (size_t i = 0; i < type.instructions.size(); ++i)
293 {
294 type.instructions[i](file, type.file);
295
296 if (i == type.instructions.size() - 1)
297 type.file.put('\n'); // newline after last field
298 else
299 type.file.put(','); // comma separator between fields
300 }
301 }
302 catch (const std::out_of_range& e)
303 {
304 std::cerr << "Type not found: " << typeName << std::endl;
305 return false;
306 }
307 catch (std::runtime_error& e)
308 {
309 std::cerr << "Error deserializing type: " << typeName << " - "
310 << e.what() << std::endl;
311 return false;
312 }
313 }
314
315 return true;
316}
317
318} // namespace Boardcore
Class used to deserialize the binary logs created using fedetft's logger into csv files.
std::filesystem::path outputDirectory() const
Returns the path to the directory where the log will be decoded.
Deserializer(std::filesystem::path fileName)
Initializes the deserializer with the filename provided.
bool deserialize()
Deserializes the provided file.
void deserializeField(std::ifstream &in, std::ofstream &out)
Driver for the VN100S IMU.
constexpr char MappingMarker
Marker character for a type mapping.
Definition Logger.h:50
@ UInt64
Definition Logger.h:64
@ Int32
Definition Logger.h:61
@ UInt16
Definition Logger.h:60
@ Float
Definition Logger.h:65
@ UInt32
Definition Logger.h:62
@ Double
Definition Logger.h:66
@ Int16
Definition Logger.h:59
@ Int64
Definition Logger.h:63
@ UInt8
Definition Logger.h:58
double float64_t
float float32_t
Definition WIZ5500.h:339