Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
PeterJohnson committed Dec 27, 2023
1 parent 8fa969d commit 1817d37
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 42 deletions.
134 changes: 106 additions & 28 deletions sysid/src/main/native/cpp/view/LogLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,61 +4,139 @@

#include "sysid/view/LogLoader.h"

#include <exception>
#include <algorithm>
#include <span>
#include <string_view>
#include <system_error>

#include <imgui.h>
#include <portable-file-dialogs.h>
#include <wpi/fs.h>
#include <wpi/timestamp.h>
#include <wpi/SmallVector.h>
#include <wpi/SpanExtras.h>
#include <wpi/StringExtras.h>

#include "glass/support/DataLogReaderThread.h"
#include "sysid/Util.h"
#include "sysid/analysis/JSONConverter.h"

using namespace sysid;

void LogLoader::DisplayConverter(
const char* tooltip,
std::function<std::string(std::string_view, wpi::Logger&)> converter) {
if (ImGui::Button(tooltip)) {
void LogLoader::Display() {
if (ImGui::Button("Open data log file...")) {
m_opener = std::make_unique<pfd::open_file>(
tooltip, "", std::vector<std::string>{"JSON File", SYSID_PFD_JSON_EXT});
"Select Data Log", "",
std::vector<std::string>{"DataLog Files", "*.wpilog"});
}

if (m_opener && m_opener->ready()) {
// Handle opening the file
if (m_opener && m_opener->ready(0)) {
if (!m_opener->result().empty()) {
m_location = m_opener->result()[0];
try {
converter(m_location, m_logger);
m_timestamp = wpi::Now() * 1E-6;
} catch (const std::exception& e) {
ImGui::OpenPopup("Exception Caught!");
m_exception = e.what();
m_filename = m_opener->result()[0];

std::error_code ec;
auto buf = wpi::MemoryBuffer::GetFile(m_filename, ec);
if (ec) {
ImGui::OpenPopup("Error");
m_error = fmt::format("Could not open file: {}", ec.message());
return;
}

wpi::log::DataLogReader reader{std::move(buf)};
if (!reader.IsValid()) {
ImGui::OpenPopup("Error");
m_error = "Not a valid datalog file";
return;
}
m_reader =
std::make_unique<glass::DataLogReaderThread>(std::move(reader));
m_entryTree.clear();
}
m_opener.reset();
}

if (wpi::Now() * 1E-6 - m_timestamp < 5) {
ImGui::SameLine();
ImGui::Text("Saved!");
}

// Handle exceptions.
// Handle errors
ImGui::SetNextWindowSize(ImVec2(480.f, 0.0f));
if (ImGui::BeginPopupModal("Exception Caught!")) {
if (ImGui::BeginPopupModal("Error")) {
ImGui::PushTextWrapPos(0.0f);
ImGui::Text(
"An error occurred when parsing the JSON. This most likely means that "
"the JSON data is incorrectly formatted.");
ImGui::TextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f), "%s",
m_exception.c_str());
ImGui::TextUnformatted(m_error.c_str());
ImGui::PopTextWrapPos();
if (ImGui::Button("Close")) {
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}

if (!m_reader) {
return;
}

// Summary info
ImGui::TextUnformatted(fs::path{m_filename}.stem().string().c_str());
ImGui::Text("%u records, %u entries%s", m_reader->GetNumRecords(),
m_reader->GetNumEntries(),
m_reader->IsDone() ? "" : " (working)");

if (!m_reader->IsDone()) {
return;
}

// Display tree of entries
if (m_entryTree.empty()) {
RebuildEntryTree();
}

DisplayEntryTree(m_entryTree);
}

void LogLoader::Display() {
DisplayConverter("Select SysId JSON", sysid::ToCSV);
void LogLoader::RebuildEntryTree() {
wpi::SmallVector<std::string_view, 16> parts;
m_reader->ForEachEntryName([&](const glass::DataLogReaderThread::Entry&
entry) {
parts.clear();
// split on first : if one is present
auto [prefix, mainpart] = wpi::split(entry.name, ':');
if (mainpart.empty() || wpi::contains(prefix, '/')) {
mainpart = entry.name;
} else {
parts.emplace_back(prefix);
}
wpi::split(mainpart, parts, '/', -1, false);

// ignore a raw "/" key
if (parts.empty()) {
return;
}

// get to leaf
auto nodes = &m_entryTree;
for (auto part : wpi::drop_back(std::span{parts.begin(), parts.end()})) {
auto it =
std::find_if(nodes->begin(), nodes->end(),
[&](const auto& node) { return node.name == part; });
if (it == nodes->end()) {
nodes->emplace_back(part);
// path is from the beginning of the string to the end of the current
// part; this works because part is a reference to the internals of
// entry.name
nodes->back().path.assign(
entry.name.data(), part.data() + part.size() - entry.name.data());
it = nodes->end() - 1;
}
nodes = &it->children;
}

auto it = std::find_if(nodes->begin(), nodes->end(), [&](const auto& node) {
return node.name == parts.back();
});
if (it == nodes->end()) {
nodes->emplace_back(parts.back());
// no need to set path, as it's identical to entry.name
it = nodes->end() - 1;
}
it->entry = &entry;
});
}

void LogLoader::DisplayEntryTree(const std::vector<EntryTreeNode>& nodes) {}
29 changes: 15 additions & 14 deletions sysid/src/main/native/include/sysid/view/LogLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <string_view>

#include <glass/View.h>
#include <glass/support/DataLogReaderThread.h>
#include <portable-file-dialogs.h>
#include <wpi/Logger.h>

Expand Down Expand Up @@ -39,24 +40,24 @@ class LogLoader : public glass::View {
void Display() override;

private:
/**
* Helper method to display a specific JSON converter
*
* @param tooltip The tooltip describing the JSON converter
* @param converter The function that takes a filename path and performs the
* previously specifid JSON conversion.
*/
void DisplayConverter(
const char* tooltip,
std::function<std::string(std::string_view, wpi::Logger&)> converter);

wpi::Logger& m_logger;

std::string m_location;
std::string m_filename;
std::unique_ptr<pfd::open_file> m_opener;
std::unique_ptr<glass::DataLogReaderThread> m_reader;

std::string m_error;

std::string m_exception;
struct EntryTreeNode {
explicit EntryTreeNode(std::string_view name) : name{name} {}
std::string name; // name of just this node
std::string path; // full path if entry is nullptr
const glass::DataLogReaderThread::Entry* entry = nullptr;
std::vector<EntryTreeNode> children; // children, sorted by name
};
std::vector<EntryTreeNode> m_entryTree;

double m_timestamp = 0;
void RebuildEntryTree();
void DisplayEntryTree(const std::vector<EntryTreeNode>& nodes);
};
} // namespace sysid

0 comments on commit 1817d37

Please sign in to comment.