diff --git a/scripts/logdecoder/logdecoder.cpp b/scripts/logdecoder/logdecoder.cpp index 670873a182784e3a882b1649fb48e69502e3b164..59b7e03aad83b09bb6baea4d986f205a4d3d41d1 100644 --- a/scripts/logdecoder/logdecoder.cpp +++ b/scripts/logdecoder/logdecoder.cpp @@ -42,25 +42,43 @@ using namespace tscpp; using namespace Boardcore; -void showUsage(string commandName); +void showUsage(const string& cmdName) +{ + std::cerr << "Usage: " << cmdName << " {-a | <log_file_name> | -h}" + << "Options:\n" + << "\t-h,--help\t\tShow help message\n" + << "\t-a,--all Deserialize all logs in the current directory\n" + << std::endl; +} -/** - * @brief Deserialize a file. - * - * @param fileName File name complete with extension. - * @return Whether the deserialization was successful. - */ -bool deserialize(string fileName); +bool deserialize(string logName) +{ + std::cout << "Deserializing " << logName << "...\n"; + Deserializer d(logName); + LogTypes::registerTypes(d); -/** - * @brief Deserialize all log file in the directory. Assumes the log files named - * as logXX.dat. - * - * Scans for all the 100 possible log files and decode the ones found. - * - * @return False if an error was encountered. - */ -bool deserializeAll(); + return d.deserialize(); +} + +bool deserializeAll() +{ + for (int i = 0; i < 100; i++) + { + char fn[10]; + char fnext[11]; + sprintf(fn, "log%02d", i); + sprintf(fnext, "log%02d.dat", i); + struct stat st; + if (stat(fnext, &st) != 0) + continue; // File not found + // File found + if (!deserialize(string(fn))) + { + return false; + } + } + return true; +} int main(int argc, char* argv[]) { @@ -93,47 +111,3 @@ int main(int argc, char* argv[]) std::cout << "Deserialization ended with errors\n"; return 0; } - -void showUsage(string commandName) -{ - std::cerr << "Usage: " << commandName << " {-a | <log_file_name> | -h}" - << "Options:\n" - << "\t-h,--help\t\tShow this help message\n" - << "\t-a,--all Deserialize all logs in the current directory " - "named as logXX.dat\n" - << std::endl; -} - -bool deserialize(string fileName) -{ - std::cout << "Deserializing " << fileName << "...\n"; - - Deserializer d(fileName); - LogTypes::registerTypes(d); - - return d.deserialize(); -} - -bool deserializeAll() -{ - std::cout << "Deserializing all logs in the current directory...\n"; - - for (int i = 0; i < 100; i++) - { - char fileName[11]; - sprintf(fileName, "log%02d.dat", i); - struct stat st; - - // Check if the current logfile exists - if (stat(fileName, &st) != 0) - continue; - - // File found - if (!deserialize(string(fileName))) - return false; - - std::cout << fileName << " deserialized successfully"; - } - - return true; -} diff --git a/src/shared/logger/Deserializer.h b/src/shared/logger/Deserializer.h index e0382dffcaec69b821faa0b7f28b81f0095c0a4a..f724e7342fcd46b5b7c014c67f7260eef2124fec 100644 --- a/src/shared/logger/Deserializer.h +++ b/src/shared/logger/Deserializer.h @@ -1,5 +1,5 @@ -/* Copyright (c) 2015-2018 Skyward Experimental Rocketry - * Author: Luca Erbetta +/* Copyright (c) 2015-2022 Skyward Experimental Rocketry + * Authors: Luca Erbetta, Alberto Nidasio * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -47,26 +47,31 @@ typedef std::numeric_limits<float> flt; // linter off /** - * Class used to deserialize log files created using fedetft's logger. + * @brief Class used to deserialize the binary logs created using fedetft's + * logger into csv files. */ class Deserializer { public: + /** + * @brief Initializes the deserializer with the filename provided. + */ Deserializer(std::string fileName); ~Deserializer(); /** - * Register a type to be deserialized, and the associated print function. + * @brief Register a type to be deserialized. + * + * Node: The object type must provide a static header function and a print + * function with the following prototypes: + * static std::string header() + * void print(std::ostream& os) const * - * @param t The object to be deserialized. - * @param fncPrint Function that prints the deserialized data on the - * provided output stream. - * @param header Optional CSV header text. + * @tparam T The object type to be deserialized. */ template <typename T> - bool registerType(std::function<void(T& t, std::ostream& os)> fncPrint, - std::string header = ""); + void registerType(); /** * @brief Deserializes the provided file. @@ -75,72 +80,84 @@ public: */ bool deserialize(); + /** + * @brief Closes all the openend files. + */ void close(); private: + /** + * @brief Function to print a data element into its csv file. + * + * @tparam T Type of the object. + * @param t Object to be printed in the file. + * @param path Path where to save the file. + * @param prefix Prefix added to the file. + */ + template <typename T> + void printType(T& t, std::string path = "", std::string prefix = ""); + bool closed = false; std::vector<std::ofstream*> fileStreams; tscpp::TypePoolStream tps; - std::string fileName; + std::string logFilename; + std::string logFilenameWithoutExtension; + std::string logFolderPath; }; -Deserializer::Deserializer(std::string fileName) : fileName(fileName) {} - -Deserializer::~Deserializer() +Deserializer::Deserializer(std::string logFilename) : logFilename(logFilename) { - if (!closed) - for (auto it = fileStreams.begin(); it != fileStreams.end(); it++) - { - (*it)->close(); - delete *it; - } + // Prepare the folder path + logFilenameWithoutExtension = + logFilename.substr(0, logFilename.find_last_of(".")); + logFolderPath = logFilenameWithoutExtension + "/"; } +Deserializer::~Deserializer() { close(); } + template <typename T> -bool Deserializer::registerType( - std::function<void(T& t, std::ostream& os)> fncPrint, std::string header) +void Deserializer::registerType() { - if (closed) - { - printf("Error: Deserializer is closed.\n"); - return false; - } - - char cFilename[128]; - sprintf(cFilename, "%s_%s.csv", fileName.c_str(), typeid(T).name()); - - std::string filename(cFilename); + std::function<void(T & t)> callback = + std::bind(&Deserializer::printType<T>, this, std::placeholders::_1, + logFolderPath, logFilenameWithoutExtension); - std::ofstream* stream = new std::ofstream(); - stream->open(filename); + tps.registerType<T>(callback); +} - if (!stream->is_open()) - { - printf("Error opening file %s.\n", filename.c_str()); - perror("Error is:"); - delete stream; - return false; - } +template <typename T> +void Deserializer::printType(T& t, std::string path, std::string prefix) +{ + static std::ofstream* stream = nullptr; - fileStreams.push_back(stream); - stream->precision(flt::max_digits10); // Set stream precision to - // maximum float precision - // Print the header - if (header.length() > 0) + // If not already initialize, open the file and write the header + if (stream == nullptr) { - *stream << header; - } + stream = new std::ofstream(); + std::string filename = + path + prefix + "_" + tscpp::demangle(typeid(T).name()) + ".csv"; + std::cout << "Creating file " + filename << std::endl; + stream->open(filename); - using namespace std::placeholders; // for _1 + if (!stream->is_open()) + { + printf("Error opening file %s.\n", filename.c_str()); + perror("Error is:"); + return; + } - std::function<void(T & t)> callback = - std::bind(fncPrint, _1, std::ref(*stream)); + // Print the header in the file + *stream << T::header(); - tps.registerType<T>(callback); + // Add the file to the vector such that it will be closed + fileStreams.push_back(stream); + } - return true; + // Print data into the file if it is open + if (stream->is_open()) + t.print(std::ref(*stream)); } bool Deserializer::deserialize() @@ -148,46 +165,54 @@ bool Deserializer::deserialize() if (closed) return false; - bool success = true; - std::string unknownTypeName; + // Create the folder + mkdir(logFolderPath.c_str(), 0777); - std::ifstream file(fileName); + // Move the log file into the folder + if (rename(logFilename.c_str(), (logFolderPath + logFilename).c_str())) + { + std::cout << logFilename + " does not exists." << std::endl; + return false; + } + + // Open the log file + std::ifstream file(logFolderPath + logFilename); // Check if the file exists if (!file) { - std::cout << fileName << " does not exists." << std::endl; + std::cout << logFolderPath + logFilename + " does not exists." + << std::endl; return false; } - tscpp::UnknownInputArchive ia(file, tps); - int i = 0; - while (success) + tscpp::UnknownInputArchive inputArchive(file, tps); + while (true) { try { - ia.unserialize(); + inputArchive.unserialize(); } catch (tscpp::TscppException& ex) { // Reached end of file if (strcmp(ex.what(), "eof") == 0) { - break; + return true; } + // Unknown type found else if (strcmp(ex.what(), "unknown type") == 0) { - unknownTypeName = ex.name(); - success = false; + std::string unknownTypeName = ex.name(); std::cout << "Unknown type found: " << unknownTypeName << std::endl; - break; + return false; } } } file.close(); - return success; + return true; } void Deserializer::close() diff --git a/src/shared/logger/LogTypes.h b/src/shared/logger/LogTypes.h index bb2a1c06dfee3da621fe2676f56cdce841af3904..b0c45d193df4c9aac7924a41dd4a7e82aef716cf 100644 --- a/src/shared/logger/LogTypes.h +++ b/src/shared/logger/LogTypes.h @@ -22,6 +22,7 @@ #pragma once +#include <actuators/Servo/ServoData.h> #include <algorithms/NAS/NASState.h> #include <diagnostic/PrintLoggerData.h> #include <drivers/adc/InternalADCData.h> @@ -71,53 +72,42 @@ namespace Boardcore namespace LogTypes { -template <typename T> -void print(T& t, std::ostream& os) -{ - t.print(os); -} - -template <typename T> -void registerType(Deserializer& ds) -{ - ds.registerType<T>(print<T>, T::header()); -} - void registerTypes(Deserializer& ds) { - registerType<NASState>(ds); - registerType<LoggingString>(ds); - registerType<InternalADCData>(ds); - registerType<EventData>(ds); - registerType<LoggerStats>(ds); - registerType<MavlinkStatus>(ds); - registerType<Xbee::XbeeStatus>(ds); - registerType<TaskStatsResult>(ds); - registerType<ADS1118Data>(ds); - registerType<ADS131M04Data>(ds); - registerType<BME280Data>(ds); - registerType<BMP280Data>(ds); - registerType<BMX160Data>(ds); - registerType<BMX160WithCorrectionData>(ds); - registerType<HX711Data>(ds); - registerType<L3GD20Data>(ds); - registerType<LIS3DSHData>(ds); - registerType<LIS3MDLData>(ds); - registerType<MBLoadCellData>(ds); - registerType<MPU9250Data>(ds); - registerType<MS5803Data>(ds); - registerType<TemperatureData>(ds); - registerType<UbloxGPSData>(ds); - registerType<VN100Data>(ds); - registerType<BatteryVoltageSensorData>(ds); - registerType<CurrentSensorData>(ds); - registerType<LoadCellData>(ds); - registerType<MPXHZ6130AData>(ds); - registerType<HSCMAND015PAData>(ds); - registerType<HSCMRNN030PAData>(ds); - registerType<HSCMRNN160KAData>(ds); - registerType<SSCDANN030PAAData>(ds); - registerType<SSCDRRN015PDAData>(ds); + ds.registerType<ServoData>(); + ds.registerType<NASState>(); + ds.registerType<LoggingString>(); + ds.registerType<InternalADCData>(); + ds.registerType<EventData>(); + ds.registerType<LoggerStats>(); + ds.registerType<MavlinkStatus>(); + ds.registerType<Xbee::XbeeStatus>(); + ds.registerType<TaskStatsResult>(); + ds.registerType<ADS1118Data>(); + ds.registerType<ADS131M04Data>(); + ds.registerType<BME280Data>(); + ds.registerType<BMP280Data>(); + ds.registerType<BMX160Data>(); + ds.registerType<BMX160WithCorrectionData>(); + ds.registerType<HX711Data>(); + ds.registerType<L3GD20Data>(); + ds.registerType<LIS3DSHData>(); + ds.registerType<LIS3MDLData>(); + ds.registerType<MBLoadCellData>(); + ds.registerType<MPU9250Data>(); + ds.registerType<MS5803Data>(); + ds.registerType<TemperatureData>(); + ds.registerType<UbloxGPSData>(); + ds.registerType<VN100Data>(); + ds.registerType<BatteryVoltageSensorData>(); + ds.registerType<CurrentSensorData>(); + ds.registerType<LoadCellData>(); + ds.registerType<MPXHZ6130AData>(); + ds.registerType<HSCMAND015PAData>(); + ds.registerType<HSCMRNN030PAData>(); + ds.registerType<HSCMRNN160KAData>(); + ds.registerType<SSCDANN030PAAData>(); + ds.registerType<SSCDRRN015PDAData>(); } } // namespace LogTypes