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