diff --git a/ai_omniscope-v2-communication_sw b/ai_omniscope-v2-communication_sw index e084bad7..93dede90 160000 --- a/ai_omniscope-v2-communication_sw +++ b/ai_omniscope-v2-communication_sw @@ -1 +1 @@ -Subproject commit e084bad75322f5b0853116806a830311e3f4b8ad +Subproject commit 93dede90c91f5ef17f4b2c2b00ed911e0b52a319 diff --git a/src/handler.cpp b/src/handler.cpp index e8544a78..f5cfd731 100644 --- a/src/handler.cpp +++ b/src/handler.cpp @@ -1,133 +1,228 @@ #include "handler.hpp" +#include +#include #include #include "popups.hpp" #include "get_from_github.hpp" #include "../imgui-stdlib/imgui_stdlib.h" -void addPlots(const char *name, std::function axesSetup) { - static std::set firstRun; - const auto &plots{captureData}; - auto const plotRegion = ImGui::GetContentRegionAvail(); +std::vector getDeviceInfos() { + std::vector axisInfos; + std::vector> assignedEgus; + if (sampler.has_value()) { + for (auto const &device : sampler->sampleDevices) { + // TODO replace ADC counts with language variable + std::string egu = device.first->getEgu().value_or("ADC counts"); + auto id = device.first->getId(); + if (id.has_value()) { + Omniscope::Id deviceId = id.value(); + std::string timebase{std::to_string(deviceId.sampleRate)}; + if (captureData.find(deviceId) != captureData.end()) { + auto eguIterator = std::ranges::find( + assignedEgus, egu, + &std::pair::first); + if (eguIterator == assignedEgus.end()) { + if (assignedEgus.size() <= 3) { + ImAxis_ nextYAxis = static_cast( + ImAxis_Y1 + assignedEgus.size()); + assignedEgus.push_back( + std::make_pair(egu, nextYAxis)); + eguIterator = (assignedEgus.end() - 1); + } else { + fmt::print( + "too many Axes added, egu not added: " + "{}\nDevice id: {}", + egu, id.value()); + break; + } + } + AxisInfo axisInfo{ + std::make_pair(deviceId, + std::ref(captureData[deviceId])), + *eguIterator, timebase}; + axisInfos.push_back(axisInfo); + } + } else { + fmt::print("Error no device id found\n"); + } + } + } + return axisInfos; +} - if (ImPlot::BeginPlot(name, plotRegion, ImPlotFlags_NoFrame)) { - double x_min = std::numeric_limits::max(); - double x_max = std::numeric_limits::min(); - for (auto const &plot : plots) - if (!plot.second.empty()) { - x_min = std::min(x_min, plot.second.front().first); - x_max = std::max(x_max, plot.second.back().first); - } +void addPlots(const char *name, bool const flagPaused, + std::function + axesSetup) { + static std::set firstRun; + auto const plotRegion = ImGui::GetContentRegionAvail(); + static int activeAxes{0}; + //TODO search devices must work aswell + if (plotAxes.size() <= activeAxes) { + plotAxes = getDeviceInfos(); + activeAxes = plotAxes.size(); - axesSetup(x_max); - auto const limits = [&]() { - if (!firstRun.contains(name)) { - firstRun.insert(name); - return ImPlotRect(x_min, x_max, 0, 0); - } - return ImPlot::GetPlotLimits(); - }(); - auto addPlot = [&](auto const &plot) { - if (!plot.second.empty()) { - auto const start = [&]() { - auto p = std::lower_bound(plot.second.begin(), plot.second.end(), - std::pair{limits.X.Min, 0}); - if (p != plot.second.begin()) - return p - 1; - return p; - }(); + } + if (ImPlot::BeginPlot(name, plotRegion, ImPlotFlags_NoFrame)) { + double x_min = std::numeric_limits::max(); + double x_max = std::numeric_limits::min(); - auto const end = [&]() { - auto p = std::upper_bound(start, plot.second.end(), - std::pair{limits.X.Max, 0}); - if (p != plot.second.end()) - return p + 1; - return p; - }(); + for (auto const &axes : plotAxes) { + // fmt::print("data size:{}, egu: {}\n", axes.data.second.size(), + // axes.egu.first); + if (!axes.data.second.empty()) { + x_max = std::max(x_max, axes.data.second.back().first); + //TODO save max and min value over same axis + auto [min, max] = std::minmax_element(axes.data.second.begin(), + axes.data.second.end()); + double yMin = min->first + (min->first * 0.15); + double yMax = max->second + (max->second * 0.15); + // fmt::print("yMin {}, yMax{}\n", yMin, yMax); + axesSetup(x_max, axes.egu.first, axes.egu.second, yMin, yMax); + } + } - std::size_t const stride = [&]() -> std::size_t { - auto const s = std::distance(start, end) / (plotRegion.x * 2.0); - if (1 >= s) - return 1; - return static_cast(s); + auto const limits = [&]() { + if (!firstRun.contains(name)) { + firstRun.insert(name); + return ImPlotRect(x_min, x_max, 0, 0); + } + return ImPlot::GetPlotLimits(); }(); - ImPlot::PlotLine( - fmt::format("{}-{}", plot.first.type, plot.first.serial).c_str(), - std::addressof(start->first), std::addressof(start->second), - static_cast(std::distance(start, end)) / stride, 0, 0, - 2 * sizeof(double) * stride); - } - }; + auto addPlot = [&](auto const &plot, ImAxis_ yAxis) { + if (!plot.second.empty()) { + auto const start = [&]() { + auto p = std::lower_bound( + plot.second.begin(), plot.second.end(), + std::pair{limits.X.Min, 0}); + if (p != plot.second.begin()) return p - 1; + return p; + }(); + + auto const end = [&]() { + auto p = std::upper_bound( + start, plot.second.end(), + std::pair{limits.X.Max, 0}); + if (p != plot.second.end()) return p + 1; + return p; + }(); + + std::size_t const stride = [&]() -> std::size_t { + auto const s = + std::distance(start, end) / (plotRegion.x * 2.0); + if (1 >= s) return 1; + return static_cast(s); + }(); + + // determine which axes is the right one to choose + ImPlot::SetAxes(ImAxis_X1, yAxis); + ImPlot::PlotLine( + fmt::format("{}-{}", plot.first.type, plot.first.serial) + .c_str(), + std::addressof(start->first), std::addressof(start->second), + static_cast(std::distance(start, end)) / + stride, + 0, 0, 2 * sizeof(double) * stride); + } + }; + for (int count = 0; auto const &plot : plotAxes) { + ImPlot::SetNextLineStyle(ImVec4{ + colorMap[plot.data.first][0], colorMap[plot.data.first][1], + colorMap[plot.data.first][2], 1.0f}); + addPlot(plot.data, plot.egu.second); + } - for (auto const &plot : plots) { - ImPlot::SetNextLineStyle(ImVec4{colorMap[plot.first][0], - colorMap[plot.first][1], - colorMap[plot.first][2], 1.0f}); - addPlot(plot); + ImPlot::EndPlot(); } +} - ImPlot::EndPlot(); - } +void parseDeviceMetaData(Omniscope::MetaData metaData, + std::shared_ptr &device) { + try { + nlohmann::json metaJson = nlohmann::json::parse(metaData.data); + fmt::print("{}\n", metaJson.dump()); + device->setScale(std::stod(metaJson["scale"].dump())); + device->setOffset(std::stod(metaJson["offset"].dump())); + device->setEgu(metaJson["egu"]); + } catch (...) { + fmt::print("parsing Meta Data error: {}", metaData.data); + } } void initDevices() { - constexpr int VID = 0x2e8au; - constexpr int PID = 0x000au; + constexpr int VID = 0x2e8au; + constexpr int PID = 0x000au; - devices = deviceManager.getDevices(VID, PID); - for (auto &device : devices) { - auto id = device->getId().value(); - if (!colorMap.contains(id)) { - ImPlot::PushColormap(ImPlotColormap_Dark); - auto c = ImPlot::GetColormapColor((colorMap.size() % 7) + 1); - colorMap[id] = std::array{c.x, c.y, c.z}; - ImPlot::PopColormap(); + devices = deviceManager.getDevices(VID, PID); + for (auto &device : devices) { + auto metaDataCb = [&](auto const &msg) { + if (std::holds_alternative(msg)) { + parseDeviceMetaData(std::get(msg), device); + } + }; + auto id = device->getId().value(); + auto sampleRate = static_cast(id.sampleRate); + device->setTimeScale(static_cast(1 / sampleRate)); + if (!colorMap.contains(id)) { + ImPlot::PushColormap(ImPlotColormap_Dark); + auto c = ImPlot::GetColormapColor((colorMap.size() % 7) + 1); + colorMap[id] = std::array{c.x, c.y, c.z}; + ImPlot::PopColormap(); + } + auto &color = colorMap[id]; + device->send( + Omniscope::SetRgb{static_cast(color[0] * 255), + static_cast(color[1] * 255), + static_cast(color[2] * 255)}); + // set Callback for MetaData + device->setMessageCallback(metaDataCb); + device->send(Omniscope::GetMetaData{}); } - auto &color = colorMap[id]; - device->send(Omniscope::SetRgb{static_cast(color[0] * 255), - static_cast(color[1] * 255), - static_cast(color[2] * 255)}); - } } -void devicesList() { - auto doDevice = [&](auto &device, auto msg) { - auto &color = colorMap[device->getId().value()]; - if (ImGui::ColorEdit3( - fmt::format("{:<32}", - fmt::format("{}-{}", device->getId().value().type, - device->getId().value().serial)) - .c_str(), - color.data(), - ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoPicker | - ImGuiColorEditFlags_NoTooltip)) { - device->send( - Omniscope::SetRgb{static_cast(color[0] * 255), - static_cast(color[1] * 255), - static_cast(color[2] * 255)}); - } - ImGui::SameLine(); - ImGui::TextUnformatted(fmt::format("HW: v{}.{}.{} SW: v{}.{}.{} ", - device->getId().value().hwVersion.major, - device->getId().value().hwVersion.minor, - device->getId().value().hwVersion.patch, - device->getId().value().swVersion.major, - device->getId().value().swVersion.minor, - device->getId().value().swVersion.patch) - .c_str()); - ImGui::SameLine(); - if (device->isRunning()) - ImGui::TextUnformatted(fmt::format("{}", msg).c_str()); - else - ImGui::TextUnformatted("Error"); - }; +void devicesList(bool const &flagPaused) { + auto doDevice = [&](auto &device, auto msg) { + auto &color = colorMap[device->getId().value()]; + if (ImGui::ColorEdit3( + fmt::format("{:<32}", + fmt::format("{}-{}", device->getId().value().type, + device->getId().value().serial)) + .c_str(), + color.data(), + ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoPicker | + ImGuiColorEditFlags_NoTooltip)) { + device->send( + Omniscope::SetRgb{static_cast(color[0] * 255), + static_cast(color[1] * 255), + static_cast(color[2] * 255)}); + } + ImGui::SameLine(); + ImGui::TextUnformatted( + fmt::format("HW: v{}.{}.{} SW: v{}.{}.{} ", + device->getId().value().hwVersion.major, + device->getId().value().hwVersion.minor, + device->getId().value().hwVersion.patch, + device->getId().value().swVersion.major, + device->getId().value().swVersion.minor, + device->getId().value().swVersion.patch) + .c_str()); + ImGui::SameLine(); + if (device->isRunning()) + ImGui::TextUnformatted(fmt::format("{}", msg).c_str()); + else + ImGui::TextUnformatted("Error"); + }; - if (sampler.has_value()) - for (auto &device : sampler->sampleDevices) - doDevice(device.first, appLanguage[Key::Measurement]); - else - for (auto &device : devices) - doDevice(device, appLanguage[Key::Ready]); + if (sampler.has_value()) + for (auto &device : sampler->sampleDevices) { + if (!flagPaused) { + doDevice(device.first, appLanguage[Key::Measurement]); + } else { + doDevice(device.first, appLanguage[Key::Stop]); + } + } + else + for (auto &device : devices) doDevice(device, appLanguage[Key::Ready]); } void load_files(decltype(captureData) &loadedFiles, @@ -253,6 +348,7 @@ void rstSettings(const decltype(captureData) &loadedFiles) { devices.clear(); savedFileNames.clear(); deviceManager.clearDevices(); + plotAxes.clear(); // erase all elements excpet loadedFiles for (auto it = captureData.begin(); it != captureData.end();) { if (!loadedFiles.contains(it->first)) diff --git a/src/handler.hpp b/src/handler.hpp index a3658383..9d0987d3 100644 --- a/src/handler.hpp +++ b/src/handler.hpp @@ -7,6 +7,18 @@ #include #include #include +#include + +struct AxisInfo { + std::pair>&> data; + std::pair egu; + std::string timebase; + + AxisInfo( + std::pair>&> data_, + std::pair egu_, std::string timebase_) + : data{data_}, egu{egu_}, timebase{timebase_} {} +}; // global variables inline OmniscopeDeviceManager deviceManager{}; @@ -16,9 +28,12 @@ inline std::set savedFileNames; // unique and ordered filenames inline std::optional sampler{}; inline std::map>> captureData; -void addPlots(const char *, std::function); + +inline std::vector plotAxes; +void addPlots(const char *, const bool, std::function); +void parseDeviceMetaData(Omniscope::MetaData, std::shared_ptr&); void initDevices(); -void devicesList(); +void devicesList(bool const& flagPaused); void load_files(decltype(captureData) &, std::map &, bool &); void set_config(const std::string &); diff --git a/src/languages.hpp b/src/languages.hpp index ccc4449c..2d1fbb8a 100644 --- a/src/languages.hpp +++ b/src/languages.hpp @@ -77,6 +77,10 @@ enum class Key { Attitude, German, Ready, + x_label, + y_label, + Voltage, + Time, FontSize, SettingsText, Saving, @@ -159,6 +163,10 @@ inline const std::map englishLan{ {Key::Attitude, "Attitude"}, {Key::German, "German"}, {Key::Ready, "Ready"}, + {Key::x_label, "y [ADC counts]"}, + {Key::y_label, "x [data points]"}, + {Key::Voltage, "Voltage"}, + {Key::Time, "Time"}, {Key::FontSize, "Fontsize"}, {Key::SettingsText, "Set your personal settings for the software"}, {Key::Saving, "saving ..."}, @@ -242,6 +250,10 @@ inline const std::map germanLan{ {Key::Attitude, "Einstellung"}, {Key::German, "Deutsch"}, {Key::Ready, "Bereit"}, + {Key::x_label, "y [ADC Zähler]"}, + {Key::y_label, "x [Datenpunkte]"}, + {Key::Voltage, "Spannung"}, + {Key::Time, "Zeit"}, {Key::FontSize, "Schriftgröße"}, {Key::SettingsText, "Legen sie hier ihre persönlichen Einstellungen fest"}, {Key::Saving, "speichern ..."}, @@ -252,4 +264,4 @@ inline const std::map germanLan{ inline auto appLanguage = englishLan; namespace fs = std::filesystem; -#endif \ No newline at end of file +#endif diff --git a/src/main.cpp b/src/main.cpp index 9aea268b..aee0f868 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,10 @@ +#include +#include +#include + #include "popups.hpp" #include "settingspopup.hpp" #include "style.hpp" -#include int main() { const std::string configpath = "config/config.json"; @@ -36,7 +39,7 @@ int main() { ImGuiWindowFlags_NoTitleBar); if (Development && ImGui::Button("Development")) - ImGui::OpenPopup("Development Colors"); + ImGui::OpenPopup("Development Colors"); // Popup-Window content if (ImGui::BeginPopup("Development Colors")) { @@ -88,34 +91,47 @@ int main() { // ############################ addPlots("Recording the data", ...) ImGui::Dummy({0.f, windowSize.y * .01f}); PushPlotRegionColors(); - ImGui::PushStyleVar(ImGuiStyleVar_ChildBorderSize, windowSize.x * .009f); + ImGui::PushStyleVar(ImGuiStyleVar_ChildBorderSize, + windowSize.x * .009f); ImGui::BeginChild("Record Data", {0.f, windowSize.y * 0.62f}, - ImGuiChildFlags_Border); + ImGuiChildFlags_Border); - addPlots("Recording the data", [flagPaused](double x_max) { - if (!flagPaused) { - ImPlot::SetupAxes("x [Data points]", "y [ADC Value]", - ImPlotAxisFlags_AutoFit, ImPlotAxisFlags_AutoFit); - ImPlot::SetupAxisLimits(ImAxis_X1, x_max - 7500, x_max + 7500, - ImGuiCond_Always); - } else { - ImPlot::SetupAxes("x [Seconds]", "y [Volts]"); - ImPlot::SetupAxesLimits(0, 10, -10, 200); + // Axes 1 to 3 + // Check if time base for axes are same + // check if egu and timescale for plot are same + // error if third device is added + addPlots("Recording the data", flagPaused, [&flagPaused](double x_max, std::string yLabel, ImAxis_ axis, double yMin, double yMax) { + ImPlot::SetupLegend(ImPlotLocation_NorthEast | + ImPlotLegendFlags_Outside); + auto auxFlagsMeasuring = + ImPlotAxisFlags_AutoFit | ImPlotAxisFlags_NoGridLines; + auto auxFlagsPaused = ImPlotAxisFlags_NoGridLines; ImPlot::SetupAxisTicks(ImAxis_Y1, -10, 200, 22, nullptr, true); - ImPlot::SetupLegend(ImPlotLocation_NorthEast); - } + + if(!flagPaused){ + ImPlot::SetupAxis(axis, yLabel.c_str(), ImPlotAxisFlags_AutoFit); + ImPlot::SetupAxis(ImAxis_X1, "time [s]", ImPlotAxisFlags_AutoFit); + ImPlot::SetupAxisLimits(axis, yMin - 2, yMax + 2, ImGuiCond_Always); + ImPlot::SetupAxisLimits(ImAxis_X1, x_max - 1, x_max + 9, ImGuiCond_Always); + + }else{ + ImPlot::SetupAxis(ImAxis_X1, "time [s]"); + ImPlot::SetupAxis(axis, yLabel.c_str()); + ImPlot::SetupAxisLimits(ImAxis_X1, 0, 10); + ImPlot::SetupAxisLimits(axis, yMin - 2, yMax + 2); + } }); - ImGui::EndChild(); // end child Record Data + ImGui::EndChild(); // end child Record Data ImGui::PopStyleVar(); PopPlotRegionColors(); // ############################ Devicelist SetDeviceMenuStyle(); - ImGui::Dummy({0.f, windowSize.y * .01f}); + ImGui::Dummy({0.f, windowSize.y * .01f}); ImGui::BeginChild("Devicelist"); ImGui::Dummy({windowSize.x * .36f, 0.f}); ImGui::SameLine(); ImGui::Text(appLanguage[Key::Devices_found]); - devicesList(); + devicesList(flagPaused); if (!loadedFiles.empty()) { // if devices were successfully loaded from file static std::map loadedFilesChkBxs; for (auto it = loadedFiles.begin(); it != loadedFiles.end();) { @@ -143,11 +159,11 @@ int main() { loadedFilenames.erase(it->first); loadedFilesChkBxs[it->first].b = false; it = loadedFiles.erase(it); - } else + } else it++; ImGui::PopID(); } // end of for-loop - } + } ImGui::EndChild(); // end child "Devicelist" ImGui::EndChild(); // end child "Right Side" ImGui::End(); @@ -158,4 +174,4 @@ int main() { while (window.run(render)) ; return 0; -} \ No newline at end of file +}