From 623488236b137753addf92de1bdcef45149c55a7 Mon Sep 17 00:00:00 2001 From: noy zini Date: Wed, 25 Dec 2024 10:56:49 +0200 Subject: [PATCH] add dds config tool --- common/CMakeLists.txt | 2 + common/dds-model.cpp | 321 ++++++++++++++++++ common/dds-model.h | 66 ++++ common/device-model.cpp | 18 +- common/device-model.h | 2 + .../include/rsutils/type}/eth-config-header.h | 0 .../include/rsutils/type}/eth-config-v3.h | 0 .../include/rsutils/type}/eth-config.cpp | 0 .../include/rsutils/type}/eth-config.h | 0 tools/dds/dds-config/CMakeLists.txt | 1 + tools/dds/dds-config/rs-dds-config.cpp | 2 +- tools/depth-quality/CMakeLists.txt | 2 + tools/realsense-viewer/CMakeLists.txt | 2 + 13 files changed, 414 insertions(+), 2 deletions(-) create mode 100644 common/dds-model.cpp create mode 100644 common/dds-model.h rename {tools/dds/dds-config => third-party/rsutils/include/rsutils/type}/eth-config-header.h (100%) rename {tools/dds/dds-config => third-party/rsutils/include/rsutils/type}/eth-config-v3.h (100%) rename {tools/dds/dds-config => third-party/rsutils/include/rsutils/type}/eth-config.cpp (100%) rename {tools/dds/dds-config => third-party/rsutils/include/rsutils/type}/eth-config.h (100%) diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index b46dd01701..18648fa655 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -57,6 +57,8 @@ set(COMMON_SRC "${CMAKE_CURRENT_LIST_DIR}/stream-model.cpp" "${CMAKE_CURRENT_LIST_DIR}/post-processing-filters.h" "${CMAKE_CURRENT_LIST_DIR}/post-processing-filters.cpp" + "${CMAKE_CURRENT_LIST_DIR}/dds-model.h" + "${CMAKE_CURRENT_LIST_DIR}/dds-model.cpp" ) set(SW_UPDATE_FILES diff --git a/common/dds-model.cpp b/common/dds-model.cpp new file mode 100644 index 0000000000..2de05025fa --- /dev/null +++ b/common/dds-model.cpp @@ -0,0 +1,321 @@ +#include "dds-model.h" +// License: Apache 2.0. See LICENSE file in root directory. +// Copyright(c) 2024 Intel Corporation. All Rights Reserved. + +#include "device-model.h" +#include "ux-window.h" +#include +#include +#include + +#include +#include + +using namespace rs2; +using rsutils::json; + +dds_model::dds_model(rs2::device dev) + : _device(dev), _window_open(false) +{ + if (supports_DDS()) { + _defult_config = get_eth_config(_device, DEFULT_VALUES); + _current_config = get_eth_config(_device, ACTUAL_VALUES); + _changed_config = _current_config; + } + +} + +eth_config dds_model::get_eth_config(rs2::debug_protocol dev, bool defult_val) +{ + auto cmd = dev.build_command(GET_ETH_CONFIG, defult_val ? 0 : 1); + auto data = dev.send_and_receive_raw_data(cmd); + int32_t const& code = *reinterpret_cast(data.data()); + data.erase(data.begin(), data.begin() + sizeof(code)); + return eth_config(data); +} + +void rs2::dds_model::set_eth_config(eth_config &new_config , std::string& error_message) +{ + rs2::debug_protocol hwm(_device); + auto cmd = hwm.build_command(SET_ETH_CONFIG, 0, 0, 0, 0, new_config.build_command()); + auto data = hwm.send_and_receive_raw_data(cmd); + int32_t const& code = *reinterpret_cast(data.data()); + if (data.size() != sizeof(code)) { + error_message = rsutils::string::from()<< "Failed to change: bad response size " << data.size() << ' '<< rsutils::string::hexdump(data.data(), data.size()); + close_window(); + } + if (code != SET_ETH_CONFIG) { + error_message = rsutils::string::from() << "Failed to change: bad response " << code; + close_window(); + } + if (!_no_reset) + { + close_window(); + _device.hardware_reset(); + } +} + +void rs2::dds_model::enable_dds(std::string& error_message) +{ + if (_device.get_type() == "DDS") + { + auto const filename + = rsutils::os::get_special_folder(rsutils::os::special_folder::app_data) + RS2_CONFIG_FILENAME; + auto config = rsutils::json_config::load_from_file(filename); + + bool enabled; + if (!config.nested("context", "dds", "enabled").get_ex(enabled)) + { + config["context"]["dds"]["enabled"] = true; + try + { + std::ofstream out(filename); + out << std::setw(2) << config; + out.close(); + } + catch (std::exception const& e) + { + error_message = e.what(); + close_window(); + } + } + } +} + +priority rs2::dds_model::classifyPriority(link_priority &pr) +{ + if (pr == link_priority::usb_only || pr == link_priority::usb_first) + { + return priority::USB_FIRST; + } + else if (pr == link_priority::eth_first || pr == link_priority::eth_only) + { + return priority::ETH_FIRST; + } + return priority::DYNAMIC; +} + +bool dds_model::supports_DDS() +{ + auto dev = debug_protocol(_device); + auto cmd = dev.build_command(GET_ETH_CONFIG , ACTUAL_VALUES ); + auto data = dev.send_and_receive_raw_data(cmd); + int32_t const& code = *reinterpret_cast(data.data()); + if (code != GET_ETH_CONFIG) + return false; + return true; +} + +void rs2::dds_model::ipInputText(std::string label ,rsutils::type::ip_address &ip) +{ + char buffer[16]; + std::string ip_str = ip.to_string(); + std::snprintf(buffer, sizeof(buffer), "%s", ip_str.c_str()); + std::string label_name = "##" + label; + + if (ImGui::InputText(label_name.c_str(), buffer, sizeof(buffer))) { + std::string new_ip_str(buffer); + if (rsutils::type::ip_address(new_ip_str).is_valid()) { + ip = rsutils::type::ip_address(new_ip_str); + } + else { + std::snprintf(buffer, sizeof(buffer), "%s", ip.to_string().c_str()); + } + } +} + +void dds_model::render_dds_config_window(ux_window& window , std::string& error_message) +{ + if (_window_open) + { + const auto window_name = "DDS Configuration"; + + // Calculate window position and size + const float w = 620; + const float h = 500; + const float x0 = std::max(window.width() - w, 0.f) / 2; + const float y0 = std::max(window.height() - h, 0.f) / 2; + ImGui::SetNextWindowPos({ x0, y0 }); + ImGui::SetNextWindowSize({ w, h }); + + auto flags = ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar | + ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings; + + ImGui::PushStyleColor(ImGuiCol_PopupBg, sensor_bg); + ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, light_grey); + ImGui::PushStyleColor(ImGuiCol_Text, light_grey); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(5, 5)); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 1); + ImGui::PushStyleColor(ImGuiCol_Button, button_color); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, button_color + 0.1f); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, button_color + 0.1f); + + + ImGui::Begin(window_name, &_window_open, flags); + + // Title + const char* title_message = window_name; + ImVec2 title_size = ImGui::CalcTextSize(title_message); + float title_x = (w - title_size.x-10) / 2.0f; + ImGui::SetCursorPos({ title_x, 10.0f }); + ImGui::PushFont(window.get_large_font()); + ImGui::PushStyleColor(ImGuiCol_Text, white); + ImGui::Text("%s", title_message); + ImGui::PopStyleColor(); + ImGui::PopFont(); + ImGui::Separator(); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 15); + + // Version Display + ImGui::Text("Version: %s" , RS2_API_FULL_VERSION_STR); + + // Main Scrollable Section + ImGui::BeginChild("MainContent", ImVec2(w-10, h - 120), true); + ImGui::PushItemWidth(150.0f); + + // Connection Priority Section + priority connection_priority = classifyPriority(_changed_config.link.priority); + if (ImGui::CollapsingHeader("Connection Priority")) { + ImGui::Text("Select connection priority:"); + ImGui::RadioButton("Ethernet First", reinterpret_cast(&connection_priority), 0); + if (static_cast(connection_priority) == 0) { + ImGui::SameLine(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 50); + ImGui::Text("Link Timeout (seconds)"); + ImGui::SameLine(); + int tempTimeout = static_cast(_changed_config.link.timeout); + if (ImGui::InputInt("##Link Timeout (seconds)", &tempTimeout)) { + _changed_config.link.timeout = static_cast(std::max(0, tempTimeout)); + } + } + ImGui::RadioButton("USB First", reinterpret_cast(&connection_priority), 1); + ImGui::RadioButton("Dynamic Priority", reinterpret_cast(&connection_priority), 2); + switch (connection_priority) { + case ETH_FIRST: + _changed_config.link.priority = link_priority::eth_first; + break; + case USB_FIRST: + _changed_config.link.priority = link_priority::usb_first; + break; + case DYNAMIC: + _changed_config.link.priority = _current_config.link.speed ? link_priority::dynamic_eth_first : link_priority::dynamic_usb_first; + break; + } + } + + // Network Configuration Section + if (ImGui::CollapsingHeader("Network Configuration")) { + ImGui::Checkbox("Enable DHCP", &_changed_config.dhcp.on); + if (!_changed_config.dhcp.on) { + ImGui::Text("Static IP Address"); + ImGui::SameLine(); + float textbox_align = ImGui::GetCursorPosX(); + ipInputText("Static IP Address", _changed_config.configured.ip); + ImGui::Text("Subnet Mask"); + ImGui::SameLine(); + ImGui::SetCursorPosX(textbox_align); + bool maskStylePushed = false; + ipInputText("Subnet Mask", _changed_config.configured.netmask); + ImGui::Text("Gateway"); + ImGui::SameLine(); + ImGui::SetCursorPosX(textbox_align); + ipInputText("Gateway", _changed_config.configured.gateway); + } + ImGui::Text("DHCP Timeout (seconds)"); + ImGui::SameLine(); + int tempTimeout = static_cast(_changed_config.dhcp.timeout); + if (ImGui::InputInt("##DHCP Timeout (seconds)", &tempTimeout)) { + _changed_config.dhcp.timeout = static_cast(std::max(0, tempTimeout)); + } + } + + ImGui::Text("Domain ID"); + ImGui::SameLine(); + if (ImGui::InputInt("##Domain ID", &_changed_config.dds.domain_id)) { + if (_changed_config.dds.domain_id < 0) + _changed_config.dds.domain_id = 0; + else if(_changed_config.dds.domain_id > 232) + _changed_config.dds.domain_id = 232; + } + ImGui::Checkbox("No Reset after changes", &_no_reset); + + if (ImGui::Checkbox("Set to defult values", &_set_defult)) { + if (_set_defult) + _changed_config = _defult_config; + else + _changed_config = _current_config; + } + + ImGui::PopItemWidth(); + ImGui::EndChild(); + + //window buttons + float button_width = 100.0f; + float spacing = 10.0f; + float total_buttons_width = button_width * 4 + spacing * 2; + float start_x = (w - total_buttons_width) / 2.0f; + bool hasChanges = (_changed_config != _current_config); + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 8); + + ImGui::SetCursorPosX(start_x); + + if (ImGui::Button("Cancel", ImVec2(button_width, 25))) { + close_window(); + } + if (ImGui::IsItemHovered()) { + window.link_hovered(); + ImGui::SetTooltip("%s", "Close without saving any changes"); + } + ImGui::SameLine(); + if (ImGui::Button("Factory Reset", ImVec2(button_width, 25))) { + enable_dds(error_message); + set_eth_config(_defult_config , error_message); + close_window(); + } + if (ImGui::IsItemHovered()) { + window.link_hovered(); + ImGui::SetTooltip("%s", "Reset settings back to defult values"); + } + ImGui::SameLine(); + std::string revert_label = "Revert changes"; + if (ImGui::ButtonEx(revert_label.c_str(), ImVec2(button_width, 25), hasChanges ? 0 : ImGuiButtonFlags_Disabled)) { + _changed_config = _current_config; + } + if (ImGui::IsItemHovered()) { + window.link_hovered(); + ImGui::SetTooltip("%s", "Revert to current configuration values"); + } + ImGui::SameLine(); + std::string apply_label = "Apply"; + if (ImGui::ButtonEx(apply_label.c_str(), ImVec2(button_width, 25), hasChanges ? 0 : ImGuiButtonFlags_Disabled)) { + enable_dds(error_message); + set_eth_config(_changed_config, error_message); + close_window(); + } + if (ImGui::IsItemHovered()) { + window.link_hovered(); + ImGui::SetTooltip("%s", "Apply changes"); + } + if (ImGui::BeginPopupModal("No Changes Needed", NULL, ImGuiWindowFlags_AlwaysAutoResize)) { + ImGui::Text("No changes were made to the configuration."); + + if (ImGui::Button("OK", ImVec2(100, 25))) { + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + ImGui::End(); + ImGui::PopStyleColor(6); + ImGui::PopStyleVar(2); + } + +} + +void rs2::dds_model::open_dds_tool_window() +{ + _current_config = get_eth_config(_device, ACTUAL_VALUES); + _changed_config = _current_config; + _window_open = true; +} + diff --git a/common/dds-model.h b/common/dds-model.h new file mode 100644 index 0000000000..b434221a5c --- /dev/null +++ b/common/dds-model.h @@ -0,0 +1,66 @@ +// License: Apache 2.0. See LICENSE file in root directory. +// Copyright(c) 2024 Intel Corporation. All Rights Reserved. +#pragma once + +#include +#include +#include +#include +#include +#include +#include "../third-party/rsutils/include/rsutils/type/eth-config.h" +#include +#include + +uint32_t const GET_ETH_CONFIG = 0xBB; +uint32_t const SET_ETH_CONFIG = 0xBA; + +bool const ACTUAL_VALUES = 0; +bool const DEFULT_VALUES = 1; + +enum priority { + ETH_FIRST, + USB_FIRST, + DYNAMIC +}; + +namespace rs2 +{ + class ux_window; + + class dds_model + { + + public: + dds_model(rs2::device dev); + + bool supports_DDS(); + + void render_dds_config_window(ux_window& window, std::string& error_message); + + void open_dds_tool_window(); + + void close_window() { _window_open = false; } + + eth_config get_eth_config(rs2::debug_protocol dev, bool defult_val); + + void set_eth_config(eth_config &new_config , std::string& error_message); + + void enable_dds(std::string& error_message); + + + private: + rs2::device _device; + + eth_config _defult_config; + eth_config _current_config; + eth_config _changed_config; + + bool _window_open; + bool _no_reset = false; + bool _set_defult = false; + + void ipInputText(std::string label, rsutils::type::ip_address &ip); + priority classifyPriority(link_priority &pr); + }; +} diff --git a/common/device-model.cpp b/common/device-model.cpp index 72d37d2bb6..75876c01e3 100644 --- a/common/device-model.cpp +++ b/common/device-model.cpp @@ -370,7 +370,8 @@ namespace rs2 _detected_objects(std::make_shared< atomic_objects_in_frame >()), _updates(viewer.updates), _updates_profile(std::make_shared()), - _allow_remove(remove) + _allow_remove(remove), + _dds_model(dev) { auto name = get_device_name(dev); id = rsutils::string::from() << name.first << ", " << name.second; @@ -1407,6 +1408,20 @@ namespace rs2 } } } + ImGuiSelectableFlags is_streaming_flag = (is_streaming) ? ImGuiSelectableFlags_Disabled : 0; + if (_dds_model.supports_DDS()) { + if (ImGui::Selectable("DDS Configuration",false, is_streaming_flag)) + { + _dds_model.open_dds_tool_window(); + } + if (ImGui::IsItemHovered()) + { + std::string tooltip = rsutils::string::from() + << "Change the configuration of Ethernet based devices" + << (is_streaming ? " (Disabled while streaming)" : ""); + ImGui::SetTooltip("%s", tooltip.c_str()); + } + } } draw_device_panel_auto_calib(viewer, something_to_show, error_message); @@ -1429,6 +1444,7 @@ namespace rs2 } _calib_model.update(window, error_message); + _dds_model.render_dds_config_window(window , error_message); //////////////////////////////////////// diff --git a/common/device-model.h b/common/device-model.h index 11401f8267..d988f83bdd 100644 --- a/common/device-model.h +++ b/common/device-model.h @@ -11,6 +11,7 @@ #include "updates-model.h" #include "calibration-model.h" #include "objects-in-frame.h" +#include "dds-model.h" ImVec4 from_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a, bool consistent_color = false); ImVec4 operator+(const ImVec4& c, float v); @@ -451,6 +452,7 @@ namespace rs2 std::shared_ptr _updates; std::shared_ptr_updates_profile; calibration_model _calib_model; + dds_model _dds_model; }; std::pair get_device_name(const device& dev); diff --git a/tools/dds/dds-config/eth-config-header.h b/third-party/rsutils/include/rsutils/type/eth-config-header.h similarity index 100% rename from tools/dds/dds-config/eth-config-header.h rename to third-party/rsutils/include/rsutils/type/eth-config-header.h diff --git a/tools/dds/dds-config/eth-config-v3.h b/third-party/rsutils/include/rsutils/type/eth-config-v3.h similarity index 100% rename from tools/dds/dds-config/eth-config-v3.h rename to third-party/rsutils/include/rsutils/type/eth-config-v3.h diff --git a/tools/dds/dds-config/eth-config.cpp b/third-party/rsutils/include/rsutils/type/eth-config.cpp similarity index 100% rename from tools/dds/dds-config/eth-config.cpp rename to third-party/rsutils/include/rsutils/type/eth-config.cpp diff --git a/tools/dds/dds-config/eth-config.h b/third-party/rsutils/include/rsutils/type/eth-config.h similarity index 100% rename from tools/dds/dds-config/eth-config.h rename to third-party/rsutils/include/rsutils/type/eth-config.h diff --git a/tools/dds/dds-config/CMakeLists.txt b/tools/dds/dds-config/CMakeLists.txt index 805d2e3ef9..f97ef91457 100644 --- a/tools/dds/dds-config/CMakeLists.txt +++ b/tools/dds/dds-config/CMakeLists.txt @@ -9,6 +9,7 @@ file( GLOB_RECURSE RS_DDS_CONFIG_SOURCE_FILES LIST_DIRECTORIES false RELATIVE ${PROJECT_SOURCE_DIR} "${CMAKE_CURRENT_LIST_DIR}/*" + "${PROJECT_SOURCE_DIR}/../../../third-party/rsutils/include/rsutils/type/*" ) target_sources( ${PROJECT_NAME} PRIVATE ${RS_DDS_CONFIG_SOURCE_FILES} ) diff --git a/tools/dds/dds-config/rs-dds-config.cpp b/tools/dds/dds-config/rs-dds-config.cpp index 22c898bd4c..53bee0aa89 100644 --- a/tools/dds/dds-config/rs-dds-config.cpp +++ b/tools/dds/dds-config/rs-dds-config.cpp @@ -1,7 +1,7 @@ // License: Apache 2.0. See LICENSE file in root directory. // Copyright(c) 2024 Intel Corporation. All Rights Reserved. -#include "eth-config.h" +#include #include diff --git a/tools/depth-quality/CMakeLists.txt b/tools/depth-quality/CMakeLists.txt index 82c9678d41..8140b1f00b 100644 --- a/tools/depth-quality/CMakeLists.txt +++ b/tools/depth-quality/CMakeLists.txt @@ -42,6 +42,8 @@ if(BUILD_GRAPHICAL_EXAMPLES) ../../third-party/glad/glad.c ../../third-party/tinyfiledialogs/tinyfiledialogs.c ../../third-party/tinyfiledialogs/tinyfiledialogs.h + ../../third-party/rsutils/include/rsutils/type/eth-config.h + ../../third-party/rsutils/include/rsutils/type/eth-config.cpp ) if(WIN32) diff --git a/tools/realsense-viewer/CMakeLists.txt b/tools/realsense-viewer/CMakeLists.txt index 7add228b9c..3812dc4aa3 100644 --- a/tools/realsense-viewer/CMakeLists.txt +++ b/tools/realsense-viewer/CMakeLists.txt @@ -51,6 +51,8 @@ if(BUILD_GRAPHICAL_EXAMPLES) ../../common/rs-config.cpp ../../common/os.h ../../common/os.cpp + ../../third-party/rsutils/include/rsutils/type/eth-config.h + ../../third-party/rsutils/include/rsutils/type/eth-config.cpp ) SET(DELAYED