// Copyright (c) FIRST and other WPILib contributors. // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. #include #include #include #include #include #include #include "wpi/datalog/DataLogReader.hpp" #include "wpi/util/DenseMap.hpp" #include "wpi/util/MemoryBuffer.hpp" #include "wpi/util/print.hpp" int main(int argc, const char** argv) { if (argc != 2) { wpi::util::print(stderr, "Usage: printlog \n"); return EXIT_FAILURE; } auto fileBuffer = wpi::util::MemoryBuffer::GetFile(argv[1]); if (!fileBuffer) { wpi::util::print(stderr, "could not open file: {}\n", fileBuffer.error().message()); return EXIT_FAILURE; } wpi::log::DataLogReader reader{std::move(*fileBuffer)}; if (!reader) { wpi::util::print(stderr, "not a log file\n"); return EXIT_FAILURE; } wpi::util::DenseMap entries; for (auto&& record : reader) { if (record.IsStart()) { wpi::log::StartRecordData data; if (record.GetStartData(&data)) { wpi::util::print( "Start({}, name='{}', type='{}', metadata='{}') [{}]\n", data.entry, data.name, data.type, data.metadata, record.GetTimestamp() / 1000000.0); if (entries.find(data.entry) != entries.end()) { wpi::util::print("...DUPLICATE entry ID, overriding\n"); } entries[data.entry] = data; } else { wpi::util::print("Start(INVALID)\n"); } } else if (record.IsFinish()) { int entry; if (record.GetFinishEntry(&entry)) { wpi::util::print("Finish({}) [{}]\n", entry, record.GetTimestamp() / 1000000.0); auto it = entries.find(entry); if (it == entries.end()) { wpi::util::print("...ID not found\n"); } else { entries.erase(it); } } else { wpi::util::print("Finish(INVALID)\n"); } } else if (record.IsSetMetadata()) { wpi::log::MetadataRecordData data; if (record.GetSetMetadataData(&data)) { wpi::util::print("SetMetadata({}, '{}') [{}]\n", data.entry, data.metadata, record.GetTimestamp() / 1000000.0); auto it = entries.find(data.entry); if (it == entries.end()) { wpi::util::print("...ID not found\n"); } else { it->second.metadata = data.metadata; } } else { wpi::util::print("SetMetadata(INVALID)\n"); } } else if (record.IsControl()) { wpi::util::print("Unrecognized control record\n"); } else { wpi::util::print("Data({}, size={}) ", record.GetEntry(), record.GetSize()); auto entry = entries.find(record.GetEntry()); if (entry == entries.end()) { wpi::util::print("\n"); continue; } wpi::util::print(" [{}]\n", entry->second.name, entry->second.type, record.GetTimestamp() / 1000000.0); // handle systemTime specially if (entry->second.name == "systemTime" && entry->second.type == "int64") { int64_t val; if (record.GetInteger(&val)) { auto timeval = std::chrono::system_clock::time_point( std::chrono::microseconds(val)); wpi::util::print(" {:%Y-%m-%d %H:%M:%S}.{:06}\n", timeval, val % 1000000); } else { wpi::util::print(" invalid\n"); } continue; } if (entry->second.type == "double") { double val; if (record.GetDouble(&val)) { wpi::util::print(" {}\n", val); } else { wpi::util::print(" invalid\n"); } } else if (entry->second.type == "int64") { int64_t val; if (record.GetInteger(&val)) { wpi::util::print(" {}\n", val); } else { wpi::util::print(" invalid\n"); } } else if (entry->second.type == "string" || entry->second.type == "json") { std::string_view val; record.GetString(&val); wpi::util::print(" '{}'\n", val); } else if (entry->second.type == "boolean") { bool val; if (record.GetBoolean(&val)) { wpi::util::print(" {}\n", val); } else { wpi::util::print(" invalid\n"); } } else if (entry->second.type == "boolean[]") { std::vector val; if (record.GetBooleanArray(&val)) { wpi::util::print(" {}\n", fmt::join(val, ", ")); } else { wpi::util::print(" invalid\n"); } } else if (entry->second.type == "double[]") { std::vector val; if (record.GetDoubleArray(&val)) { wpi::util::print(" {}\n", fmt::join(val, ", ")); } else { wpi::util::print(" invalid\n"); } } else if (entry->second.type == "float[]") { std::vector val; if (record.GetFloatArray(&val)) { wpi::util::print(" {}\n", fmt::join(val, ", ")); } else { wpi::util::print(" invalid\n"); } } else if (entry->second.type == "int64[]") { std::vector val; if (record.GetIntegerArray(&val)) { wpi::util::print(" {}\n", fmt::join(val, ", ")); } else { wpi::util::print(" invalid\n"); } } else if (entry->second.type == "string[]") { std::vector val; if (record.GetStringArray(&val)) { wpi::util::print(" {}\n", fmt::join(val, ", ")); } else { wpi::util::print(" invalid\n"); } } } } }