Select Git revision
logdecoder.cpp
-
We have decided to use socrate instead of tscpp for logging because it allows for more flexibility. When a new type is logged the system also logs a mapping string that encodes the structure of that type. This string is then used in the deserializer to get the structure of the type and deserialize it correctly.
We have decided to use socrate instead of tscpp for logging because it allows for more flexibility. When a new type is logged the system also logs a mapping string that encodes the structure of that type. This string is then used in the deserializer to get the structure of the type and deserialize it correctly.
logdecoder.cpp 5.02 KiB
/* Copyright (c) 2025 Skyward Experimental Rocketry
* Author: Niccolò Betto
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <fmt/format.h>
#include <logger/Deserializer.h>
#include <chrono>
#include <filesystem>
#include <iomanip>
#include <iostream>
#include <string_view>
/**
* @brief Binary log file decoder.
*
* This program deserializes binary log files generated by the Skyward boards
* to CSV files, each containing the data of a specific type.
*/
using namespace std::chrono;
using namespace Boardcore;
// cppcheck-suppress passedByValue
void printUsage(std::string_view cmdName)
{
std::cerr
<< "Skyward Log Decoder\n"
<< "Usage: " << cmdName << " [OPTIONS] [FILES]\n\n"
<< "FILES may be a mix of files and directories.\n"
<< "With no FILES specified, deserialize all log files in the current "
"directory.\n\n"
<< "Options:\n"
<< " -h, --help\t\tDisplay this help and exit\n";
}
bool deserialize(const std::filesystem::path& file)
{
Deserializer d(file);
std::cout << "Deserializing " << file << " to " << d.outputDirectory()
<< '\n';
auto start = steady_clock::now();
bool result = d.deserialize();
auto end = steady_clock::now();
if (result)
{
auto duration =
std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "Successfully deserialized " << file << " in " << duration
<< '\n';
}
else
{
std::cerr << "Failed to deserialize " << file << '\n';
}
return result;
}
bool deserializeDirectory(const std::filesystem::path& directory)
{
std::cout << "Deserializing all log files in " << directory << '\n';
if (!std::filesystem::is_directory(directory))
{
std::cerr << directory << " is not a directory\n";
return false;
}
bool success = true;
int count = 0;
for (int i = 0; i < Logger::getMaxFilenameNumber(); i++)
{
auto file = directory / fmt::format("log{:02d}.dat", i);
if (!std::filesystem::is_regular_file(file))
continue;
count++;
success &= deserialize(file);
}
if (count == 0)
std::cerr << "No log files found in " << directory << '\n';
return success;
}
int main(int argc, char* argv[])
{
auto exeName = argv[0];
// A list of files and directories to deserialize
std::vector<std::filesystem::path> files;
// Parse arguments
for (int i = 1; i < argc; i++)
{
auto arg = std::string_view(argv[i]);
// Help option
if (arg == "-h" || arg == "--help")
{
printUsage(exeName);
return 0;
}
// Invalid option
if (arg.starts_with("-"))
{
std::cerr << exeName << ": invalid option "
<< std::quoted(arg, '\'') << '\n'
<< "Try '" << exeName
<< " --help' for more information.\n";
return 1;
}
// File or directory argument
auto file = std::filesystem::path(arg);
if (std::filesystem::exists(arg))
{
files.push_back(file);
}
else
{
std::cerr << "File " << file << " does not exist\n";
return 1;
}
}
// If no files are provided, deserialize all log files in the current dir
if (files.empty())
{
std::cout << "No files specified, deserializing all log files in "
"current directory\n";
files.push_back(std::filesystem::current_path());
}
bool success = true;
// Deserialize all files
for (const auto& file : files)
if (std::filesystem::is_directory(file))
success &= deserializeDirectory(file);
else
success &= deserialize(file);
if (success)
{
std::cout << "Done\n";
return 0;
}
else
{
std::cerr << "Error: one or more files failed to deserialize\n";
return 1;
}
}