From 0a0d70cd935d8206cb887b52005a1acb1861e84a Mon Sep 17 00:00:00 2001 From: Piotr Wasilewski Date: Mon, 16 Sep 2024 20:35:00 +0200 Subject: [PATCH 01/24] feature: working on csv data streaming --- CMakeLists.txt | 5 +- .../MCUViewer_project/MCUViewer_test.cfg | 6 +- src/CSVStreamer/CSVStreamer.hpp | 128 ++++++++++++++++++ src/FileHandler/IFileHandler.hpp | 1 + src/FileHandler/NFDFileHandler.cpp | 11 +- src/FileHandler/NFDFileHandler.hpp | 4 +- src/Gui/Gui.cpp | 13 ++ src/Gui/Gui.hpp | 2 + src/Gui/GuiAcqusition.cpp | 35 +++++ src/Gui/GuiPlots.cpp | 2 +- src/PlotHandler/PlotHandler.cpp | 25 ++++ src/PlotHandler/PlotHandler.hpp | 6 +- 12 files changed, 231 insertions(+), 7 deletions(-) create mode 100644 src/CSVStreamer/CSVStreamer.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e514dc5..25e67878 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ project(MCUViewer) set(MCUVIEWER_VERSION 1.0.0) -set(CMAKE_BUILD_TYPE Release) +set(CMAKE_BUILD_TYPE Debug) set(CMAKE_CXX_STANDARD 20) set(CMAKE_EXPORT_COMPILE_COMMANDS 1) @@ -188,7 +188,8 @@ target_include_directories(${EXECUTABLE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/TraceReader ${CMAKE_CURRENT_SOURCE_DIR}/src/RingBuffer ${CMAKE_CURRENT_SOURCE_DIR}/src/Statistics - ${CMAKE_CURRENT_SOURCE_DIR}/src/GdbParser) + ${CMAKE_CURRENT_SOURCE_DIR}/src/GdbParser + ${CMAKE_CURRENT_SOURCE_DIR}/src/CSVStreamer) target_include_directories(${EXECUTABLE} SYSTEM PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/stlink/inc/ diff --git a/example/STMViewer_test/MCUViewer_project/MCUViewer_test.cfg b/example/STMViewer_test/MCUViewer_project/MCUViewer_test.cfg index d0449869..7b07920e 100644 --- a/example/STMViewer_test/MCUViewer_project/MCUViewer_test.cfg +++ b/example/STMViewer_test/MCUViewer_project/MCUViewer_test.cfg @@ -10,7 +10,7 @@ refresh_on_elf_change = true stop_acq_on_elf_change = true probe_type = 1 target_name = STM32G474CC -probe_mode = 1 +probe_mode = 0 probe_speed_khz = 50000 probe_sn = 506003225 @@ -22,6 +22,10 @@ max_viewport_points_percent = 10 trigger_channel = -1 trigger_level = 0.000000 timeout = 2 +probe_type = 0 +target_name = +probe_speed_khz = 10000 +probe_sn = [var0] name = test.a diff --git a/src/CSVStreamer/CSVStreamer.hpp b/src/CSVStreamer/CSVStreamer.hpp new file mode 100644 index 00000000..25821120 --- /dev/null +++ b/src/CSVStreamer/CSVStreamer.hpp @@ -0,0 +1,128 @@ +#ifndef _CSV_STREAMER_HPP +#define _CSV_STREAMER_HPP + +#include +#include +#include +#include +#include + +class CSVStreamer +{ + public: + struct Buffer + { + std::array buffer; + size_t index; + Buffer* nextBuffer; + + bool appendLine(std::string& line) + { + if (isFull()) + { + return false; + } + + buffer[index] = line; + index++; + return true; + } + + bool isFull() const + { + return (index + 1) >= buffer.size(); + } + }; + + CSVStreamer() + { + currentBuffer = &buffer1; + buffer1.nextBuffer = &buffer2; + buffer2.nextBuffer = &buffer1; + } + + ~CSVStreamer() + { + finishLogging(); + } + + std::string getFilePath() const + { + return filePath; + } + + bool prepareFile(std::string& directory) + { + filePath = directory + "/logfile.csv"; + csvFile.open(filePath, std::ios::app); + if (!csvFile.is_open()) + { + std::cerr << "Failed to open file: " << filePath << std::endl; + return false; + } + return true; + } + + void createHeader(const std::vector& values) + { + std::string header; + for (const auto& value : values) + { + header += value + ","; + } + header.back() = '\n'; + currentBuffer->appendLine(header); + } + + void writeLine(double time, const std::vector& values) + { + std::string line = std::to_string(time) + ","; + for (const auto& value : values) + { + line += std::to_string(value) + ","; + } + line.back() = '\n'; + + currentBuffer->appendLine(line); + + if (currentBuffer->isFull()) + { + processingBuffer = currentBuffer; + currentBuffer = currentBuffer->nextBuffer; + currentBuffer->index = 0; + saveTask = std::async(std::launch::async, &CSVStreamer::save, this); + } + } + + void save() + { + if (!csvFile.is_open()) + { + std::cerr << "CSV file is not open!" << std::endl; + return; + } + for (const auto& line : processingBuffer->buffer) + { + csvFile << line; + } + } + + void finishLogging() + { + if (csvFile.is_open()) + { + csvFile.close(); + } + } + + private: + std::future saveTask{}; + std::string filePath; + std::ofstream csvFile; + Buffer buffer1; + Buffer buffer2; + Buffer* currentBuffer; + Buffer* processingBuffer; +}; + +#endif \ No newline at end of file diff --git a/src/FileHandler/IFileHandler.hpp b/src/FileHandler/IFileHandler.hpp index ca4fc7b1..e0751660 100644 --- a/src/FileHandler/IFileHandler.hpp +++ b/src/FileHandler/IFileHandler.hpp @@ -12,6 +12,7 @@ class IFileHandler virtual bool deinit() = 0; virtual std::string openFile(std::pair&& filterFileNameFileExtension) = 0; virtual std::string saveFile(std::pair&& filterFileNameFileExtension) = 0; + virtual std::string openDirectory(std::pair&& filterFileNameFileExtension) = 0; }; #endif \ No newline at end of file diff --git a/src/FileHandler/NFDFileHandler.cpp b/src/FileHandler/NFDFileHandler.cpp index 9f436f7e..c8e157e6 100644 --- a/src/FileHandler/NFDFileHandler.cpp +++ b/src/FileHandler/NFDFileHandler.cpp @@ -5,25 +5,32 @@ #include "nfd.h" - bool NFDFileHandler::init() { return NFD_Init() != NFD_ERROR; } + bool NFDFileHandler::deinit() { NFD_Quit(); return true; } + std::string NFDFileHandler::openFile(std::pair&& filterFileNameFileExtension) { return handleFile(handleType::OPEN, filterFileNameFileExtension); } + std::string NFDFileHandler::saveFile(std::pair&& filterFileNameFileExtension) { return handleFile(handleType::SAVE, filterFileNameFileExtension); } +std::string NFDFileHandler::openDirectory(std::pair&& filterFileNameFileExtension) +{ + return handleFile(handleType::OPENDIR, filterFileNameFileExtension); +} + std::string NFDFileHandler::handleFile(handleType type, std::pair& filterFileNameFileExtension) { nfdchar_t* outPath = nullptr; @@ -35,6 +42,8 @@ std::string NFDFileHandler::handleFile(handleType type, std::pair&& filterFileNameFileExtension) override; std::string saveFile(std::pair&& filterFileNameFileExtension) override; + std::string openDirectory(std::pair&& filterFileNameFileExtension) override; private: enum class handleType { SAVE, - OPEN + OPEN, + OPENDIR }; std::string handleFile(handleType type, std::pair& filterFileNameFileExtension); }; diff --git a/src/Gui/Gui.cpp b/src/Gui/Gui.cpp index dc87b5e8..67bb4d06 100644 --- a/src/Gui/Gui.cpp +++ b/src/Gui/Gui.cpp @@ -1020,6 +1020,19 @@ bool Gui::openElfFile() return false; } +bool Gui::openLogDirectory(std::string& logDirectory) +{ + std::string path = fileHandler->openDirectory({"", ""}); + + if (path != "") + { + logDirectory = path; + logger->info("Log directory: {}", path); + return true; + } + return false; +} + std::string Gui::convertProjectPathToAbsolute(const std::string& relativePath) { if (relativePath.empty()) diff --git a/src/Gui/Gui.hpp b/src/Gui/Gui.hpp index fa421af8..cb6678c5 100644 --- a/src/Gui/Gui.hpp +++ b/src/Gui/Gui.hpp @@ -94,6 +94,7 @@ class Gui void drawPlotsTree(); void drawAcqusitionSettingsWindow(ActiveViewType type); void acqusitionSettingsViewer(); + void drawLoggingSettings(); void drawAboutWindow(); void drawPreferencesWindow(); void drawStatisticsAnalog(std::shared_ptr plt); @@ -115,6 +116,7 @@ class Gui bool saveProjectAs(); void showChangeFormatPopup(const char* text, Plot& plt, const std::string& name); bool openElfFile(); + bool openLogDirectory(std::string& logDirectory); std::string convertProjectPathToAbsolute(const std::string& projectRelativePath); void checkShortcuts(); bool checkElfFileChanged(); diff --git a/src/Gui/GuiAcqusition.cpp b/src/Gui/GuiAcqusition.cpp index 7b206823..af87e15f 100644 --- a/src/Gui/GuiAcqusition.cpp +++ b/src/Gui/GuiAcqusition.cpp @@ -49,6 +49,8 @@ void Gui::acqusitionSettingsViewer() plotHandler->setSettings(settings); drawDebugProbes(); + + drawLoggingSettings(); } void Gui::drawDebugProbes() @@ -161,6 +163,39 @@ void Gui::drawDebugProbes() ImGui::PopID(); } +void Gui::drawLoggingSettings() +{ + static bool logging = false; + static std::string directory = ""; + + PlotHandler::Settings settings = plotHandler->getSettings(); + + ImGui::PushID("logging"); + ImGui::Dummy(ImVec2(-1, 5)); + drawCenteredText("Logging"); + ImGui::SameLine(); + ImGui::HelpMarker("Log all registered variables values to a selected log file"); + ImGui::Separator(); + + /* CSV streamer */ + ImGui::Text("Log to file: "); + ImGui::SameLine(); + ImGui::Checkbox("##logging", &logging); + + ImGui::BeginDisabled(!logging); + + ImGui::Text("Logfile directory: "); + ImGui::SameLine(); + ImGui::InputText("##", &settings.logFilePath, 0, NULL, NULL); + ImGui::SameLine(); + if (ImGui::Button("...", ImVec2(35 * contentScale, 19 * contentScale))) + openLogDirectory(settings.logFilePath); + + ImGui::EndDisabled(); + ImGui::PopID(); + plotHandler->setSettings(settings); +} + void Gui::acqusitionSettingsTrace() { TracePlotHandler::Settings settings = tracePlotHandler->getSettings(); diff --git a/src/Gui/GuiPlots.cpp b/src/Gui/GuiPlots.cpp index bacbad39..b81a2b1d 100644 --- a/src/Gui/GuiPlots.cpp +++ b/src/Gui/GuiPlots.cpp @@ -216,7 +216,7 @@ void Gui::drawPlotTable(Plot* plot, ScrollingBuffer& time, std::mapgetSeriesValueString(key, serPtr->var->getValue()).data(), maxVariableNameLength); showChangeFormatPopup("format", *plot, key); ImGui::TableSetColumnIndex(3); - ImGui::PushID("input"); + ImGui::PushID("input"); char newValue[maxVariableNameLength] = {0}; if (ImGui::SelectableInput(key.c_str(), false, ImGuiSelectableFlags_None, newValue, maxVariableNameLength)) { diff --git a/src/PlotHandler/PlotHandler.cpp b/src/PlotHandler/PlotHandler.cpp index 958154e0..d9b6254a 100644 --- a/src/PlotHandler/PlotHandler.cpp +++ b/src/PlotHandler/PlotHandler.cpp @@ -101,6 +101,8 @@ void PlotHandler::dataHandler() else if (period > ((1.0 / settings.sampleFrequencyHz) * timer)) { + std::vector values; + values.reserve(100); for (auto& [key, plot] : plotsMap) { if (!plot->getVisibility()) @@ -119,10 +121,14 @@ void PlotHandler::dataHandler() /* thread-safe part */ std::lock_guard lock(*mtx); for (auto& [name, ser] : plot->getSeriesMap()) + { plot->addPoint(name, ser->var->getValue()); + values.push_back(ser->var->getValue()); + } plot->addTimePoint(period); } /* filter sampling frequency */ + csvStreamer.writeLine(period, values); averageSamplingPeriod = samplingPeriodFilter.filter((period - lastT)); lastT = period; timer++; @@ -137,6 +143,22 @@ void PlotHandler::dataHandler() { auto addressSizeVector = createAddressSizeVector(); + /* prepare CSV files for streaming */ + std::vector headerNames; + + for (auto& [key, plot] : plotsMap) + { + if (!plot->getVisibility()) + continue; + + for (auto& [name, ser] : plot->getSeriesMap()) + { + headerNames.push_back(name); + } + } + csvStreamer.prepareFile(settings.logFilePath); + csvStreamer.createHeader(headerNames); + if (varReader->start(probeSettings, addressSizeVector, settings.sampleFrequencyHz)) { timer = 0; @@ -147,7 +169,10 @@ void PlotHandler::dataHandler() viewerState = state::STOP; } else + { varReader->stop(); + csvStreamer.finishLogging(); + } stateChangeOrdered = false; } } diff --git a/src/PlotHandler/PlotHandler.hpp b/src/PlotHandler/PlotHandler.hpp index c29bf760..203b9736 100644 --- a/src/PlotHandler/PlotHandler.hpp +++ b/src/PlotHandler/PlotHandler.hpp @@ -8,12 +8,13 @@ #include #include +#include "CSVStreamer.hpp" #include "IDebugProbe.hpp" +#include "MemoryReader.hpp" #include "MovingAverage.hpp" #include "Plot.hpp" #include "PlotHandlerBase.hpp" #include "ScrollingBuffer.hpp" -#include "MemoryReader.hpp" #include "spdlog/spdlog.h" class PlotHandler : public PlotHandlerBase @@ -28,6 +29,7 @@ class PlotHandler : public PlotHandlerBase uint32_t maxViewportPoints = 5000; bool refreshAddressesOnElfChange = false; bool stopAcqusitionOnElfChange = false; + std::string logFilePath = ""; } Settings; PlotHandler(std::atomic& done, std::mutex* mtx, spdlog::logger* logger); @@ -50,6 +52,8 @@ class PlotHandler : public PlotHandlerBase return 0.0; } + CSVStreamer csvStreamer; + private: void dataHandler(); std::vector> createAddressSizeVector(); From 07d0d651a54eac8c4f25864e67457cfa131b0e8c Mon Sep 17 00:00:00 2001 From: Piotr Wasilewski Date: Fri, 20 Sep 2024 19:18:37 +0200 Subject: [PATCH 02/24] fix: fixing bugs in the csv streamer --- src/CSVStreamer/CSVStreamer.hpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/CSVStreamer/CSVStreamer.hpp b/src/CSVStreamer/CSVStreamer.hpp index 25821120..4ebcee16 100644 --- a/src/CSVStreamer/CSVStreamer.hpp +++ b/src/CSVStreamer/CSVStreamer.hpp @@ -54,7 +54,7 @@ class CSVStreamer bool prepareFile(std::string& directory) { filePath = directory + "/logfile.csv"; - csvFile.open(filePath, std::ios::app); + csvFile.open(filePath, std::ios::out); if (!csvFile.is_open()) { std::cerr << "Failed to open file: " << filePath << std::endl; @@ -65,7 +65,7 @@ class CSVStreamer void createHeader(const std::vector& values) { - std::string header; + std::string header = "time,"; for (const auto& value : values) { header += value + ","; @@ -87,13 +87,18 @@ class CSVStreamer if (currentBuffer->isFull()) { - processingBuffer = currentBuffer; - currentBuffer = currentBuffer->nextBuffer; - currentBuffer->index = 0; + exchangeBuffers(); saveTask = std::async(std::launch::async, &CSVStreamer::save, this); } } + void exchangeBuffers() + { + processingBuffer = currentBuffer; + currentBuffer = currentBuffer->nextBuffer; + currentBuffer->index = 0; + } + void save() { if (!csvFile.is_open()) @@ -101,9 +106,10 @@ class CSVStreamer std::cerr << "CSV file is not open!" << std::endl; return; } - for (const auto& line : processingBuffer->buffer) + + for (size_t i = 0; i < processingBuffer->index; i++) { - csvFile << line; + csvFile << processingBuffer->buffer[i]; } } @@ -111,6 +117,8 @@ class CSVStreamer { if (csvFile.is_open()) { + exchangeBuffers(); + save(); csvFile.close(); } } From ea07e0351d3e33a5f3649e4fef5a4f593f1e6a1a Mon Sep 17 00:00:00 2001 From: Piotr Wasilewski Date: Fri, 20 Sep 2024 22:50:27 +0200 Subject: [PATCH 03/24] feature: working on csv streaming --- .../MCUViewer_project/MCUViewer_test.cfg | 6 +- src/Gui/Gui.hpp | 5 +- src/Gui/GuiAcqusition.cpp | 67 +++++++++---------- src/PlotHandler/PlotHandler.cpp | 15 +++-- src/PlotHandler/PlotHandler.hpp | 6 +- src/PlotHandler/PlotHandlerBase.hpp | 2 + src/PlotHandler/TracePlotHandler.cpp | 30 +++++++-- src/PlotHandler/TracePlotHandler.hpp | 4 +- 8 files changed, 82 insertions(+), 53 deletions(-) diff --git a/example/STMViewer_test/MCUViewer_project/MCUViewer_test.cfg b/example/STMViewer_test/MCUViewer_project/MCUViewer_test.cfg index 7b07920e..cc20ee7a 100644 --- a/example/STMViewer_test/MCUViewer_project/MCUViewer_test.cfg +++ b/example/STMViewer_test/MCUViewer_project/MCUViewer_test.cfg @@ -22,10 +22,10 @@ max_viewport_points_percent = 10 trigger_channel = -1 trigger_level = 0.000000 timeout = 2 -probe_type = 0 -target_name = +probe_type = 1 +target_name = STM32G474CC probe_speed_khz = 10000 -probe_sn = +probe_sn = 506003225 [var0] name = test.a diff --git a/src/Gui/Gui.hpp b/src/Gui/Gui.hpp index cb6678c5..439f60ab 100644 --- a/src/Gui/Gui.hpp +++ b/src/Gui/Gui.hpp @@ -94,7 +94,10 @@ class Gui void drawPlotsTree(); void drawAcqusitionSettingsWindow(ActiveViewType type); void acqusitionSettingsViewer(); - void drawLoggingSettings(); + + template + void drawLoggingSettings(PlotHandlerBase* handler, Settings& settings); + void drawAboutWindow(); void drawPreferencesWindow(); void drawStatisticsAnalog(std::shared_ptr plt); diff --git a/src/Gui/GuiAcqusition.cpp b/src/Gui/GuiAcqusition.cpp index af87e15f..2f2c5b4c 100644 --- a/src/Gui/GuiAcqusition.cpp +++ b/src/Gui/GuiAcqusition.cpp @@ -6,7 +6,7 @@ void Gui::acqusitionSettingsViewer() drawCenteredText("Project"); ImGui::Separator(); - ImGui::Text("*.elf file: "); + ImGui::Text("*.elf file: "); ImGui::SameLine(); ImGui::InputText("##", &projectElfPath, 0, NULL, NULL); ImGui::SameLine(); @@ -15,15 +15,15 @@ void Gui::acqusitionSettingsViewer() PlotHandler::Settings settings = plotHandler->getSettings(); - ImGui::Text("Refresh addresses on *.elf change: "); + ImGui::Text("Refresh vars on *.elf change: "); ImGui::SameLine(); ImGui::Checkbox("##refresh", &settings.refreshAddressesOnElfChange); - ImGui::Text("Stop acqusition on *.elf change: "); + ImGui::Text("Stop on *.elf change: "); ImGui::SameLine(); ImGui::Checkbox("##stop", &settings.stopAcqusitionOnElfChange); - ImGui::Text("Sampling [Hz]: "); + ImGui::Text("Sampling [Hz]: "); ImGui::SameLine(); ImGui::InputScalar("##sample", ImGuiDataType_U32, &settings.sampleFrequencyHz, NULL, NULL, "%u"); ImGui::SameLine(); @@ -32,25 +32,25 @@ void Gui::acqusitionSettingsViewer() const uint32_t minPoints = 100; const uint32_t maxPoints = 20000; - ImGui::Text("Max points: "); + ImGui::Text("Max points: "); ImGui::SameLine(); ImGui::InputScalar("##maxPoints", ImGuiDataType_U32, &settings.maxPoints, NULL, NULL, "%u"); ImGui::SameLine(); ImGui::HelpMarker("Max points used for a single series after which the oldest points will be overwritten."); settings.maxPoints = std::clamp(settings.maxPoints, minPoints, maxPoints); - ImGui::Text("Max view points: "); + ImGui::Text("Max view points: "); ImGui::SameLine(); ImGui::InputScalar("##maxViewportPoints", ImGuiDataType_U32, &settings.maxViewportPoints, NULL, NULL, "%u"); ImGui::SameLine(); ImGui::HelpMarker("Max points used for a single series that will be shown in the viewport without scroling."); settings.maxViewportPoints = std::clamp(settings.maxViewportPoints, minPoints, settings.maxPoints); - plotHandler->setSettings(settings); - drawDebugProbes(); - drawLoggingSettings(); + drawLoggingSettings(plotHandler, settings); + + plotHandler->setSettings(settings); } void Gui::drawDebugProbes() @@ -66,7 +66,7 @@ void Gui::drawDebugProbes() ImGui::HelpMarker("Select the debug probe type and the serial number of the probe to unlock the START button."); ImGui::Separator(); - ImGui::Text("Debug probe: "); + ImGui::Text("Debug probe: "); ImGui::SameLine(); const char* debugProbes[] = {"STLINK", "JLINK"}; @@ -90,7 +90,7 @@ void Gui::drawDebugProbes() } SNptr = 0; } - ImGui::Text("Debug probe S/N: "); + ImGui::Text("Debug probe S/N: "); ImGui::SameLine(); if (ImGui::Combo("##debugProbeSN", &SNptr, devicesList)) @@ -113,7 +113,7 @@ void Gui::drawDebugProbes() shouldListDevices = false; } - ImGui::Text("SWD speed [kHz]: "); + ImGui::Text("SWD speed [kHz]: "); ImGui::SameLine(); if (ImGui::InputScalar("##speed", ImGuiDataType_U32, &probeSettings.speedkHz, NULL, NULL, "%u")) @@ -121,7 +121,7 @@ void Gui::drawDebugProbes() if (probeSettings.debugProbe == 1) { - ImGui::Text("Target name: "); + ImGui::Text("Target name: "); ImGui::SameLine(); if (ImGui::InputText("##device", &probeSettings.device, 0, NULL, NULL)) @@ -134,7 +134,7 @@ void Gui::drawDebugProbes() modified = true; } - ImGui::Text("Mode: "); + ImGui::Text("Mode: "); ImGui::SameLine(); const char* probeModes[] = {"NORMAL", "HSS"}; @@ -163,28 +163,24 @@ void Gui::drawDebugProbes() ImGui::PopID(); } -void Gui::drawLoggingSettings() +template +void Gui::drawLoggingSettings(PlotHandlerBase* handler, Settings& settings) { - static bool logging = false; - static std::string directory = ""; - - PlotHandler::Settings settings = plotHandler->getSettings(); - ImGui::PushID("logging"); ImGui::Dummy(ImVec2(-1, 5)); drawCenteredText("Logging"); ImGui::SameLine(); - ImGui::HelpMarker("Log all registered variables values to a selected log file"); + ImGui::HelpMarker("Log all registered variables values to a selected log file."); ImGui::Separator(); /* CSV streamer */ - ImGui::Text("Log to file: "); + ImGui::Text("Log to file: "); ImGui::SameLine(); - ImGui::Checkbox("##logging", &logging); + ImGui::Checkbox("##logging", &settings.shouldLog); - ImGui::BeginDisabled(!logging); + ImGui::BeginDisabled(!settings.shouldLog); - ImGui::Text("Logfile directory: "); + ImGui::Text("Logfile directory: "); ImGui::SameLine(); ImGui::InputText("##", &settings.logFilePath, 0, NULL, NULL); ImGui::SameLine(); @@ -193,37 +189,38 @@ void Gui::drawLoggingSettings() ImGui::EndDisabled(); ImGui::PopID(); - plotHandler->setSettings(settings); } void Gui::acqusitionSettingsTrace() { TracePlotHandler::Settings settings = tracePlotHandler->getSettings(); - ImGui::Text("Max points: "); + ImGui::Text("Max points: "); ImGui::SameLine(); ImGui::InputScalar("##maxPoints", ImGuiDataType_U32, &settings.maxPoints, NULL, NULL, "%u"); ImGui::SameLine(); ImGui::HelpMarker("Max points used for a single series after which the oldest points will be overwritten."); settings.maxPoints = std::clamp(settings.maxPoints, static_cast(100), static_cast(20000)); - ImGui::Text("Viewport width [%%]: "); + ImGui::Text("Viewport width [%%]: "); ImGui::SameLine(); ImGui::InputScalar("##maxViewportPoints", ImGuiDataType_U32, &settings.maxViewportPointsPercent, NULL, NULL, "%u"); ImGui::SameLine(); ImGui::HelpMarker("The percentage of trace time visible during collect. Expressed in percent since the sample period is not constant."); settings.maxViewportPointsPercent = std::clamp(settings.maxViewportPointsPercent, static_cast(1), static_cast(100)); - ImGui::Text("Timeout [s]: "); + ImGui::Text("Timeout [s]: "); ImGui::SameLine(); ImGui::InputScalar("##timeout", ImGuiDataType_U32, &settings.timeout, NULL, NULL, "%u"); ImGui::SameLine(); ImGui::HelpMarker("Timeout is the period after which trace will be stopped due to no trace data being received."); settings.timeout = std::clamp(settings.timeout, static_cast(1), static_cast(999999)); - tracePlotHandler->setSettings(settings); - drawTraceProbes(); + + drawLoggingSettings(tracePlotHandler, settings); + + tracePlotHandler->setSettings(settings); } void Gui::drawTraceProbes() @@ -239,7 +236,7 @@ void Gui::drawTraceProbes() ImGui::HelpMarker("Select the debug probe type and the serial number of the probe to unlock the START button."); ImGui::Separator(); - ImGui::Text("Debug probe: "); + ImGui::Text("Debug probe: "); ImGui::SameLine(); const char* debugProbes[] = {"STLINK", "JLINK"}; @@ -263,7 +260,7 @@ void Gui::drawTraceProbes() } SNptr = 0; } - ImGui::Text("Debug probe S/N: "); + ImGui::Text("Debug probe S/N: "); ImGui::SameLine(); if (ImGui::Combo("##debugProbeSN", &SNptr, devicesList)) @@ -286,7 +283,7 @@ void Gui::drawTraceProbes() shouldListDevices = false; } - ImGui::Text("SWD speed [kHz]: "); + ImGui::Text("SWD speed [kHz]: "); ImGui::SameLine(); if (ImGui::InputScalar("##speed", ImGuiDataType_U32, &probeSettings.speedkHz, NULL, NULL, "%u")) @@ -294,7 +291,7 @@ void Gui::drawTraceProbes() if (probeSettings.debugProbe == 1) { - ImGui::Text("Target name: "); + ImGui::Text("Target name: "); ImGui::SameLine(); if (ImGui::InputText("##device", &probeSettings.device, 0, NULL, NULL)) diff --git a/src/PlotHandler/PlotHandler.cpp b/src/PlotHandler/PlotHandler.cpp index d9b6254a..a6db2307 100644 --- a/src/PlotHandler/PlotHandler.cpp +++ b/src/PlotHandler/PlotHandler.cpp @@ -61,6 +61,8 @@ void PlotHandler::dataHandler() std::chrono::time_point start; uint32_t timer = 0; double lastT = 0.0; + std::vector csvValues; + csvValues.reserve(maxVariablesOnSinglePlot); while (!done) { @@ -68,6 +70,7 @@ void PlotHandler::dataHandler() { auto finish = std::chrono::steady_clock::now(); double period = std::chrono::duration_cast>(finish - start).count(); + csvValues.clear(); if (probeSettings.mode == IDebugProbe::Mode::HSS) { @@ -90,9 +93,13 @@ void PlotHandler::dataHandler() double value = varReader->castToProperType(values[ser->var->getAddress()], ser->var->getType()); ser->var->setValue(value); plot->addPoint(name, value); + csvValues.push_back(ser->var->getValue()); } plot->addTimePoint(timestamp); } + + if (settings.shouldLog) + csvStreamer.writeLine(period, csvValues); /* filter sampling frequency */ averageSamplingPeriod = samplingPeriodFilter.filter((period - lastT)); lastT = period; @@ -101,8 +108,6 @@ void PlotHandler::dataHandler() else if (period > ((1.0 / settings.sampleFrequencyHz) * timer)) { - std::vector values; - values.reserve(100); for (auto& [key, plot] : plotsMap) { if (!plot->getVisibility()) @@ -123,12 +128,14 @@ void PlotHandler::dataHandler() for (auto& [name, ser] : plot->getSeriesMap()) { plot->addPoint(name, ser->var->getValue()); - values.push_back(ser->var->getValue()); + csvValues.push_back(ser->var->getValue()); } plot->addTimePoint(period); } + + if (settings.shouldLog) + csvStreamer.writeLine(period, csvValues); /* filter sampling frequency */ - csvStreamer.writeLine(period, values); averageSamplingPeriod = samplingPeriodFilter.filter((period - lastT)); lastT = period; timer++; diff --git a/src/PlotHandler/PlotHandler.hpp b/src/PlotHandler/PlotHandler.hpp index 203b9736..affb47f2 100644 --- a/src/PlotHandler/PlotHandler.hpp +++ b/src/PlotHandler/PlotHandler.hpp @@ -8,7 +8,6 @@ #include #include -#include "CSVStreamer.hpp" #include "IDebugProbe.hpp" #include "MemoryReader.hpp" #include "MovingAverage.hpp" @@ -29,6 +28,7 @@ class PlotHandler : public PlotHandlerBase uint32_t maxViewportPoints = 5000; bool refreshAddressesOnElfChange = false; bool stopAcqusitionOnElfChange = false; + bool shouldLog = false; std::string logFilePath = ""; } Settings; @@ -52,13 +52,13 @@ class PlotHandler : public PlotHandlerBase return 0.0; } - CSVStreamer csvStreamer; - private: void dataHandler(); std::vector> createAddressSizeVector(); private: + static constexpr size_t maxVariablesOnSinglePlot = 100; + std::unique_ptr varReader; IDebugProbe::DebugProbeSettings probeSettings{}; Settings settings{}; diff --git a/src/PlotHandler/PlotHandlerBase.hpp b/src/PlotHandler/PlotHandlerBase.hpp index e835491b..e5d4160f 100644 --- a/src/PlotHandler/PlotHandlerBase.hpp +++ b/src/PlotHandler/PlotHandlerBase.hpp @@ -10,6 +10,7 @@ #include "ScrollingBuffer.hpp" #include "StlinkDebugProbe.hpp" #include "spdlog/spdlog.h" +#include "CSVStreamer.hpp" class PlotHandlerBase { @@ -56,6 +57,7 @@ class PlotHandlerBase iterator end(); protected: + CSVStreamer csvStreamer; std::atomic& done; std::atomic viewerState = state::STOP; std::map> plotsMap; diff --git a/src/PlotHandler/TracePlotHandler.cpp b/src/PlotHandler/TracePlotHandler.cpp index 74a0d9ed..23d0e5ce 100644 --- a/src/PlotHandler/TracePlotHandler.cpp +++ b/src/PlotHandler/TracePlotHandler.cpp @@ -39,7 +39,7 @@ void TracePlotHandler::initPlots() TracePlotHandler::Settings TracePlotHandler::getSettings() const { - return traceSettings; + return settings; } void TracePlotHandler::setSettings(const Settings& settings) @@ -49,7 +49,7 @@ void TracePlotHandler::setSettings(const Settings& settings) traceReader->setTraceShouldReset(settings.shouldReset); traceReader->setTraceTimeout(settings.timeout); setMaxPoints(settings.maxPoints); - traceSettings = settings; + this->settings = settings; } TraceReader::TraceIndicators TracePlotHandler::getTraceIndicators() const @@ -78,12 +78,12 @@ std::string TracePlotHandler::getLastReaderError() const void TracePlotHandler::setTriggerChannel(int32_t triggerChannel) { - traceSettings.triggerChannel = triggerChannel; + settings.triggerChannel = triggerChannel; } int32_t TracePlotHandler::getTriggerChannel() const { - return traceSettings.triggerChannel; + return settings.triggerChannel; } void TracePlotHandler::setDebugProbe(std::shared_ptr probe) @@ -136,6 +136,8 @@ void TracePlotHandler::dataHandler() { uint32_t cnt = 0; double time = 0.0; + std::vector csvValues; + csvValues.reserve(channels); while (!done) { @@ -161,6 +163,7 @@ void TracePlotHandler::dataHandler() errorFrames.handle(time, oldestTimestamp, indicators.errorFramesTotal); delayed3Frames.handle(time, oldestTimestamp, indicators.delayedTimestamp3); + csvValues.clear(); uint32_t i = 0; for (auto& [key, plot] : plotsMap) { @@ -173,7 +176,7 @@ void TracePlotHandler::dataHandler() Plot::Series* ser = plot->getSeriesMap().begin()->second.get(); double newPoint = getDoubleValue(*plot, traces[i]); - if (traceTriggered == false && i == static_cast(traceSettings.triggerChannel) && newPoint > traceSettings.triggerLevel) + if (traceTriggered == false && i == static_cast(settings.triggerChannel) && newPoint > settings.triggerLevel) { logger->info("Trigger!"); traceTriggered = true; @@ -181,13 +184,19 @@ void TracePlotHandler::dataHandler() cnt = 0; } + csvValues.push_back(newPoint); + /* thread-safe part */ std::lock_guard lock(*mtx); plot->addPoint(ser->var->getName(), newPoint); plot->addTimePoint(time); i++; } - if (traceTriggered && cnt++ >= (traceSettings.maxPoints * 0.9)) + + if (settings.shouldLog) + csvStreamer.writeLine(time, csvValues); + + if (traceTriggered && cnt++ >= (settings.maxPoints * 0.9)) { logger->info("After-trigger trace collcted. Stopping."); viewerState = state::STOP; @@ -218,15 +227,24 @@ void TracePlotHandler::dataHandler() if (viewerState == state::RUN) { std::array activeChannels{}; + /* prepare CSV files for streaming */ + std::vector headerNames; uint32_t i = 0; for (auto& [key, plot] : plotsMap) + { activeChannels[i++] = plot->getVisibility(); + if (plot->getVisibility()) + headerNames.push_back(std::string("CH") + std::to_string(i)); + } errorFrames.reset(); delayed3Frames.reset(); lastErrorMsg = ""; + csvStreamer.prepareFile(settings.logFilePath); + csvStreamer.createHeader(headerNames); + if (traceReader->startAcqusition(probeSettings, activeChannels)) time = 0; else diff --git a/src/PlotHandler/TracePlotHandler.hpp b/src/PlotHandler/TracePlotHandler.hpp index f4afeaae..a75a8713 100644 --- a/src/PlotHandler/TracePlotHandler.hpp +++ b/src/PlotHandler/TracePlotHandler.hpp @@ -26,6 +26,8 @@ class TracePlotHandler : public PlotHandlerBase double triggerLevel = 0.9; bool shouldReset = false; uint32_t timeout = 2; + bool shouldLog = false; + std::string logFilePath = ""; } Settings; TracePlotHandler(std::atomic& done, std::mutex* mtx, spdlog::logger* logger); @@ -89,7 +91,7 @@ class TracePlotHandler : public PlotHandlerBase uint32_t previousErrors; }; - Settings traceSettings{}; + Settings settings{}; std::unique_ptr traceReader; MarkerTimestamps errorFrames{}; From a32b87bbbfbf9a0247d4e66c8774dd26e4897817 Mon Sep 17 00:00:00 2001 From: Piotr Wasilewski Date: Sat, 21 Sep 2024 12:15:52 +0200 Subject: [PATCH 04/24] refactor: method to automatically align text --- src/Gui/Gui.cpp | 8 ++++++++ src/Gui/Gui.hpp | 1 + src/Gui/GuiAcqusition.cpp | 42 ++++++++++++++++++++------------------- 3 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/Gui/Gui.cpp b/src/Gui/Gui.cpp index 67bb4d06..5dfdd458 100644 --- a/src/Gui/Gui.cpp +++ b/src/Gui/Gui.cpp @@ -1110,3 +1110,11 @@ void Gui::drawCenteredText(std::string&& text) ImGui::SetCursorPosX((ImGui::GetWindowSize().x - ImGui::CalcTextSize(text.c_str()).x) * 0.5f); ImGui::Text("%s", text.c_str()); } + +void Gui::drawTextAlignedToSize(std::string&& text, size_t alignTo) +{ + size_t currentLength = text.length(); + size_t spacesToAdd = (currentLength < alignTo) ? (alignTo - currentLength) : 0; + std::string alignedText = text + std::string(spacesToAdd, ' '); + ImGui::Text("%s", alignedText.c_str()); +} diff --git a/src/Gui/Gui.hpp b/src/Gui/Gui.hpp index 439f60ab..dd475f27 100644 --- a/src/Gui/Gui.hpp +++ b/src/Gui/Gui.hpp @@ -154,6 +154,7 @@ class Gui std::optional showDeletePopup(const char* text, const std::string& name); std::string intToHexString(uint32_t i); void drawCenteredText(std::string&& text); + void drawTextAlignedToSize(std::string&& text, size_t alignTo); bool openWebsite(const char* url); diff --git a/src/Gui/GuiAcqusition.cpp b/src/Gui/GuiAcqusition.cpp index 2f2c5b4c..05c438d4 100644 --- a/src/Gui/GuiAcqusition.cpp +++ b/src/Gui/GuiAcqusition.cpp @@ -1,12 +1,14 @@ #include "Gui.hpp" +static constexpr size_t alignment = 30; + void Gui::acqusitionSettingsViewer() { ImGui::Dummy(ImVec2(-1, 5)); drawCenteredText("Project"); ImGui::Separator(); - ImGui::Text("*.elf file: "); + drawTextAlignedToSize("*.elf file:", alignment); ImGui::SameLine(); ImGui::InputText("##", &projectElfPath, 0, NULL, NULL); ImGui::SameLine(); @@ -15,15 +17,15 @@ void Gui::acqusitionSettingsViewer() PlotHandler::Settings settings = plotHandler->getSettings(); - ImGui::Text("Refresh vars on *.elf change: "); + drawTextAlignedToSize("Refresh vars on *.elf change:", alignment); ImGui::SameLine(); ImGui::Checkbox("##refresh", &settings.refreshAddressesOnElfChange); - ImGui::Text("Stop on *.elf change: "); + drawTextAlignedToSize("Stop on *.elf change:", alignment); ImGui::SameLine(); ImGui::Checkbox("##stop", &settings.stopAcqusitionOnElfChange); - ImGui::Text("Sampling [Hz]: "); + drawTextAlignedToSize("Sampling [Hz]:", alignment); ImGui::SameLine(); ImGui::InputScalar("##sample", ImGuiDataType_U32, &settings.sampleFrequencyHz, NULL, NULL, "%u"); ImGui::SameLine(); @@ -32,14 +34,14 @@ void Gui::acqusitionSettingsViewer() const uint32_t minPoints = 100; const uint32_t maxPoints = 20000; - ImGui::Text("Max points: "); + drawTextAlignedToSize("Max points:", alignment); ImGui::SameLine(); ImGui::InputScalar("##maxPoints", ImGuiDataType_U32, &settings.maxPoints, NULL, NULL, "%u"); ImGui::SameLine(); ImGui::HelpMarker("Max points used for a single series after which the oldest points will be overwritten."); settings.maxPoints = std::clamp(settings.maxPoints, minPoints, maxPoints); - ImGui::Text("Max view points: "); + drawTextAlignedToSize("Max view points:", alignment); ImGui::SameLine(); ImGui::InputScalar("##maxViewportPoints", ImGuiDataType_U32, &settings.maxViewportPoints, NULL, NULL, "%u"); ImGui::SameLine(); @@ -66,7 +68,7 @@ void Gui::drawDebugProbes() ImGui::HelpMarker("Select the debug probe type and the serial number of the probe to unlock the START button."); ImGui::Separator(); - ImGui::Text("Debug probe: "); + drawTextAlignedToSize("Debug probe:", alignment); ImGui::SameLine(); const char* debugProbes[] = {"STLINK", "JLINK"}; @@ -90,7 +92,7 @@ void Gui::drawDebugProbes() } SNptr = 0; } - ImGui::Text("Debug probe S/N: "); + drawTextAlignedToSize("Debug probe S/N:", alignment); ImGui::SameLine(); if (ImGui::Combo("##debugProbeSN", &SNptr, devicesList)) @@ -113,7 +115,7 @@ void Gui::drawDebugProbes() shouldListDevices = false; } - ImGui::Text("SWD speed [kHz]: "); + drawTextAlignedToSize("SWD speed [kHz]:", alignment); ImGui::SameLine(); if (ImGui::InputScalar("##speed", ImGuiDataType_U32, &probeSettings.speedkHz, NULL, NULL, "%u")) @@ -121,7 +123,7 @@ void Gui::drawDebugProbes() if (probeSettings.debugProbe == 1) { - ImGui::Text("Target name: "); + drawTextAlignedToSize("Target name:", alignment); ImGui::SameLine(); if (ImGui::InputText("##device", &probeSettings.device, 0, NULL, NULL)) @@ -134,7 +136,7 @@ void Gui::drawDebugProbes() modified = true; } - ImGui::Text("Mode: "); + drawTextAlignedToSize("Mode:", alignment); ImGui::SameLine(); const char* probeModes[] = {"NORMAL", "HSS"}; @@ -174,13 +176,13 @@ void Gui::drawLoggingSettings(PlotHandlerBase* handler, Settings& settings) ImGui::Separator(); /* CSV streamer */ - ImGui::Text("Log to file: "); + drawTextAlignedToSize("Log to file:", alignment); ImGui::SameLine(); ImGui::Checkbox("##logging", &settings.shouldLog); ImGui::BeginDisabled(!settings.shouldLog); - ImGui::Text("Logfile directory: "); + drawTextAlignedToSize("Logfile directory:", alignment); ImGui::SameLine(); ImGui::InputText("##", &settings.logFilePath, 0, NULL, NULL); ImGui::SameLine(); @@ -195,21 +197,21 @@ void Gui::acqusitionSettingsTrace() { TracePlotHandler::Settings settings = tracePlotHandler->getSettings(); - ImGui::Text("Max points: "); + drawTextAlignedToSize("Max points:", alignment); ImGui::SameLine(); ImGui::InputScalar("##maxPoints", ImGuiDataType_U32, &settings.maxPoints, NULL, NULL, "%u"); ImGui::SameLine(); ImGui::HelpMarker("Max points used for a single series after which the oldest points will be overwritten."); settings.maxPoints = std::clamp(settings.maxPoints, static_cast(100), static_cast(20000)); - ImGui::Text("Viewport width [%%]: "); + drawTextAlignedToSize("Viewport width [%%]:", alignment); ImGui::SameLine(); ImGui::InputScalar("##maxViewportPoints", ImGuiDataType_U32, &settings.maxViewportPointsPercent, NULL, NULL, "%u"); ImGui::SameLine(); ImGui::HelpMarker("The percentage of trace time visible during collect. Expressed in percent since the sample period is not constant."); settings.maxViewportPointsPercent = std::clamp(settings.maxViewportPointsPercent, static_cast(1), static_cast(100)); - ImGui::Text("Timeout [s]: "); + drawTextAlignedToSize("Timeout [s]:", alignment); ImGui::SameLine(); ImGui::InputScalar("##timeout", ImGuiDataType_U32, &settings.timeout, NULL, NULL, "%u"); ImGui::SameLine(); @@ -236,7 +238,7 @@ void Gui::drawTraceProbes() ImGui::HelpMarker("Select the debug probe type and the serial number of the probe to unlock the START button."); ImGui::Separator(); - ImGui::Text("Debug probe: "); + drawTextAlignedToSize("Debug probe:", alignment); ImGui::SameLine(); const char* debugProbes[] = {"STLINK", "JLINK"}; @@ -260,7 +262,7 @@ void Gui::drawTraceProbes() } SNptr = 0; } - ImGui::Text("Debug probe S/N: "); + drawTextAlignedToSize("Debug probe S/N:", alignment); ImGui::SameLine(); if (ImGui::Combo("##debugProbeSN", &SNptr, devicesList)) @@ -283,7 +285,7 @@ void Gui::drawTraceProbes() shouldListDevices = false; } - ImGui::Text("SWD speed [kHz]: "); + drawTextAlignedToSize("SWD speed [kHz]:", alignment); ImGui::SameLine(); if (ImGui::InputScalar("##speed", ImGuiDataType_U32, &probeSettings.speedkHz, NULL, NULL, "%u")) @@ -291,7 +293,7 @@ void Gui::drawTraceProbes() if (probeSettings.debugProbe == 1) { - ImGui::Text("Target name: "); + drawTextAlignedToSize("Target name:", alignment); ImGui::SameLine(); if (ImGui::InputText("##device", &probeSettings.device, 0, NULL, NULL)) From 5fe6ebc5bc38719fd8297c83545be3ec30aec841 Mon Sep 17 00:00:00 2001 From: Piotr Wasilewski Date: Sat, 21 Sep 2024 13:37:41 +0200 Subject: [PATCH 05/24] refactor: refactoring csvStreamer --- CMakeLists.txt | 3 +- .../MCUViewer_project/MCUViewer_test.cfg | 4 +- src/CSVStreamer/CSVStreamer.cpp | 111 ++++++++++++++++ src/CSVStreamer/CSVStreamer.hpp | 118 +++--------------- src/Gui/GuiAcqusition.cpp | 4 - src/PlotHandler/PlotHandler.cpp | 10 +- src/PlotHandler/PlotHandlerBase.cpp | 1 + src/PlotHandler/PlotHandlerBase.hpp | 2 +- src/PlotHandler/TracePlotHandler.cpp | 6 +- 9 files changed, 143 insertions(+), 116 deletions(-) create mode 100644 src/CSVStreamer/CSVStreamer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 25e67878..67181999 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,7 +124,8 @@ set(PROJECT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/TraceReader/TraceReader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/TraceReader/StlinkTraceProbe.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/TraceReader/JlinkTraceProbe.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/GdbParser/GdbParser.cpp) + ${CMAKE_CURRENT_SOURCE_DIR}/src/GdbParser/GdbParser.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/CSVStreamer/CSVStreamer.cpp) set(IMGUI_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/third_party/imgui/imgui.cpp diff --git a/example/STMViewer_test/MCUViewer_project/MCUViewer_test.cfg b/example/STMViewer_test/MCUViewer_project/MCUViewer_test.cfg index cc20ee7a..14bb0de3 100644 --- a/example/STMViewer_test/MCUViewer_project/MCUViewer_test.cfg +++ b/example/STMViewer_test/MCUViewer_project/MCUViewer_test.cfg @@ -3,14 +3,14 @@ file_path = ../example/STMViewer_test/Debug/STMViewer_test.elf [settings] version = 0 -sample_frequency_hz = 1000 +sample_frequency_hz = 1000000 max_points = 10000 max_viewport_points = 5000 refresh_on_elf_change = true stop_acq_on_elf_change = true probe_type = 1 target_name = STM32G474CC -probe_mode = 0 +probe_mode = 1 probe_speed_khz = 50000 probe_sn = 506003225 diff --git a/src/CSVStreamer/CSVStreamer.cpp b/src/CSVStreamer/CSVStreamer.cpp new file mode 100644 index 00000000..1c7ec141 --- /dev/null +++ b/src/CSVStreamer/CSVStreamer.cpp @@ -0,0 +1,111 @@ +#include "CSVStreamer.hpp" + +#include +#include +#include +#include + +bool CSVStreamer::Buffer::appendLine(std::string& line) +{ + if (isFull()) + { + return false; + } + + buffer[index] = line; + index++; + return true; +} + +bool CSVStreamer::Buffer::isFull() const +{ + return (index + 1) >= buffer.size(); +} + +CSVStreamer::CSVStreamer(spdlog::logger* logger) : logger(logger) +{ + currentBuffer = &buffer1; + buffer1.nextBuffer = &buffer2; + buffer2.nextBuffer = &buffer1; +} + +CSVStreamer::~CSVStreamer() +{ + finishLogging(); +} + +bool CSVStreamer::prepareFile(std::string& directory) +{ + filePath = directory + logFileName; + csvFile.open(filePath, std::ios::out); + if (!csvFile.is_open()) + { + std::cerr << "Failed to open file: " << filePath << std::endl; + return false; + } + return true; +} + +void CSVStreamer::createHeader(const std::vector& values) +{ + std::string header = "time,"; + for (const auto& value : values) + { + header += value + ","; + } + header.back() = '\n'; + currentBuffer->appendLine(header); +} + +void CSVStreamer::writeLine(double time, const std::vector& values) +{ + std::string line = std::to_string(time) + ","; + for (const auto& value : values) + { + line += std::to_string(value) + ","; + } + line.back() = '\n'; + + currentBuffer->appendLine(line); + + if (currentBuffer->isFull()) + { + exchangeBuffers(); + + if (saveTask.valid() && saveTask.wait_for(std::chrono::seconds(0)) != std::future_status::ready) + logger->error("Buffer overrun in CSVStreamer object!"); + + saveTask = std::async(std::launch::async, &CSVStreamer::save, this); + } +} + +void CSVStreamer::exchangeBuffers() +{ + processingBuffer = currentBuffer; + currentBuffer = currentBuffer->nextBuffer; + currentBuffer->index = 0; +} + +void CSVStreamer::save() +{ + if (!csvFile.is_open()) + { + std::cerr << "CSV file is not open!" << std::endl; + return; + } + + for (size_t i = 0; i < processingBuffer->index; i++) + { + csvFile << processingBuffer->buffer[i]; + } +} + +void CSVStreamer::finishLogging() +{ + if (csvFile.is_open()) + { + exchangeBuffers(); + save(); + csvFile.close(); + } +} \ No newline at end of file diff --git a/src/CSVStreamer/CSVStreamer.hpp b/src/CSVStreamer/CSVStreamer.hpp index 4ebcee16..8b779473 100644 --- a/src/CSVStreamer/CSVStreamer.hpp +++ b/src/CSVStreamer/CSVStreamer.hpp @@ -5,126 +5,44 @@ #include #include #include -#include + +#include "spdlog/spdlog.h" class CSVStreamer { public: struct Buffer { + bool appendLine(std::string& line); + bool isFull() const; + std::array buffer; size_t index; Buffer* nextBuffer; - - bool appendLine(std::string& line) - { - if (isFull()) - { - return false; - } - - buffer[index] = line; - index++; - return true; - } - - bool isFull() const - { - return (index + 1) >= buffer.size(); - } }; - CSVStreamer() - { - currentBuffer = &buffer1; - buffer1.nextBuffer = &buffer2; - buffer2.nextBuffer = &buffer1; - } + CSVStreamer(spdlog::logger* logger); - ~CSVStreamer() - { - finishLogging(); - } + ~CSVStreamer(); - std::string getFilePath() const - { - return filePath; - } + bool prepareFile(std::string& directory); - bool prepareFile(std::string& directory) - { - filePath = directory + "/logfile.csv"; - csvFile.open(filePath, std::ios::out); - if (!csvFile.is_open()) - { - std::cerr << "Failed to open file: " << filePath << std::endl; - return false; - } - return true; - } + void createHeader(const std::vector& values); - void createHeader(const std::vector& values) - { - std::string header = "time,"; - for (const auto& value : values) - { - header += value + ","; - } - header.back() = '\n'; - currentBuffer->appendLine(header); - } + void writeLine(double time, const std::vector& values); - void writeLine(double time, const std::vector& values) - { - std::string line = std::to_string(time) + ","; - for (const auto& value : values) - { - line += std::to_string(value) + ","; - } - line.back() = '\n'; - - currentBuffer->appendLine(line); + void exchangeBuffers(); - if (currentBuffer->isFull()) - { - exchangeBuffers(); - saveTask = std::async(std::launch::async, &CSVStreamer::save, this); - } - } + void save(); - void exchangeBuffers() - { - processingBuffer = currentBuffer; - currentBuffer = currentBuffer->nextBuffer; - currentBuffer->index = 0; - } - - void save() - { - if (!csvFile.is_open()) - { - std::cerr << "CSV file is not open!" << std::endl; - return; - } - - for (size_t i = 0; i < processingBuffer->index; i++) - { - csvFile << processingBuffer->buffer[i]; - } - } - - void finishLogging() - { - if (csvFile.is_open()) - { - exchangeBuffers(); - save(); - csvFile.close(); - } - } + void finishLogging(); private: - std::future saveTask{}; + const char* logFileName = "/logfile.csv"; + + spdlog::logger* logger; + std::future + saveTask{}; std::string filePath; std::ofstream csvFile; Buffer buffer1; diff --git a/src/Gui/GuiAcqusition.cpp b/src/Gui/GuiAcqusition.cpp index 05c438d4..f28f7b8f 100644 --- a/src/Gui/GuiAcqusition.cpp +++ b/src/Gui/GuiAcqusition.cpp @@ -49,9 +49,7 @@ void Gui::acqusitionSettingsViewer() settings.maxViewportPoints = std::clamp(settings.maxViewportPoints, minPoints, settings.maxPoints); drawDebugProbes(); - drawLoggingSettings(plotHandler, settings); - plotHandler->setSettings(settings); } @@ -219,9 +217,7 @@ void Gui::acqusitionSettingsTrace() settings.timeout = std::clamp(settings.timeout, static_cast(1), static_cast(999999)); drawTraceProbes(); - drawLoggingSettings(tracePlotHandler, settings); - tracePlotHandler->setSettings(settings); } diff --git a/src/PlotHandler/PlotHandler.cpp b/src/PlotHandler/PlotHandler.cpp index a6db2307..0b33ba88 100644 --- a/src/PlotHandler/PlotHandler.cpp +++ b/src/PlotHandler/PlotHandler.cpp @@ -99,7 +99,7 @@ void PlotHandler::dataHandler() } if (settings.shouldLog) - csvStreamer.writeLine(period, csvValues); + csvStreamer->writeLine(period, csvValues); /* filter sampling frequency */ averageSamplingPeriod = samplingPeriodFilter.filter((period - lastT)); lastT = period; @@ -134,7 +134,7 @@ void PlotHandler::dataHandler() } if (settings.shouldLog) - csvStreamer.writeLine(period, csvValues); + csvStreamer->writeLine(period, csvValues); /* filter sampling frequency */ averageSamplingPeriod = samplingPeriodFilter.filter((period - lastT)); lastT = period; @@ -163,8 +163,8 @@ void PlotHandler::dataHandler() headerNames.push_back(name); } } - csvStreamer.prepareFile(settings.logFilePath); - csvStreamer.createHeader(headerNames); + csvStreamer->prepareFile(settings.logFilePath); + csvStreamer->createHeader(headerNames); if (varReader->start(probeSettings, addressSizeVector, settings.sampleFrequencyHz)) { @@ -178,7 +178,7 @@ void PlotHandler::dataHandler() else { varReader->stop(); - csvStreamer.finishLogging(); + csvStreamer->finishLogging(); } stateChangeOrdered = false; } diff --git a/src/PlotHandler/PlotHandlerBase.cpp b/src/PlotHandler/PlotHandlerBase.cpp index 898fe89b..fab9db8f 100644 --- a/src/PlotHandler/PlotHandlerBase.cpp +++ b/src/PlotHandler/PlotHandlerBase.cpp @@ -8,6 +8,7 @@ PlotHandlerBase::PlotHandlerBase(std::atomic& done, std::mutex* mtx, spdlog::logger* logger) : done(done), mtx(mtx), logger(logger) { + csvStreamer = std::make_unique(logger); } void PlotHandlerBase::addPlot(const std::string& name) diff --git a/src/PlotHandler/PlotHandlerBase.hpp b/src/PlotHandler/PlotHandlerBase.hpp index e5d4160f..d700fba6 100644 --- a/src/PlotHandler/PlotHandlerBase.hpp +++ b/src/PlotHandler/PlotHandlerBase.hpp @@ -57,7 +57,7 @@ class PlotHandlerBase iterator end(); protected: - CSVStreamer csvStreamer; + std::unique_ptr csvStreamer; std::atomic& done; std::atomic viewerState = state::STOP; std::map> plotsMap; diff --git a/src/PlotHandler/TracePlotHandler.cpp b/src/PlotHandler/TracePlotHandler.cpp index 23d0e5ce..7fb5ea2d 100644 --- a/src/PlotHandler/TracePlotHandler.cpp +++ b/src/PlotHandler/TracePlotHandler.cpp @@ -194,7 +194,7 @@ void TracePlotHandler::dataHandler() } if (settings.shouldLog) - csvStreamer.writeLine(time, csvValues); + csvStreamer->writeLine(time, csvValues); if (traceTriggered && cnt++ >= (settings.maxPoints * 0.9)) { @@ -242,8 +242,8 @@ void TracePlotHandler::dataHandler() delayed3Frames.reset(); lastErrorMsg = ""; - csvStreamer.prepareFile(settings.logFilePath); - csvStreamer.createHeader(headerNames); + csvStreamer->prepareFile(settings.logFilePath); + csvStreamer->createHeader(headerNames); if (traceReader->startAcqusition(probeSettings, activeChannels)) time = 0; From b5e8987ba0f845066a61b5a1986d2d59ddcb8be2 Mon Sep 17 00:00:00 2001 From: Piotr Wasilewski Date: Sat, 21 Sep 2024 13:45:31 +0200 Subject: [PATCH 06/24] docs: added doxygen comments to CSVStreamer --- src/CSVStreamer/CSVStreamer.hpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/CSVStreamer/CSVStreamer.hpp b/src/CSVStreamer/CSVStreamer.hpp index 8b779473..92014bb0 100644 --- a/src/CSVStreamer/CSVStreamer.hpp +++ b/src/CSVStreamer/CSVStreamer.hpp @@ -22,27 +22,36 @@ class CSVStreamer }; CSVStreamer(spdlog::logger* logger); - ~CSVStreamer(); + /// @brief Creates file in given directory with a fixed name + /// @param directory directory string + /// @return bool prepareFile(std::string& directory); + /// @brief create csv file header from given argument, first column - time - is added internally + /// @param values table headers void createHeader(const std::vector& values); + /// @brief writes single line to internal buffer + /// @param time + /// @param values void writeLine(double time, const std::vector& values); + /// @brief exchanges the buffer that is being processed with the one that's being written to void exchangeBuffers(); + /// @brief saves the processing buffer to the opened csv file void save(); + /// @brief writes the rest of the buffer to the file and closes it void finishLogging(); private: const char* logFileName = "/logfile.csv"; spdlog::logger* logger; - std::future - saveTask{}; + std::future saveTask{}; std::string filePath; std::ofstream csvFile; Buffer buffer1; From fbddf90008dc778c863db019c5bb41fb0b89f1b8 Mon Sep 17 00:00:00 2001 From: Piotr Wasilewski Date: Sat, 21 Sep 2024 14:51:16 +0200 Subject: [PATCH 07/24] refactor: refactoring csvStreamer --- src/CSVStreamer/CSVStreamer.cpp | 12 +++++------- src/CSVStreamer/CSVStreamer.hpp | 4 ++-- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/CSVStreamer/CSVStreamer.cpp b/src/CSVStreamer/CSVStreamer.cpp index 1c7ec141..b64ac588 100644 --- a/src/CSVStreamer/CSVStreamer.cpp +++ b/src/CSVStreamer/CSVStreamer.cpp @@ -8,9 +8,7 @@ bool CSVStreamer::Buffer::appendLine(std::string& line) { if (isFull()) - { return false; - } buffer[index] = line; index++; @@ -40,7 +38,7 @@ bool CSVStreamer::prepareFile(std::string& directory) csvFile.open(filePath, std::ios::out); if (!csvFile.is_open()) { - std::cerr << "Failed to open file: " << filePath << std::endl; + logger->error("Failed to open file: {}", filePath); return false; } return true; @@ -75,7 +73,7 @@ void CSVStreamer::writeLine(double time, const std::vector& values) if (saveTask.valid() && saveTask.wait_for(std::chrono::seconds(0)) != std::future_status::ready) logger->error("Buffer overrun in CSVStreamer object!"); - saveTask = std::async(std::launch::async, &CSVStreamer::save, this); + saveTask = std::async(std::launch::async, &CSVStreamer::writeFile, this); } } @@ -86,11 +84,11 @@ void CSVStreamer::exchangeBuffers() currentBuffer->index = 0; } -void CSVStreamer::save() +void CSVStreamer::writeFile() { if (!csvFile.is_open()) { - std::cerr << "CSV file is not open!" << std::endl; + logger->error("CSV file is not open!"); return; } @@ -105,7 +103,7 @@ void CSVStreamer::finishLogging() if (csvFile.is_open()) { exchangeBuffers(); - save(); + writeFile(); csvFile.close(); } } \ No newline at end of file diff --git a/src/CSVStreamer/CSVStreamer.hpp b/src/CSVStreamer/CSVStreamer.hpp index 92014bb0..f446dc52 100644 --- a/src/CSVStreamer/CSVStreamer.hpp +++ b/src/CSVStreamer/CSVStreamer.hpp @@ -41,8 +41,8 @@ class CSVStreamer /// @brief exchanges the buffer that is being processed with the one that's being written to void exchangeBuffers(); - /// @brief saves the processing buffer to the opened csv file - void save(); + /// @brief writes the processing buffer to the opened csv file + void writeFile(); /// @brief writes the rest of the buffer to the file and closes it void finishLogging(); From 54d6640620b6d3b1ad50c98e172d5e78a52f38be Mon Sep 17 00:00:00 2001 From: Piotr Wasilewski Date: Sun, 22 Sep 2024 21:40:45 +0200 Subject: [PATCH 08/24] feature: added log settings saving --- .gitignore | 3 +++ .../STMViewer_test/MCUViewer_project/MCUViewer_test.cfg | 4 ++++ src/ConfigHandler/ConfigHandler.cpp | 8 ++++++++ src/Gui/GuiAcqusition.cpp | 2 +- src/PlotHandler/TracePlotHandler.cpp | 3 ++- 5 files changed, 18 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 95373d3f..d31829b5 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,6 @@ test/MCUViewer_test/.settings/ # Executables *.out *.app + +# Log files +*.csv \ No newline at end of file diff --git a/example/STMViewer_test/MCUViewer_project/MCUViewer_test.cfg b/example/STMViewer_test/MCUViewer_project/MCUViewer_test.cfg index 14bb0de3..4e7df426 100644 --- a/example/STMViewer_test/MCUViewer_project/MCUViewer_test.cfg +++ b/example/STMViewer_test/MCUViewer_project/MCUViewer_test.cfg @@ -13,6 +13,8 @@ target_name = STM32G474CC probe_mode = 1 probe_speed_khz = 50000 probe_sn = 506003225 +should_log = false +log_directory = [trace_settings] core_frequency = 150000 @@ -26,6 +28,8 @@ probe_type = 1 target_name = STM32G474CC probe_speed_khz = 10000 probe_sn = 506003225 +should_log = true +log_directory = C:/Users/klonyyy/PROJECTS/MCUViewer_/MCUViewer/example/STMViewer_test/MCUViewer_project [var0] name = test.a diff --git a/src/ConfigHandler/ConfigHandler.cpp b/src/ConfigHandler/ConfigHandler.cpp index d0ceea8a..ac489cd4 100644 --- a/src/ConfigHandler/ConfigHandler.cpp +++ b/src/ConfigHandler/ConfigHandler.cpp @@ -61,6 +61,8 @@ bool ConfigHandler::readConfigFile(std::mapget("settings").get("probe_SN"); + getValue("settings", "should_log", viewerSettings.shouldLog); + viewerSettings.logFilePath = ini->get("settings").get("log_directory"); getValue("trace_settings", "core_frequency", traceSettings.coreFrequency); getValue("trace_settings", "trace_prescaler", traceSettings.tracePrescaler); @@ -73,6 +75,8 @@ bool ConfigHandler::readConfigFile(std::mapget("trace_settings").get("target_name"); getValue("trace_settings", "probe_speed_kHz", traceProbeSettings.speedkHz); traceProbeSettings.serialNumber = ini->get("trace_settings").get("probe_SN"); + getValue("trace_settings", "should_log", traceSettings.shouldLog); + traceSettings.logFilePath = ini->get("trace_settings").get("log_directory"); /* TODO magic numbers (lots of them)! */ if (traceSettings.timeout == 0) @@ -237,6 +241,8 @@ bool ConfigHandler::saveConfigFile(std::map traces{}; + std::array traces{}; if (!traceReader->readTrace(timestamp, traces)) continue; @@ -253,6 +253,7 @@ void TracePlotHandler::dataHandler() else { traceReader->stopAcqusition(); + csvStreamer->finishLogging(); traceTriggered = false; } stateChangeOrdered = false; From 16124778fec89de26c1cb17682ef4e646d3e594b Mon Sep 17 00:00:00 2001 From: Piotr Wasilewski Date: Mon, 23 Sep 2024 23:09:35 +0200 Subject: [PATCH 09/24] wip: trying to fix Fedora install --- CMakeLists.txt | 7 +++++++ launch/MCUViewer.conf | 1 + launch/postinstall | 3 +++ 3 files changed, 11 insertions(+) create mode 100644 launch/MCUViewer.conf create mode 100644 launch/postinstall diff --git a/CMakeLists.txt b/CMakeLists.txt index 67181999..bf190597 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,6 +74,9 @@ if(UNIX) set(LIB_INSTALL_PATH /usr/local/lib) set(DESKTOP_FILE_PATH /usr/share/applications) + set(LIB_CONF_FILE ${CMAKE_CURRENT_SOURCE_DIR}/launch/MCUViewer.conf) + set(LIB_CONF_FILE_PATH /etc/ld.so.conf.d/) + if(APPLE) find_package(OpenGL REQUIRED) find_package(GLUT REQUIRED) @@ -269,6 +272,9 @@ if(UNIX) install(FILES ${JLINK_LINUX} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE DESTINATION ${LIB_INSTALL_PATH}) + install(FILES ${LIB_CONF_FILE} + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE + DESTINATION ${LIB_CONF_FILE_PATH}) set(CPACK_GENERATOR "DEB;RPM") set(CPACK_DEBIAN_PACKAGE_DEPENDS "libglfw3 | libglfw3-wayland, libgl1, libglib2.0-0, libgtk-3-0, libstdc++6, libusb-1.0-0, gdb") endif() @@ -285,4 +291,5 @@ set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON) set(CPACK_NSIS_MODIFY_PATH ON) set(CPACK_ALL_INSTALL_TYPES Full Developer) set(CPACK_COMPONENT_APPLICATIONS_INSTALL_TYPES Full) +set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${PROJECT_SOURCE_DIR}/launch/postinstall") include(CPack) \ No newline at end of file diff --git a/launch/MCUViewer.conf b/launch/MCUViewer.conf new file mode 100644 index 00000000..7ba15589 --- /dev/null +++ b/launch/MCUViewer.conf @@ -0,0 +1 @@ +/usr/local/lib \ No newline at end of file diff --git a/launch/postinstall b/launch/postinstall new file mode 100644 index 00000000..732a7320 --- /dev/null +++ b/launch/postinstall @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Running postinstall script..." +sudo ldconfig \ No newline at end of file From 6121b4cb84b0fea62eae3f719c3f81d6ecdeaa68 Mon Sep 17 00:00:00 2001 From: Piotr Wasilewski Date: Mon, 23 Sep 2024 23:38:50 +0200 Subject: [PATCH 10/24] wip: trying to fix Fedora install --- CMakeLists.txt | 2 +- launch/{postinstall => postinst} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename launch/{postinstall => postinst} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index bf190597..3c08a89b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -291,5 +291,5 @@ set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON) set(CPACK_NSIS_MODIFY_PATH ON) set(CPACK_ALL_INSTALL_TYPES Full Developer) set(CPACK_COMPONENT_APPLICATIONS_INSTALL_TYPES Full) -set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${PROJECT_SOURCE_DIR}/launch/postinstall") +set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${PROJECT_SOURCE_DIR}/launch/postinst") include(CPack) \ No newline at end of file diff --git a/launch/postinstall b/launch/postinst similarity index 100% rename from launch/postinstall rename to launch/postinst From a1cd99017cefd703c5365953f47b41d63691d5bc Mon Sep 17 00:00:00 2001 From: Piotr Wasilewski Date: Tue, 24 Sep 2024 17:20:09 +0200 Subject: [PATCH 11/24] fix: fixed problems with Fedora install #83 --- CMakeLists.txt | 10 +++++----- launch/{ => install/Unix}/MCUViewer.conf | 0 launch/{ => install/Unix}/MCUViewer.desktop | 0 launch/{ => install/Unix}/icon.png | Bin launch/{ => install/Unix}/icon.xcf | Bin launch/{ => install/Unix}/postinst | 0 .../{ => install/Unix}/udevrules/49-stlinkv1.rules | 0 .../Unix}/udevrules/49-stlinkv2-1.rules | 0 .../{ => install/Unix}/udevrules/49-stlinkv2.rules | 0 .../{ => install/Unix}/udevrules/49-stlinkv3.rules | 0 launch/{ => install/Windows}/icon.ico | Bin launch/{ => install/Windows}/icon.rc | 0 12 files changed, 5 insertions(+), 5 deletions(-) rename launch/{ => install/Unix}/MCUViewer.conf (100%) rename launch/{ => install/Unix}/MCUViewer.desktop (100%) rename launch/{ => install/Unix}/icon.png (100%) rename launch/{ => install/Unix}/icon.xcf (100%) rename launch/{ => install/Unix}/postinst (100%) rename launch/{ => install/Unix}/udevrules/49-stlinkv1.rules (100%) rename launch/{ => install/Unix}/udevrules/49-stlinkv2-1.rules (100%) rename launch/{ => install/Unix}/udevrules/49-stlinkv2.rules (100%) rename launch/{ => install/Unix}/udevrules/49-stlinkv3.rules (100%) rename launch/{ => install/Windows}/icon.ico (100%) rename launch/{ => install/Windows}/icon.rc (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c08a89b..7e91d52e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,7 +74,7 @@ if(UNIX) set(LIB_INSTALL_PATH /usr/local/lib) set(DESKTOP_FILE_PATH /usr/share/applications) - set(LIB_CONF_FILE ${CMAKE_CURRENT_SOURCE_DIR}/launch/MCUViewer.conf) + set(LIB_CONF_FILE ${CMAKE_CURRENT_SOURCE_DIR}/launch/install/Unix/MCUViewer.conf) set(LIB_CONF_FILE_PATH /etc/ld.so.conf.d/) if(APPLE) @@ -90,7 +90,7 @@ endif() if(WIN32) enable_language("RC") - set(ICON_RC "${CMAKE_CURRENT_SOURCE_DIR}/launch/icon.rc") + set(ICON_RC "${CMAKE_CURRENT_SOURCE_DIR}/launch/install/Windows/icon.rc") set(GLFW3_WINDOWS ${CMAKE_CURRENT_SOURCE_DIR}/third_party/GLFW/lib/windows/glfw3.dll) set(STLINK_WINDOWS ${CMAKE_CURRENT_SOURCE_DIR}/third_party/stlink/lib/windows/libstlink.a) set(JLINK_WINDOWS ${CMAKE_CURRENT_SOURCE_DIR}/third_party/jlink/lib/windows/JLink_x64.dll) @@ -265,8 +265,8 @@ if(WIN32) endif() if(UNIX) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/launch/icon.png DESTINATION ${INSTALL_PATH}) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/launch/MCUViewer.desktop + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/launch/install/Unix/icon.png DESTINATION ${INSTALL_PATH}) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/launch/install/Unix/MCUViewer.desktop PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE DESTINATION ${DESKTOP_FILE_PATH}) install(FILES ${JLINK_LINUX} @@ -291,5 +291,5 @@ set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON) set(CPACK_NSIS_MODIFY_PATH ON) set(CPACK_ALL_INSTALL_TYPES Full Developer) set(CPACK_COMPONENT_APPLICATIONS_INSTALL_TYPES Full) -set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${PROJECT_SOURCE_DIR}/launch/postinst") +set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${PROJECT_SOURCE_DIR}/launch/install/Unix/postinst") include(CPack) \ No newline at end of file diff --git a/launch/MCUViewer.conf b/launch/install/Unix/MCUViewer.conf similarity index 100% rename from launch/MCUViewer.conf rename to launch/install/Unix/MCUViewer.conf diff --git a/launch/MCUViewer.desktop b/launch/install/Unix/MCUViewer.desktop similarity index 100% rename from launch/MCUViewer.desktop rename to launch/install/Unix/MCUViewer.desktop diff --git a/launch/icon.png b/launch/install/Unix/icon.png similarity index 100% rename from launch/icon.png rename to launch/install/Unix/icon.png diff --git a/launch/icon.xcf b/launch/install/Unix/icon.xcf similarity index 100% rename from launch/icon.xcf rename to launch/install/Unix/icon.xcf diff --git a/launch/postinst b/launch/install/Unix/postinst similarity index 100% rename from launch/postinst rename to launch/install/Unix/postinst diff --git a/launch/udevrules/49-stlinkv1.rules b/launch/install/Unix/udevrules/49-stlinkv1.rules similarity index 100% rename from launch/udevrules/49-stlinkv1.rules rename to launch/install/Unix/udevrules/49-stlinkv1.rules diff --git a/launch/udevrules/49-stlinkv2-1.rules b/launch/install/Unix/udevrules/49-stlinkv2-1.rules similarity index 100% rename from launch/udevrules/49-stlinkv2-1.rules rename to launch/install/Unix/udevrules/49-stlinkv2-1.rules diff --git a/launch/udevrules/49-stlinkv2.rules b/launch/install/Unix/udevrules/49-stlinkv2.rules similarity index 100% rename from launch/udevrules/49-stlinkv2.rules rename to launch/install/Unix/udevrules/49-stlinkv2.rules diff --git a/launch/udevrules/49-stlinkv3.rules b/launch/install/Unix/udevrules/49-stlinkv3.rules similarity index 100% rename from launch/udevrules/49-stlinkv3.rules rename to launch/install/Unix/udevrules/49-stlinkv3.rules diff --git a/launch/icon.ico b/launch/install/Windows/icon.ico similarity index 100% rename from launch/icon.ico rename to launch/install/Windows/icon.ico diff --git a/launch/icon.rc b/launch/install/Windows/icon.rc similarity index 100% rename from launch/icon.rc rename to launch/install/Windows/icon.rc From b6d32c8ad512fb486e6b25a150d4f05463921b56 Mon Sep 17 00:00:00 2001 From: Piotr Wasilewski Date: Tue, 24 Sep 2024 17:38:44 +0200 Subject: [PATCH 12/24] fix: trying to fix Windows pipeline --- CMakeLists.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e91d52e..fcd9d01e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ project(MCUViewer) set(MCUVIEWER_VERSION 1.0.0) -set(CMAKE_BUILD_TYPE Debug) +set(CMAKE_BUILD_TYPE ReleaseWithDbg) set(CMAKE_CXX_STANDARD 20) set(CMAKE_EXPORT_COMPILE_COMMANDS 1) @@ -33,8 +33,8 @@ if(WIN32 AND "${PLATFORM}" STREQUAL "native") endif() if(CMAKE_BUILD_TYPE STREQUAL "ReleaseWithDbg") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g1") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g1") endif() add_compile_options(-Wall @@ -42,7 +42,8 @@ add_compile_options(-Wall -Wextra -Wpedantic -Wno-unused-parameter - -Wno-missing-field-initializers) + -Wno-missing-field-initializers + -mbig-obj) set(JLINK_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/jlink/inc/) From 986fd2c448253649649ef66e872d6700ef985565 Mon Sep 17 00:00:00 2001 From: Piotr Wasilewski Date: Tue, 24 Sep 2024 17:50:50 +0200 Subject: [PATCH 13/24] fix: trying to fix Windows pipeline --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fcd9d01e..c5ca519c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,7 @@ add_compile_options(-Wall -Wpedantic -Wno-unused-parameter -Wno-missing-field-initializers - -mbig-obj) + -Wa,-mbig-obj) set(JLINK_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/jlink/inc/) From 2e0f3c41eba4cd64aab07b52fb81eb5a4fd83944 Mon Sep 17 00:00:00 2001 From: Piotr Wasilewski Date: Tue, 24 Sep 2024 17:58:01 +0200 Subject: [PATCH 14/24] fix: trying to fix Windows pipeline --- CMakeLists.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c5ca519c..64cd6905 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,8 +42,11 @@ add_compile_options(-Wall -Wextra -Wpedantic -Wno-unused-parameter - -Wno-missing-field-initializers - -Wa,-mbig-obj) + -Wno-missing-field-initializers) + +if(WIN32) + add_compile_options(-Wa,-mbig-obj) +endif() set(JLINK_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/jlink/inc/) From 3b004f65d2d9a9093c49ee4fa6568d9ed2da6dd2 Mon Sep 17 00:00:00 2001 From: Piotr Wasilewski Date: Tue, 24 Sep 2024 18:15:50 +0200 Subject: [PATCH 15/24] fix: implemented production cmake switch --- CMakeLists.txt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 64cd6905..0b65a11c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,12 +19,16 @@ endif() project(MCUViewer) set(MCUVIEWER_VERSION 1.0.0) - -set(CMAKE_BUILD_TYPE ReleaseWithDbg) set(CMAKE_CXX_STANDARD 20) - set(CMAKE_EXPORT_COMPILE_COMMANDS 1) +if(PRODUCTION) + set(CMAKE_BUILD_TYPE Release) + message("Building for production!") +else() + set(CMAKE_BUILD_TYPE ReleaseWithDbg) +endif() + if(WIN32 AND "${PLATFORM}" STREQUAL "native") set(LLVM_DIR "C:/msys64/mingw64/bin") set(CMAKE_PREFIX_PATH ${LLVM_DIR} ${CMAKE_PREFIX_PATH}) From ea55321f4bcceed076bc247c6f23441f3505b891 Mon Sep 17 00:00:00 2001 From: Piotr Wasilewski Date: Tue, 24 Sep 2024 21:33:46 +0200 Subject: [PATCH 16/24] docs: added SEGGER's SWO wiki link --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4e16a60e..8d25d592 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ It works similar with other probes such as JLink, so be sure to check the maximu Example project with MCUViewer config file is located in test/MCUViewer_test directory. FAQ and common issues: + 1. Problem: My trace doesn't look like it's supposed to and I get a lot of error frames Answer: Try lowering the trace prescaller and check the SWO pin connection - the SWO pin output is high frequency and it shouldn't be too long. @@ -100,6 +101,7 @@ Answer: Try logging fewer channels simultaneously. It could be that you've satur 3. Problem: My trace looks like it's supposed to but I get the "delayed timestamp 1" indicator Answer: This is not a critical error, however, you should be cautious as some of the trace frames may be delayed. To fix try logging fewer channels simultaneously. +Please remember that although SWO is ARM standardized, there might be some differences the setup process. It should work without problems in most cases, but some MCUs might require some additional steps. Please see the [SEGGER's wiki page](https://wiki.segger.com/SWO) for more information. ## Building From 2c464a405767feb8512d9d1c01bbd45463c0d5a3 Mon Sep 17 00:00:00 2001 From: Piotr Wasilewski Date: Tue, 24 Sep 2024 21:40:17 +0200 Subject: [PATCH 17/24] feature: added mcu type to the issue template --- .github/ISSUE_TEMPLATE/issue_template.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/issue_template.yml b/.github/ISSUE_TEMPLATE/issue_template.yml index 0b7950a2..85a5a332 100644 --- a/.github/ISSUE_TEMPLATE/issue_template.yml +++ b/.github/ISSUE_TEMPLATE/issue_template.yml @@ -22,6 +22,13 @@ body: placeholder: "e.g. ST-Link V2, ST-Link V3 MINIE, J-Link Ultra" validations: required: true + - type: input + id: MCU + attributes: + label: "Microcontroller:" + placeholder: "e.g. STM32G474CC (ST), LPC1768FBD100 (NXP)" + validations: + required: true - type: textarea id: issue_description attributes: From 3cf19667c62d60fad4404ea3554458d6d72b8eb7 Mon Sep 17 00:00:00 2001 From: Piotr Wasilewski Date: Tue, 24 Sep 2024 22:24:21 +0200 Subject: [PATCH 18/24] fix: fixed small bugs in csv streamer --- src/PlotHandler/PlotHandler.cpp | 38 ++++++++++++++++------------ src/PlotHandler/PlotHandler.hpp | 1 + src/PlotHandler/TracePlotHandler.cpp | 33 ++++++++++++++++-------- src/PlotHandler/TracePlotHandler.hpp | 1 + 4 files changed, 47 insertions(+), 26 deletions(-) diff --git a/src/PlotHandler/PlotHandler.cpp b/src/PlotHandler/PlotHandler.cpp index 0b33ba88..030a6ff9 100644 --- a/src/PlotHandler/PlotHandler.cpp +++ b/src/PlotHandler/PlotHandler.cpp @@ -150,21 +150,7 @@ void PlotHandler::dataHandler() { auto addressSizeVector = createAddressSizeVector(); - /* prepare CSV files for streaming */ - std::vector headerNames; - - for (auto& [key, plot] : plotsMap) - { - if (!plot->getVisibility()) - continue; - - for (auto& [name, ser] : plot->getSeriesMap()) - { - headerNames.push_back(name); - } - } - csvStreamer->prepareFile(settings.logFilePath); - csvStreamer->createHeader(headerNames); + prepareCSVFile(); if (varReader->start(probeSettings, addressSizeVector, settings.sampleFrequencyHz)) { @@ -178,7 +164,8 @@ void PlotHandler::dataHandler() else { varReader->stop(); - csvStreamer->finishLogging(); + if (settings.shouldLog) + csvStreamer->finishLogging(); } stateChangeOrdered = false; } @@ -199,4 +186,23 @@ std::vector> PlotHandler::createAddressSizeVector() } return addressSizeVector; +} + +void PlotHandler::prepareCSVFile() +{ + if (!settings.shouldLog) + return; + + std::vector headerNames; + + for (auto& [key, plot] : plotsMap) + { + if (!plot->getVisibility()) + continue; + + for (auto& [name, ser] : plot->getSeriesMap()) + headerNames.push_back(name); + } + csvStreamer->prepareFile(settings.logFilePath); + csvStreamer->createHeader(headerNames); } \ No newline at end of file diff --git a/src/PlotHandler/PlotHandler.hpp b/src/PlotHandler/PlotHandler.hpp index affb47f2..32a9ce1c 100644 --- a/src/PlotHandler/PlotHandler.hpp +++ b/src/PlotHandler/PlotHandler.hpp @@ -55,6 +55,7 @@ class PlotHandler : public PlotHandlerBase private: void dataHandler(); std::vector> createAddressSizeVector(); + void prepareCSVFile(); private: static constexpr size_t maxVariablesOnSinglePlot = 100; diff --git a/src/PlotHandler/TracePlotHandler.cpp b/src/PlotHandler/TracePlotHandler.cpp index 944a379a..a807cee8 100644 --- a/src/PlotHandler/TracePlotHandler.cpp +++ b/src/PlotHandler/TracePlotHandler.cpp @@ -227,23 +227,16 @@ void TracePlotHandler::dataHandler() if (viewerState == state::RUN) { std::array activeChannels{}; - /* prepare CSV files for streaming */ - std::vector headerNames; - uint32_t i = 0; + size_t i = 0; for (auto& [key, plot] : plotsMap) - { activeChannels[i++] = plot->getVisibility(); - if (plot->getVisibility()) - headerNames.push_back(std::string("CH") + std::to_string(i)); - } errorFrames.reset(); delayed3Frames.reset(); lastErrorMsg = ""; - csvStreamer->prepareFile(settings.logFilePath); - csvStreamer->createHeader(headerNames); + prepareCSVFile(); if (traceReader->startAcqusition(probeSettings, activeChannels)) time = 0; @@ -253,7 +246,8 @@ void TracePlotHandler::dataHandler() else { traceReader->stopAcqusition(); - csvStreamer->finishLogging(); + if (settings.shouldLog) + csvStreamer->finishLogging(); traceTriggered = false; } stateChangeOrdered = false; @@ -261,3 +255,22 @@ void TracePlotHandler::dataHandler() } logger->info("Exiting trace plot handler thread"); } + +void TracePlotHandler::prepareCSVFile() +{ + if (!settings.shouldLog) + return; + + std::vector headerNames; + + size_t i = 0; + for (auto& [key, plot] : plotsMap) + { + if (plot->getVisibility()) + headerNames.push_back(std::string("CH") + std::to_string(i)); + i++; + } + + csvStreamer->prepareFile(settings.logFilePath); + csvStreamer->createHeader(headerNames); +} \ No newline at end of file diff --git a/src/PlotHandler/TracePlotHandler.hpp b/src/PlotHandler/TracePlotHandler.hpp index a75a8713..06e7fcbb 100644 --- a/src/PlotHandler/TracePlotHandler.hpp +++ b/src/PlotHandler/TracePlotHandler.hpp @@ -55,6 +55,7 @@ class TracePlotHandler : public PlotHandlerBase private: void dataHandler(); + void prepareCSVFile(); private: class MarkerTimestamps From f67686926352a4f8d2bf6cfdf573dced96ab76db Mon Sep 17 00:00:00 2001 From: Piotr Wasilewski Date: Wed, 25 Sep 2024 23:07:19 +0200 Subject: [PATCH 19/24] fix: fixed JLink trace hanging on Linux --- example/STMViewer_test/MCUViewer_project/MCUViewer_test.cfg | 2 +- src/TraceReader/JLinkTraceProbe.cpp | 6 ++++++ src/TraceReader/JlinkTraceProbe.cpp | 6 ++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/example/STMViewer_test/MCUViewer_project/MCUViewer_test.cfg b/example/STMViewer_test/MCUViewer_project/MCUViewer_test.cfg index 4e7df426..59a1a24a 100644 --- a/example/STMViewer_test/MCUViewer_project/MCUViewer_test.cfg +++ b/example/STMViewer_test/MCUViewer_project/MCUViewer_test.cfg @@ -11,7 +11,7 @@ stop_acq_on_elf_change = true probe_type = 1 target_name = STM32G474CC probe_mode = 1 -probe_speed_khz = 50000 +probe_speed_khz = 20000 probe_sn = 506003225 should_log = false log_directory = diff --git a/src/TraceReader/JLinkTraceProbe.cpp b/src/TraceReader/JLinkTraceProbe.cpp index 42cac488..700a8e36 100644 --- a/src/TraceReader/JLinkTraceProbe.cpp +++ b/src/TraceReader/JLinkTraceProbe.cpp @@ -11,6 +11,12 @@ JlinkTraceProbe::JlinkTraceProbe(spdlog::logger* logger) : logger(logger) bool JlinkTraceProbe::stopTrace() { + if (JLINKARM_SWO_Control(JLINKARM_SWO_CMD_STOP, nullptr) == -1) + { + logger->error("Error stopping trace!"); + return false; + } + JLINKARM_Close(); logger->info("Trace stopped."); return true; diff --git a/src/TraceReader/JlinkTraceProbe.cpp b/src/TraceReader/JlinkTraceProbe.cpp index 42cac488..700a8e36 100644 --- a/src/TraceReader/JlinkTraceProbe.cpp +++ b/src/TraceReader/JlinkTraceProbe.cpp @@ -11,6 +11,12 @@ JlinkTraceProbe::JlinkTraceProbe(spdlog::logger* logger) : logger(logger) bool JlinkTraceProbe::stopTrace() { + if (JLINKARM_SWO_Control(JLINKARM_SWO_CMD_STOP, nullptr) == -1) + { + logger->error("Error stopping trace!"); + return false; + } + JLINKARM_Close(); logger->info("Trace stopped."); return true; From 4631f4242241312f6b9cc6d4c07f385d61d8743c Mon Sep 17 00:00:00 2001 From: Piotr Wasilewski Date: Sun, 29 Sep 2024 08:27:23 +0200 Subject: [PATCH 20/24] feature: improved drag&drop #86 --- CMakeLists.txt | 2 +- src/Gui/Gui.cpp | 18 ++++++++++-------- src/Gui/GuiPlots.cpp | 16 +++++++--------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b65a11c..5ed71f15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,7 @@ if(PRODUCTION) set(CMAKE_BUILD_TYPE Release) message("Building for production!") else() - set(CMAKE_BUILD_TYPE ReleaseWithDbg) + set(CMAKE_BUILD_TYPE Debug) endif() if(WIN32 AND "${PLATFORM}" STREQUAL "native") diff --git a/src/Gui/Gui.cpp b/src/Gui/Gui.cpp index 5dfdd458..96e5f7be 100644 --- a/src/Gui/Gui.cpp +++ b/src/Gui/Gui.cpp @@ -475,7 +475,9 @@ void Gui::drawVarTable() if (selection.empty()) selection.insert(name); - ImGui::SetDragDropPayload("MY_DND", &selection, sizeof(selection)); + /* pass a pointer to the selection as we have to call clear() on the original object upon receiving */ + std::set* selectionPtr = &selection; + ImGui::SetDragDropPayload("MY_DND", &selectionPtr, sizeof(selectionPtr)); ImGui::PushID(name.c_str()); ImGui::ColorEdit4("##", &vars[*selection.begin()]->getColor().r, ImGuiColorEditFlags_NoInputs); ImGui::SameLine(); @@ -668,13 +670,13 @@ void Gui::drawPlotsTree() } if (ImGui::BeginDragDropTarget()) { - std::set selection; if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_DND")) { - selection = *(decltype(selection)*)payload->Data; + std::set* selection = *(std::set**)payload->Data; - for (auto& name : selection) + for (const auto& name : *selection) plt->addSeries(*vars[name]); + selection->clear(); } ImGui::EndDragDropTarget(); } @@ -1113,8 +1115,8 @@ void Gui::drawCenteredText(std::string&& text) void Gui::drawTextAlignedToSize(std::string&& text, size_t alignTo) { - size_t currentLength = text.length(); - size_t spacesToAdd = (currentLength < alignTo) ? (alignTo - currentLength) : 0; - std::string alignedText = text + std::string(spacesToAdd, ' '); - ImGui::Text("%s", alignedText.c_str()); + size_t currentLength = text.length(); + size_t spacesToAdd = (currentLength < alignTo) ? (alignTo - currentLength) : 0; + std::string alignedText = text + std::string(spacesToAdd, ' '); + ImGui::Text("%s", alignedText.c_str()); } diff --git a/src/Gui/GuiPlots.cpp b/src/Gui/GuiPlots.cpp index b81a2b1d..d10cff39 100644 --- a/src/Gui/GuiPlots.cpp +++ b/src/Gui/GuiPlots.cpp @@ -4,14 +4,13 @@ void Gui::dragAndDropPlot(Plot* plot) { if (ImPlot::BeginDragDropTargetPlot()) { - std::set selection; if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_DND")) { - selection = *(decltype(selection)*)payload->Data; + std::set* selection = *(std::set**)payload->Data; - for (auto& name : selection) + for (const auto& name : *selection) plot->addSeries(*vars[name]); - selection.clear(); + selection->clear(); } ImPlot::EndDragDropTarget(); } @@ -216,7 +215,7 @@ void Gui::drawPlotTable(Plot* plot, ScrollingBuffer& time, std::mapgetSeriesValueString(key, serPtr->var->getValue()).data(), maxVariableNameLength); showChangeFormatPopup("format", *plot, key); ImGui::TableSetColumnIndex(3); - ImGui::PushID("input"); + ImGui::PushID("input"); char newValue[maxVariableNameLength] = {0}; if (ImGui::SelectableInput(key.c_str(), false, ImGuiSelectableFlags_None, newValue, maxVariableNameLength)) { @@ -238,14 +237,13 @@ void Gui::drawPlotTable(Plot* plot, ScrollingBuffer& time, std::map selection; if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_DND")) { - selection = *(decltype(selection)*)payload->Data; + std::set* selection = *(std::set**)payload->Data; - for (auto& name : selection) + for (const auto& name : *selection) plot->addSeries(*vars[name]); - selection.clear(); + selection->clear(); } ImGui::EndDragDropTarget(); } From 9a3194778ef1d08c9273102567d183102aa6d12c Mon Sep 17 00:00:00 2001 From: Piotr Wasilewski Date: Sun, 29 Sep 2024 22:08:25 +0200 Subject: [PATCH 21/24] feature: added coloring for delayed timestamp 1/2 indicators --- src/Gui/Gui.hpp | 7 +++++-- src/Gui/GuiSwoControl.cpp | 23 ++++------------------- 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/src/Gui/Gui.hpp b/src/Gui/Gui.hpp index dd475f27..7b8c5268 100644 --- a/src/Gui/Gui.hpp +++ b/src/Gui/Gui.hpp @@ -142,9 +142,12 @@ class Gui valueChanged(str); } template - void drawDescriptionWithNumber(const char* description, T number, std::string unit = "", size_t decimalPlaces = 5) + void drawDescriptionWithNumber(const char* description, T number, std::string unit = "", size_t decimalPlaces = 5, float threshold = std::nan(""), ImVec4 thresholdExceededColor = {0.0f, 0.0f, 0.0f, 1.0f}) { - ImGui::Text("%s", description); + if (threshold != std::nan("") && number > threshold) + ImGui::TextColored(thresholdExceededColor, "%s", description); + else + ImGui::Text("%s", description); ImGui::SameLine(); std::ostringstream formattedNum; formattedNum << std::fixed << std::setprecision(decimalPlaces) << number; diff --git a/src/Gui/GuiSwoControl.cpp b/src/Gui/GuiSwoControl.cpp index 2bf3de00..de1055ab 100644 --- a/src/Gui/GuiSwoControl.cpp +++ b/src/Gui/GuiSwoControl.cpp @@ -66,26 +66,11 @@ void Gui::drawIndicatorsSwo() drawDescriptionWithNumber("frames total: ", indicators.framesTotal); drawDescriptionWithNumber("sleep cycles: ", indicators.sleepCycles); drawDescriptionWithNumber("error frames total: ", indicators.errorFramesTotal); - - const char* inView = "error frames in view: "; - if (indicators.errorFramesInView > 0) - ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "%s", inView); - else - ImGui::Text("%s", inView); - ImGui::SameLine(); - ImGui::Text("%s", (std::to_string(indicators.errorFramesInView)).c_str()); - - drawDescriptionWithNumber("delayed timestamp 1: ", indicators.delayedTimestamp1); - drawDescriptionWithNumber("delayed timestamp 2: ", indicators.delayedTimestamp2); + drawDescriptionWithNumber("error frames in view: ", indicators.errorFramesInView, "", 5, 0, {1, 0, 0, 1}); + drawDescriptionWithNumber("delayed timestamp 1: ", indicators.delayedTimestamp1, "", 5, 0, {1, 1, 0, 1}); + drawDescriptionWithNumber("delayed timestamp 2: ", indicators.delayedTimestamp2, "", 5, 0, {1, 1, 0, 1}); drawDescriptionWithNumber("delayed timestamp 3: ", indicators.delayedTimestamp3); - - const char* timestampDelayed3inView = "delayed timestamp 3 in view: "; - if (indicators.delayedTimestamp3InView > 0) - ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "%s", timestampDelayed3inView); - else - ImGui::Text("%s", timestampDelayed3inView); - ImGui::SameLine(); - ImGui::Text("%s", (std::to_string(indicators.delayedTimestamp3InView)).c_str()); + drawDescriptionWithNumber("delayed timestamp 3 in view: ", indicators.delayedTimestamp3InView, "", 5, 0, {1, 0, 0, 1}); } void Gui::drawPlotsTreeSwo() From 2be05e3b1c1c86c702a48b7c879f9def2f0d0a1e Mon Sep 17 00:00:00 2001 From: Piotr Wasilewski Date: Wed, 2 Oct 2024 23:12:34 +0200 Subject: [PATCH 22/24] fix: fixed segfault bug due to csv buffers being uninitialized --- src/CSVStreamer/CSVStreamer.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CSVStreamer/CSVStreamer.hpp b/src/CSVStreamer/CSVStreamer.hpp index f446dc52..25a1010c 100644 --- a/src/CSVStreamer/CSVStreamer.hpp +++ b/src/CSVStreamer/CSVStreamer.hpp @@ -54,8 +54,8 @@ class CSVStreamer std::future saveTask{}; std::string filePath; std::ofstream csvFile; - Buffer buffer1; - Buffer buffer2; + Buffer buffer1{}; + Buffer buffer2{}; Buffer* currentBuffer; Buffer* processingBuffer; }; From 877cb251b20e23184054705b288210bb6d99bc42 Mon Sep 17 00:00:00 2001 From: Piotr Wasilewski Date: Wed, 2 Oct 2024 23:27:34 +0200 Subject: [PATCH 23/24] fix: fixed statistics segfault #88 --- src/Statistics/Statistics.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Statistics/Statistics.hpp b/src/Statistics/Statistics.hpp index 71671faa..acb92cbb 100644 --- a/src/Statistics/Statistics.hpp +++ b/src/Statistics/Statistics.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -122,9 +123,11 @@ class Statistics size_t end = time.size() - 1; size_t i = 1; - if (data.empty() || time.empty()) + if (data.empty() || time.empty() || data.size() < 2 || time.size() < 2) return false; + std::cout << data.size() << std::endl; + while (data[i] == data[0] && i < data.size()) i++; start = i; From 01104194d27f2fae423e291916bacd6344376324 Mon Sep 17 00:00:00 2001 From: Piotr Wasilewski Date: Thu, 3 Oct 2024 20:27:21 +0200 Subject: [PATCH 24/24] feature: set version to 1.0.1 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ed71f15..823a11a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,7 +18,7 @@ endif() project(MCUViewer) -set(MCUVIEWER_VERSION 1.0.0) +set(MCUVIEWER_VERSION 1.0.1) set(CMAKE_CXX_STANDARD 20) set(CMAKE_EXPORT_COMPILE_COMMANDS 1)