diff --git a/example/STMViewer_test/MCUViewer_project/MCUViewer_test.cfg b/example/STMViewer_test/MCUViewer_project/MCUViewer_test.cfg index 7b07920..cc20ee7 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 cb6678c..439f60a 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 af87e15..2f2c5b4 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 d9b6254..a6db230 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 203b973..affb47f 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 e835491..e5d4160 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 74a0d9e..23d0e5c 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 f4afeaa..a75a871 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{};