Skip to content
Snippets Groups Projects
Select Git revision
  • sx1278-priority-fix
  • main default protected
  • sensor-manager-upd
  • ABK-PID-dev
  • zvk-dev
  • bfloat16
  • usart-debug
  • nas-pitot-correction
  • logger-documentation
  • arp
  • arp-gyro
  • async-fsm
  • chipselect-mux
  • nas-catch-dev
  • parafoil-mavlink-upd
  • mockup-main-software
  • quadspi-flash
  • quadspi-flash2
  • sx1278-resilience
  • units-impl
  • ARP-pre-2.7
  • PYXIS_ROCCARASO
  • PYXIS_EUROC
  • lynx-euroc
  • hermes-v1.0
  • hermes-flight-1
26 results

logdecoder.cpp

Blame
    • Pietro Bortolus's avatar
      7b450266
      [Logger] New logger with socrate · 7b450266
      Pietro Bortolus authored and Niccolò Betto's avatar Niccolò Betto committed
      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.
      7b450266
      History
      [Logger] New logger with socrate
      Pietro Bortolus authored and Niccolò Betto's avatar Niccolò Betto committed
      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;
        }
    }