From ef56139a6ae7566e985b6b4ca7e9acf9105fdf40 Mon Sep 17 00:00:00 2001 From: Eran Date: Mon, 25 Dec 2023 11:44:15 +0200 Subject: [PATCH 01/12] add rsutils::json::nested::string_ref_or_empty(); rename default_value<>() --- third-party/realdds/src/dds-device-impl.cpp | 2 +- third-party/rsutils/include/rsutils/json.h | 10 ++++++++-- third-party/rsutils/src/json.cpp | 2 ++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/third-party/realdds/src/dds-device-impl.cpp b/third-party/realdds/src/dds-device-impl.cpp index 157681d0c5..9222990a66 100644 --- a/third-party/realdds/src/dds-device-impl.cpp +++ b/third-party/realdds/src/dds-device-impl.cpp @@ -137,7 +137,7 @@ dds_device::impl::impl( std::shared_ptr< dds_participant > const & participant, , _subscriber( std::make_shared< dds_subscriber >( participant ) ) , _device_settings( device_settings( participant ) ) , _reply_timeout_ms( - rsutils::json::nested( _device_settings, "control", "reply-timeout-ms" ).value< size_t >( 2000 ) ) + rsutils::json::nested( _device_settings, "control", "reply-timeout-ms" ).default_value< size_t >( 2000 ) ) { create_notifications_reader(); create_control_writer(); diff --git a/third-party/rsutils/include/rsutils/json.h b/third-party/rsutils/include/rsutils/json.h index c33c0b1e43..1a3c3e6300 100644 --- a/third-party/rsutils/include/rsutils/json.h +++ b/third-party/rsutils/include/rsutils/json.h @@ -11,6 +11,8 @@ namespace json { extern nlohmann::json const null_json; +extern nlohmann::json const empty_json_string; +extern nlohmann::json const empty_json_object; // Returns true if the json has a certain key. @@ -168,11 +170,15 @@ class nested bool is_string() const { return exists() && _pj->is_string(); } // Get the JSON as a value - template< class T > T value() { return json::value< T >( get() ); } + template< class T > T value() const { return json::value< T >( get() ); } // Get the JSON as a value, or a default if not there - template < class T > T value( T const & default_value ) { return json::value< T >( get(), default_value ); } + template < class T > T default_value( T const & default_value ) const { return json::value< T >( get(), default_value ); } + // Get the object, with a default being an empty one + nlohmann::json const & default_object() const { return is_object() ? *_pj : empty_json_object; } // Get a JSON string by reference (zero copy); it must be a string or it'll throw inline std::string const & string_ref() const { return json::string_ref( get() ); } + // Get a JSON string by reference (zero copy); does not throw + inline std::string const & string_ref_or_empty() const { return json::string_ref( exists() ? *_pj : empty_json_string ); } }; diff --git a/third-party/rsutils/src/json.cpp b/third-party/rsutils/src/json.cpp index 6f6d18a1b2..5b55788bf2 100644 --- a/third-party/rsutils/src/json.cpp +++ b/third-party/rsutils/src/json.cpp @@ -9,6 +9,8 @@ namespace json { nlohmann::json const null_json = {}; +nlohmann::json const empty_json_string = nlohmann::json::value_type( nlohmann::json::value_t::string ); +nlohmann::json const empty_json_object = nlohmann::json::object(); void patch( nlohmann::json & j, nlohmann::json const & patches, std::string const & what ) From fb31ce62a870d4b8db3c7c640743f73563d32ad4 Mon Sep 17 00:00:00 2001 From: Eran Date: Mon, 25 Dec 2023 12:45:24 +0200 Subject: [PATCH 02/12] add json::nested.find( ... ) --- third-party/realdds/src/dds-device-impl.cpp | 6 +++--- third-party/rsutils/include/rsutils/json.h | 10 ++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/third-party/realdds/src/dds-device-impl.cpp b/third-party/realdds/src/dds-device-impl.cpp index 9222990a66..f4e4b565ea 100644 --- a/third-party/realdds/src/dds-device-impl.cpp +++ b/third-party/realdds/src/dds-device-impl.cpp @@ -253,8 +253,8 @@ void dds_device::impl::on_option_value( nlohmann::json const & j, eprosima::fast // Find the relevant (stream) options to update dds_options const * options = &_options; - std::string stream_name; // default = empty = device option - if( rsutils::json::get_ex( control, stream_name_key, &stream_name ) && ! stream_name.empty() ) + std::string const & stream_name = control.find( stream_name_key ).string_ref_or_empty(); // default = empty = device option + if( ! stream_name.empty() ) { auto stream_it = _streams.find( stream_name ); if( stream_it == _streams.end() ) @@ -291,7 +291,7 @@ void dds_device::impl::on_option_value( nlohmann::json const & j, eprosima::fast return; } - rsutils::json::nested option_name_j( control, option_name_key ); + auto option_name_j = control.find( option_name_key ); if( ! option_name_j.exists() ) throw std::runtime_error( "missing option-name" ); diff --git a/third-party/rsutils/include/rsutils/json.h b/third-party/rsutils/include/rsutils/json.h index 1a3c3e6300..35d73a59ee 100644 --- a/third-party/rsutils/include/rsutils/json.h +++ b/third-party/rsutils/include/rsutils/json.h @@ -152,6 +152,8 @@ class nested nlohmann::json const * _pj; public: + nested() : _pj( nullptr ) {} + template< typename... Rest > nested( nlohmann::json const & j, Rest... rest ) : _pj( _nested( j, std::forward< Rest >( rest )... ) ) @@ -169,6 +171,14 @@ class nested bool is_object() const { return exists() && _pj->is_object(); } bool is_string() const { return exists() && _pj->is_string(); } + // Dig deeper + template< typename... Rest > + inline nested find( Rest... rest ) const + { + return _pj ? nested( *_pj, std::forward< Rest >( rest )... ) : nested(); + } + inline nested operator[]( std::string const & key ) const { return find( key ); } + // Get the JSON as a value template< class T > T value() const { return json::value< T >( get() ); } // Get the JSON as a value, or a default if not there From 5258aa4ef11da4a66a5f350fb7203e4f43614155 Mon Sep 17 00:00:00 2001 From: Eran Date: Mon, 25 Dec 2023 12:04:09 +0200 Subject: [PATCH 03/12] change realdds::topics::device_info to be json-based --- src/dds/rs-dds-device-info.cpp | 12 +--- src/dds/rs-dds-device-proxy.cpp | 23 ++++-- src/dds/rs-dds-sensor-proxy.cpp | 2 +- src/dds/rsdds-device-factory.cpp | 22 ++++-- .../include/realdds/topics/device-info-msg.h | 24 ++++--- third-party/realdds/py/pyrealdds.cpp | 23 ++---- .../realdds/src/dds-device-broadcaster.cpp | 2 +- third-party/realdds/src/dds-device-impl.cpp | 6 +- third-party/realdds/src/dds-device-server.cpp | 2 +- third-party/realdds/src/dds-device.cpp | 2 +- .../realdds/src/topics/device-info-msg.cpp | 71 +++++++++++++------ tools/dds/dds-adapter/rs-dds-adapter.cpp | 36 +++++++--- unit-tests/dds/d405.py | 11 +-- unit-tests/dds/d435i.py | 11 +-- unit-tests/dds/d455.py | 17 ++--- unit-tests/dds/formats-conversion-server.py | 9 ++- .../dds/test-librs-formats-conversion.py | 2 +- unit-tests/dds/watcher-server.py | 9 ++- 18 files changed, 170 insertions(+), 114 deletions(-) diff --git a/src/dds/rs-dds-device-info.cpp b/src/dds/rs-dds-device-info.cpp index f871227143..1aa6cf6cc6 100644 --- a/src/dds/rs-dds-device-info.cpp +++ b/src/dds/rs-dds-device-info.cpp @@ -27,22 +27,14 @@ std::string dds_device_info::get_address() const return rsutils::string::from() << "dds." << domain_id << "://" << _dev->participant()->print( _dev->server_guid() ) << "@" - << _dev->device_info().topic_root; + << _dev->device_info().topic_root(); } void dds_device_info::to_stream( std::ostream & os ) const { os << "DDS device (" << _dev->participant()->print( _dev->guid() ) << " on domain " - << _dev->participant()->get()->get_domain_id() << "):"; - os << "\n\tName: " << _dev->device_info().name; - if( ! _dev->device_info().serial.empty() ) - os << "\n\tSerial: " << _dev->device_info().serial; - if( ! _dev->device_info().product_line.empty() ) - os << "\n\tProduct line: " << _dev->device_info().product_line; - os << "\n\tTopic root: " << _dev->device_info().topic_root; - if( _dev->device_info().locked ) - os << "\n\tLOCKED"; + << _dev->participant()->get()->get_domain_id() << "):" << _dev->device_info().to_json().dump( 4 ); } diff --git a/src/dds/rs-dds-device-proxy.cpp b/src/dds/rs-dds-device-proxy.cpp index de3165a06c..049165561f 100644 --- a/src/dds/rs-dds-device-proxy.cpp +++ b/src/dds/rs-dds-device-proxy.cpp @@ -121,12 +121,25 @@ dds_device_proxy::dds_device_proxy( std::shared_ptr< const device_info > const & , _dds_dev( dev ) { LOG_DEBUG( "=====> dds-device-proxy " << this << " created on top of dds-device " << _dds_dev.get() ); - register_info( RS2_CAMERA_INFO_NAME, dev->device_info().name ); - register_info( RS2_CAMERA_INFO_SERIAL_NUMBER, dev->device_info().serial ); - register_info( RS2_CAMERA_INFO_PRODUCT_LINE, dev->device_info().product_line ); + register_info( RS2_CAMERA_INFO_NAME, dev->device_info().name() ); + register_info( RS2_CAMERA_INFO_PHYSICAL_PORT, dev->device_info().topic_root() ); register_info( RS2_CAMERA_INFO_PRODUCT_ID, "DDS" ); - register_info( RS2_CAMERA_INFO_PHYSICAL_PORT, dev->device_info().topic_root ); - register_info( RS2_CAMERA_INFO_CAMERA_LOCKED, dev->device_info().locked ? "YES" : "NO" ); + + auto & j = dev->device_info().to_json(); + std::string str; + if( rsutils::json::get_ex( j, "serial", &str ) ) + { + register_info( RS2_CAMERA_INFO_SERIAL_NUMBER, str ); + rsutils::json::get_ex( j, "fw-update-id", &str ); // if fails, str will be the serial + register_info( RS2_CAMERA_INFO_FIRMWARE_UPDATE_ID, str ); + } + else if( rsutils::json::get_ex( j, "fw-update-id", &str ) ) + register_info( RS2_CAMERA_INFO_FIRMWARE_UPDATE_ID, str ); + if( rsutils::json::get_ex( j, "fw-version", &str ) ) + register_info( RS2_CAMERA_INFO_FIRMWARE_VERSION, str ); + if( rsutils::json::get_ex( j, "product-line", &str ) ) + register_info( RS2_CAMERA_INFO_PRODUCT_LINE, str ); + register_info( RS2_CAMERA_INFO_CAMERA_LOCKED, rsutils::json::get( j, "locked", true ) ? "YES" : "NO" ); // Assumes dds_device initialization finished struct sensor_info diff --git a/src/dds/rs-dds-sensor-proxy.cpp b/src/dds/rs-dds-sensor-proxy.cpp index 54fcf6dca6..cc686bba67 100644 --- a/src/dds/rs-dds-sensor-proxy.cpp +++ b/src/dds/rs-dds-sensor-proxy.cpp @@ -436,7 +436,7 @@ void dds_sensor_proxy::start( rs2_frame_callback_sptr callback ) } auto const & dds_stream = streamit->second; // Opening it will start streaming on the server side automatically - dds_stream->open( "rt/" + _dev->device_info().topic_root + '_' + dds_stream->name(), _dev->subscriber() ); + dds_stream->open( "rt/" + _dev->device_info().topic_root() + '_' + dds_stream->name(), _dev->subscriber() ); auto & streaming = _streaming_by_name[dds_stream->name()]; streaming.syncer.on_frame_release( frame_releaser ); streaming.syncer.on_frame_ready( diff --git a/src/dds/rsdds-device-factory.cpp b/src/dds/rsdds-device-factory.cpp index 905878b8c0..504231165c 100644 --- a/src/dds/rsdds-device-factory.cpp +++ b/src/dds/rsdds-device-factory.cpp @@ -145,15 +145,23 @@ std::vector< std::shared_ptr< device_info > > rsdds_device_factory::query_device LOG_DEBUG( "device '" << dev->device_info().debug_name() << "' is not ready" ); return true; } - if( dev->device_info().product_line == "D400" ) + std::string product_line; + if( rsutils::json::get_ex( dev->device_info().to_json(), "product-line", &product_line ) ) { - if( ! ( mask & RS2_PRODUCT_LINE_D400 ) ) - return true; - } - else if( dev->device_info().product_line == "D500" ) - { - if( ! ( mask & RS2_PRODUCT_LINE_D500 ) ) + if( product_line == "D400" ) + { + if( ! ( mask & RS2_PRODUCT_LINE_D400 ) ) + return true; + } + else if( product_line == "D500" ) + { + if( ! ( mask & RS2_PRODUCT_LINE_D500 ) ) + return true; + } + else if( ! ( mask & RS2_PRODUCT_LINE_NON_INTEL ) ) + { return true; + } } else if( ! ( mask & RS2_PRODUCT_LINE_NON_INTEL ) ) { diff --git a/third-party/realdds/include/realdds/topics/device-info-msg.h b/third-party/realdds/include/realdds/topics/device-info-msg.h index 60ae84d35a..78ea8d3ec2 100644 --- a/third-party/realdds/include/realdds/topics/device-info-msg.h +++ b/third-party/realdds/include/realdds/topics/device-info-msg.h @@ -1,9 +1,8 @@ // License: Apache 2.0. See LICENSE file in root directory. // Copyright(c) 2022 Intel Corporation. All Rights Reserved. - #pragma once -#include +#include #include @@ -12,14 +11,23 @@ namespace topics { class device_info { + nlohmann::json _json; + public: - std::string name; - std::string serial; - std::string product_line; - std::string topic_root; - bool locked = true; + //std::string serial; + //std::string product_line; + //bool locked = true; + + std::string const & name() const; + void set_name( std::string && ); + + std::string const & topic_root() const; + void set_topic_root( std::string && ); + + std::string const & serial_number() const; + void set_serial_number( std::string && ); - nlohmann::json to_json() const; + nlohmann::json const & to_json() const; static device_info from_json( nlohmann::json const & j ); // Substring of information already stored in the device-info that can be used to print the device 'name'. diff --git a/third-party/realdds/py/pyrealdds.cpp b/third-party/realdds/py/pyrealdds.cpp index 58a1fbf1e4..59c88a33b3 100644 --- a/third-party/realdds/py/pyrealdds.cpp +++ b/third-party/realdds/py/pyrealdds.cpp @@ -375,27 +375,16 @@ PYBIND11_MODULE(NAME, m) { py::class_< device_info >( message, "device_info" ) .def( py::init<>() ) .def_static( "create_topic", static_cast< flexible_msg_create_topic * >( &flexible_msg::create_topic ) ) - .def_readwrite( "name", &device_info::name ) - .def_readwrite( "serial", &device_info::serial ) - .def_readwrite( "product_line", &device_info::product_line ) - .def_readwrite( "locked", &device_info::locked ) - .def_readwrite( "topic_root", &device_info::topic_root ) + .def_property( "name", &device_info::name, &device_info::set_name ) + .def_property( "topic_root", &device_info::topic_root, &device_info::set_topic_root ) + .def_property( "serial", &device_info::serial_number, &device_info::set_serial_number ) .def_static( "from_json", &device_info::from_json ) .def( "to_json", &device_info::to_json ) .def( "__repr__", []( device_info const & self ) { std::ostringstream os; os << "<" SNAME ".device_info"; - if( ! self.name.empty() ) - os << " \"" << self.name << "\""; - if( ! self.serial.empty() ) - os << " s/n \"" << self.serial << "\""; - if( ! self.topic_root.empty() ) - os << " @ \"" << self.topic_root << "\""; - if( ! self.product_line.empty() ) - os << " product-line \"" << self.product_line << "\""; - if( self.locked ) - os << " locked"; + os << " " << self.to_json(); os << ">"; return os.str(); } ); @@ -953,8 +942,8 @@ PYBIND11_MODULE(NAME, m) { std::ostringstream os; os << "<" SNAME ".device"; os << " " << self.participant()->print( self.guid() ); - if( ! self.device_info().name.empty() ) - os << " \"" << self.device_info().name << "\""; + if( ! self.device_info().name().empty() ) + os << " \"" << self.device_info().name() << "\""; os << " @ " << self.device_info().debug_name(); os << ">"; return os.str(); diff --git a/third-party/realdds/src/dds-device-broadcaster.cpp b/third-party/realdds/src/dds-device-broadcaster.cpp index 930e1d67f5..788b362e48 100644 --- a/third-party/realdds/src/dds-device-broadcaster.cpp +++ b/third-party/realdds/src/dds-device-broadcaster.cpp @@ -146,7 +146,7 @@ void dds_device_broadcaster::broadcast() const } catch( std::exception const & e ) { - LOG_ERROR( "Error sending device-info message for S/N " << _device_info.serial << ": " << e.what() ); + LOG_ERROR( "Error sending device-info message for S/N " << _device_info.serial_number() << ": " << e.what() ); } } diff --git a/third-party/realdds/src/dds-device-impl.cpp b/third-party/realdds/src/dds-device-impl.cpp index f4e4b565ea..f0af09cf23 100644 --- a/third-party/realdds/src/dds-device-impl.cpp +++ b/third-party/realdds/src/dds-device-impl.cpp @@ -475,7 +475,7 @@ void dds_device::impl::create_notifications_reader() if( _notifications_reader ) return; - auto topic = topics::flexible_msg::create_topic( _participant, _info.topic_root + topics::NOTIFICATION_TOPIC_NAME ); + auto topic = topics::flexible_msg::create_topic( _participant, _info.topic_root() + topics::NOTIFICATION_TOPIC_NAME ); // We have some complicated topic structures. In particular, the metadata topic is created on demand while handling // other notifications, which doesn't work well (deadlock) if the notification is not called from another thread. So @@ -518,7 +518,7 @@ void dds_device::impl::create_metadata_reader() if( _metadata_reader ) // We can be called multiple times, once per stream return; - auto topic = topics::flexible_msg::create_topic( _participant, _info.topic_root + topics::METADATA_TOPIC_NAME ); + auto topic = topics::flexible_msg::create_topic( _participant, _info.topic_root() + topics::METADATA_TOPIC_NAME ); _metadata_reader = std::make_shared< dds_topic_reader_thread >( topic, _subscriber ); _metadata_reader->on_data_available( [this]() @@ -549,7 +549,7 @@ void dds_device::impl::create_control_writer() if( _control_writer ) return; - auto topic = topics::flexible_msg::create_topic( _participant, _info.topic_root + topics::CONTROL_TOPIC_NAME ); + auto topic = topics::flexible_msg::create_topic( _participant, _info.topic_root() + topics::CONTROL_TOPIC_NAME ); _control_writer = std::make_shared< dds_topic_writer >( topic ); dds_topic_writer::qos wqos( eprosima::fastdds::dds::RELIABLE_RELIABILITY_QOS ); wqos.history().depth = 10; // default is 1 diff --git a/third-party/realdds/src/dds-device-server.cpp b/third-party/realdds/src/dds-device-server.cpp index f3507eae94..9f2853c0d7 100644 --- a/third-party/realdds/src/dds-device-server.cpp +++ b/third-party/realdds/src/dds-device-server.cpp @@ -238,7 +238,7 @@ void dds_device_server::broadcast( topics::device_info const & device_info ) { if( _broadcaster ) DDS_THROW( runtime_error, "device server was already broadcast" ); - if( device_info.topic_root != _topic_root ) + if( device_info.topic_root() != _topic_root ) DDS_THROW( runtime_error, "topic roots do not match" ); _broadcaster = std::make_shared< dds_device_broadcaster >( _publisher, device_info ); } diff --git a/third-party/realdds/src/dds-device.cpp b/third-party/realdds/src/dds-device.cpp index a67318b8a7..bf5dcc2d9e 100644 --- a/third-party/realdds/src/dds-device.cpp +++ b/third-party/realdds/src/dds-device.cpp @@ -15,7 +15,7 @@ namespace realdds { dds_device::dds_device( std::shared_ptr< dds_participant > const & participant, topics::device_info const & info ) : _impl( std::make_shared< dds_device::impl >( participant, info ) ) { - LOG_DEBUG( "+device '" << _impl->debug_name() << "' on " << info.topic_root ); + LOG_DEBUG( "+device '" << _impl->debug_name() << "' on " << info.topic_root() ); } diff --git a/third-party/realdds/src/topics/device-info-msg.cpp b/third-party/realdds/src/topics/device-info-msg.cpp index 9e256c73cc..ebf1947c06 100644 --- a/third-party/realdds/src/topics/device-info-msg.cpp +++ b/third-party/realdds/src/topics/device-info-msg.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -11,41 +12,71 @@ namespace realdds { namespace topics { +static std::string name_key( "name", 4 ); +static std::string topic_root_key( "topic-root", 10 ); +static std::string serial_number_key( "serial", 6 ); + + /* static */ device_info device_info::from_json( nlohmann::json const & j ) { device_info ret; + ret._json = j; - ret.name = rsutils::json::get< std::string >( j, "name" ); - rsutils::json::get_ex( j, "serial", &ret.serial ); - rsutils::json::get_ex( j, "product-line", &ret.product_line ); - ret.topic_root = rsutils::json::get< std::string >( j, "topic-root" ); - rsutils::json::get_ex( j, "locked", &ret.locked ); + // Check the two mandatory fields are there + if( ret.name().empty() ) + DDS_THROW( runtime_error, "empty device-info name" ); + if( ret.topic_root().empty() ) + DDS_THROW( runtime_error, "empty device-info topic-root" ); return ret; } -nlohmann::json device_info::to_json() const +nlohmann::json const & device_info::to_json() const +{ + return _json; +} + + +std::string const & device_info::name() const +{ + return rsutils::json::nested( _json, name_key ).string_ref_or_empty(); +} + +void device_info::set_name( std::string && v ) +{ + _json[name_key] = std::move( v ); +} + + +std::string const & device_info::topic_root() const +{ + return rsutils::json::nested( _json, topic_root_key ).string_ref_or_empty(); +} + +void device_info::set_topic_root( std::string && v ) +{ + _json[topic_root_key] = std::move( v ); +} + + +std::string const & device_info::serial_number() const +{ + return rsutils::json::nested( _json, serial_number_key ).string_ref_or_empty(); +} + +void device_info::set_serial_number( std::string && v ) { - auto msg = nlohmann::json( { - { "name", name }, - { "topic-root", topic_root }, - } ); - if( ! serial.empty() ) - msg["serial"] = serial; - if( ! product_line.empty() ) - msg["product-line"] = product_line; - if( ! locked ) - msg["locked"] = false; - return msg; + _json[serial_number_key] = std::move( v ); } rsutils::string::slice device_info::debug_name() const { - auto begin = topic_root.c_str(); - auto end = begin + topic_root.length(); - if( topic_root.length() > ROOT_LEN && SEPARATOR == begin[ROOT_LEN-1] ) + auto & root = topic_root(); + auto begin = root.c_str(); + auto end = begin + root.length(); + if( root.length() > ROOT_LEN && SEPARATOR == begin[ROOT_LEN-1] ) begin += ROOT_LEN; return{ begin, end }; } diff --git a/tools/dds/dds-adapter/rs-dds-adapter.cpp b/tools/dds/dds-adapter/rs-dds-adapter.cpp index 5e32b1b419..91a071d751 100644 --- a/tools/dds/dds-adapter/rs-dds-adapter.cpp +++ b/tools/dds/dds-adapter/rs-dds-adapter.cpp @@ -28,35 +28,49 @@ using namespace TCLAP; using namespace realdds; -std::string get_topic_root( topics::device_info const & dev_info ) +std::string get_topic_root( std::string const & name, std::string const & serial_number ) { // Build device root path (we use a device model only name like DXXX) // example: /realsense/D435/11223344 constexpr char const * DEVICE_NAME_PREFIX = "Intel RealSense "; constexpr size_t DEVICE_NAME_PREFIX_CCH = 16; // We don't need the prefix in the path - std::string model_name = dev_info.name; + std::string model_name = name; if ( model_name.length() > DEVICE_NAME_PREFIX_CCH && 0 == strncmp( model_name.data(), DEVICE_NAME_PREFIX, DEVICE_NAME_PREFIX_CCH ) ) { model_name.erase( 0, DEVICE_NAME_PREFIX_CCH ); } constexpr char const * RS_ROOT = "realsense/"; - return RS_ROOT + model_name + '_' + dev_info.serial; + return RS_ROOT + model_name + '_' + serial_number; } topics::device_info rs2_device_to_info( rs2::device const & dev ) { - topics::device_info dev_info; - dev_info.name = dev.get_info( RS2_CAMERA_INFO_NAME ); - dev_info.serial = dev.get_info( RS2_CAMERA_INFO_SERIAL_NUMBER ); - dev_info.product_line = dev.get_info( RS2_CAMERA_INFO_PRODUCT_LINE ); - dev_info.locked = ( strcmp( dev.get_info( RS2_CAMERA_INFO_CAMERA_LOCKED ), "YES" ) == 0 ); + nlohmann::json j; + + // Name is mandatory + std::string const name = dev.get_info( RS2_CAMERA_INFO_NAME ); + j["name"] = name; + + if( dev.supports( RS2_CAMERA_INFO_SERIAL_NUMBER ) ) + j["serial"] = dev.get_info( RS2_CAMERA_INFO_SERIAL_NUMBER ); + if( dev.supports( RS2_CAMERA_INFO_PRODUCT_LINE ) ) + j["product-line"] = dev.get_info( RS2_CAMERA_INFO_PRODUCT_LINE ); + if( dev.supports( RS2_CAMERA_INFO_CAMERA_LOCKED ) ) + j["locked"] = ( strcmp( dev.get_info( RS2_CAMERA_INFO_CAMERA_LOCKED ), "YES" ) == 0 ); + + // FW update ID is a must for DFU; all cameras should have one + std::string const serial_number = dev.get_info( RS2_CAMERA_INFO_FIRMWARE_UPDATE_ID ); + j["fw-update-id"] = serial_number; + if( auto update_device = rs2::update_device( dev ) ) + j["recovery"] = true; // Build device topic root path - dev_info.topic_root = get_topic_root( dev_info ); - return dev_info; + j["topic-root"] = get_topic_root( name, serial_number ); + + return topics::device_info::from_json( j ); } @@ -175,7 +189,7 @@ try // Create a dds-device-server for this device auto dds_device_server - = std::make_shared< realdds::dds_device_server >( participant, dev_info.topic_root ); + = std::make_shared< realdds::dds_device_server >( participant, dev_info.topic_root() ); // Create a lrs_device_manager for this device std::shared_ptr< tools::lrs_device_controller > lrs_device_controller diff --git a/unit-tests/dds/d405.py b/unit-tests/dds/d405.py index 143aea192a..faa0f5b540 100644 --- a/unit-tests/dds/d405.py +++ b/unit-tests/dds/d405.py @@ -5,11 +5,12 @@ from rspy import log, test -device_info = dds.message.device_info() -device_info.name = "Intel RealSense D405" -device_info.serial = "123622270732" -device_info.product_line = "D400" -device_info.topic_root = "realdds/D405/" + device_info.serial +device_info = dds.message.device_info.from_json( { + "name": "Intel RealSense D405", + "serial": "123622270732", + "product-line": "D400", + "topic-root": "realdds/D405/123622270732" +} ) def build( participant ): diff --git a/unit-tests/dds/d435i.py b/unit-tests/dds/d435i.py index fd9938c804..4844fd4843 100644 --- a/unit-tests/dds/d435i.py +++ b/unit-tests/dds/d435i.py @@ -5,11 +5,12 @@ from rspy import log, test -device_info = dds.message.device_info() -device_info.name = "Intel RealSense D435I" -device_info.serial = "036522070660" -device_info.product_line = "D400" -device_info.topic_root = "realsense/D435I_" + device_info.serial +device_info = dds.message.device_info.from_json({ + "name": "Intel RealSense D435I", + "serial": "036522070660", + "product-line": "D400", + "topic-root": "realsense/D435I_036522070660" +}) def build( participant ): diff --git a/unit-tests/dds/d455.py b/unit-tests/dds/d455.py index 74fa11dce2..ca0606a60b 100644 --- a/unit-tests/dds/d455.py +++ b/unit-tests/dds/d455.py @@ -5,11 +5,12 @@ from rspy import log, test -device_info = dds.message.device_info() -device_info.name = "Intel RealSense D455" -device_info.serial = "114222251267" -device_info.product_line = "D400" -device_info.topic_root = "realdds/D455/" + device_info.serial +device_info = dds.message.device_info.from_json( { + "name": "Intel RealSense D455", + "serial": "114222251267", + "product-line": "D400", + "topic-root": "realdds/D455/114222251267" +} ) def build( participant ): @@ -233,7 +234,7 @@ def stereo_module_options(): options.append( option ) option = dds.option( "Stereo Baseline", dds.option_range( 94.9609, 94.9609, 0, 94.9609 ), "Distance in mm between the stereo imagers" ) options.append( option ) - option = dds.option( "Inter Cam Sync Mode", dds.option_range( 0, 260, 1, 0 ), + option = dds.option( "Inter Cam Sync Mode", dds.option_range( 0, 260, 1, 0 ), "Inter-camera synchronization mode: 0:Default, 1:Master, 2:Slave, 3:Full Salve, 4-258:Genlock with burst count of 1-255 frames for each trigger, 259 and 260 for two frames per trigger with laser ON-OFF and OFF-ON." ) options.append( option ) option = dds.option( "Emitter On Off", dds.option_range( 0, 1, 1, 0 ), "Alternating emitter pattern, toggled on/off on per-frame basis" ) @@ -254,11 +255,11 @@ def stereo_module_options(): options.append( option ) option = dds.option( "Sequence Id", dds.option_range( 0, 2, 1, 0 ), "HDR Option" ) options.append( option ) - option = dds.option( "Auto Exposure Limit", dds.option_range( 1, 200000, 1, 33000 ), + option = dds.option( "Auto Exposure Limit", dds.option_range( 1, 200000, 1, 33000 ), "Exposure limit is in microseconds. If the requested exposure limit is greater than frame time, it will be set to frame time at runtime. Setting will not take effect until next streaming session." ) option.set_value( 200000 ) options.append( option ) - option = dds.option( "Auto Gain Limit", dds.option_range( 16, 248, 1, 16 ), + option = dds.option( "Auto Gain Limit", dds.option_range( 16, 248, 1, 16 ), "Gain limits ranges from 16 to 248. If the requested gain limit is less than 16, it will be set to 16. If the requested gain limit is greater than 248, it will be set to 248. Setting will not take effect until next streaming session." ) option.set_value( 248 ) options.append( option ) diff --git a/unit-tests/dds/formats-conversion-server.py b/unit-tests/dds/formats-conversion-server.py index 5a9da737fe..b8d1cfdcf5 100644 --- a/unit-tests/dds/formats-conversion-server.py +++ b/unit-tests/dds/formats-conversion-server.py @@ -11,11 +11,10 @@ participant = dds.participant() participant.init( 123, "formats-conversion-server" ) -device_info = dds.message.device_info() -device_info.name = "formats-conversion-device" -device_info.serial = "123" -device_info.product_line = "D400" -device_info.topic_root = "root_" + device_info.serial +device_info = dds.message.device_info.from_json({ + "name": "formats-conversion-device", + "topic-root": "root_123" +}) # Used to created a device_server per test case, but it currently creates problems when creating a second device while # the first did not yet close. Changing to one device_server with different sensor per test case. diff --git a/unit-tests/dds/test-librs-formats-conversion.py b/unit-tests/dds/test-librs-formats-conversion.py index 0e57086e5a..07cc23f0ca 100644 --- a/unit-tests/dds/test-librs-formats-conversion.py +++ b/unit-tests/dds/test-librs-formats-conversion.py @@ -13,7 +13,7 @@ log.nested = 'C ' context = rs.context( { 'dds': { 'enabled': True, 'domain': 123, 'participant': 'test-formats-conversion' }} ) -only_sw_devices = int(rs.product_line.sw_only) | int(rs.product_line.any_intel) +only_sw_devices = int(rs.product_line.sw_only) | int(rs.product_line.any) import os.path cwd = os.path.dirname(os.path.realpath(__file__)) diff --git a/unit-tests/dds/watcher-server.py b/unit-tests/dds/watcher-server.py index 1445d7e5d7..7418054c62 100644 --- a/unit-tests/dds/watcher-server.py +++ b/unit-tests/dds/watcher-server.py @@ -19,11 +19,10 @@ def broadcast( props ): global broadcasters, publisher - di = dds.message.device_info() - di.serial = props.get( 'serial', str(len(broadcasters)) ) - di.name = props.get( 'name', f'device{di.serial}' ) - di.product_line = props.get( 'product_line', '' ) - di.topic_root = props.get( 'topic_root', f'path/to/{di.name}' ) + serial = props.setdefault( 'serial', str(len(broadcasters)) ) + props.setdefault( 'name', f'device{serial}' ) + props.setdefault( 'topic-root', f'device{serial}' ) + di = dds.message.device_info.from_json( props ) broadcasters.append( dds.device_broadcaster( publisher, di ) ) From 04348ae93a704f37c7b8d5a6182ec0f89441656c Mon Sep 17 00:00:00 2001 From: Eran Date: Sat, 30 Sep 2023 09:00:55 +0300 Subject: [PATCH 04/12] add get_type(), get_description() to rs2::device --- include/librealsense2/hpp/rs_device.hpp | 42 +++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/include/librealsense2/hpp/rs_device.hpp b/include/librealsense2/hpp/rs_device.hpp index 7986d0c8c5..dbc0893692 100644 --- a/include/librealsense2/hpp/rs_device.hpp +++ b/include/librealsense2/hpp/rs_device.hpp @@ -49,6 +49,48 @@ namespace rs2 return results; } + /** + * \return the type of device: USB/GMSL/DDS, etc. + */ + std::string get_type() const + { + if( supports( RS2_CAMERA_INFO_USB_TYPE_DESCRIPTOR ) ) + return "USB"; + if( supports( RS2_CAMERA_INFO_PRODUCT_ID ) ) + { + std::string pid = get_info( RS2_CAMERA_INFO_PRODUCT_ID ); + if( pid == "ABCD" ) // Specific for D457 + return "GMSL"; + return pid; // for DDS devices, this will be "DDS" + } + return {}; + } + + /** + * \return the one-line description: "[] s/n <#>" + */ + std::string get_description() const + { + std::ostringstream os; + auto type = get_type(); + if( supports( RS2_CAMERA_INFO_NAME ) ) + { + if( ! type.empty() ) + os << "[" << type << "] "; + os << get_info( RS2_CAMERA_INFO_NAME ); + } + else + { + if( ! type.empty() ) + os << type << " device"; + else + os << "unknown device"; + } + if( supports( RS2_CAMERA_INFO_SERIAL_NUMBER ) ) + os << " s/n " << get_info( RS2_CAMERA_INFO_SERIAL_NUMBER ); + return os.str(); + } + template T first() const { From 3252b305f5a8eecaef6f092f6f927bfb09313391 Mon Sep 17 00:00:00 2001 From: Eran Date: Tue, 26 Dec 2023 08:48:33 +0200 Subject: [PATCH 05/12] use device.get_description() in lrs-device-watcher --- tools/dds/dds-adapter/lrs-device-watcher.cpp | 21 ++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/tools/dds/dds-adapter/lrs-device-watcher.cpp b/tools/dds/dds-adapter/lrs-device-watcher.cpp index 4e00a358ed..d19b77f2ea 100644 --- a/tools/dds/dds-adapter/lrs-device-watcher.cpp +++ b/tools/dds/dds-adapter/lrs-device-watcher.cpp @@ -45,22 +45,27 @@ void lrs_device_watcher::run( std::function< void( rs2::device ) > add_device_cb try { remove_device_cb( device_to_remove ); - std::cout << "Device '" << device_to_remove.get_info( RS2_CAMERA_INFO_SERIAL_NUMBER ) << "' - removed" << std::endl; - auto it = std::find_if( strong_rs_device_list->begin(), strong_rs_device_list->end(), - [&]( const rs2::device & dev ) { - return strcmp( dev.get_info( RS2_CAMERA_INFO_SERIAL_NUMBER ), device_to_remove.get_info( RS2_CAMERA_INFO_SERIAL_NUMBER ) ) == 0; - } ); + std::cout << device_to_remove.get_description() << " - removed" << std::endl; + auto it = std::find_if( + strong_rs_device_list->begin(), + strong_rs_device_list->end(), + [&]( const rs2::device & dev ) + { + return strcmp( dev.get_info( RS2_CAMERA_INFO_FIRMWARE_UPDATE_ID ), + device_to_remove.get_info( RS2_CAMERA_INFO_FIRMWARE_UPDATE_ID ) ) + == 0; + } ); strong_rs_device_list->erase( it ); } catch( std::exception e ) { - std::cout << "Exception durin remove_device_cb: " << e.what() << std::endl; + std::cout << "Exception during remove_device_cb: " << e.what() << std::endl; } } for( auto && rs_device : info.get_new_devices() ) { - std::cout << "Device '" << rs_device.get_info( RS2_CAMERA_INFO_SERIAL_NUMBER ) << "' - detected" << std::endl; + std::cout << rs_device.get_description() << " - detected" << std::endl; add_device_cb( rs_device ); strong_rs_device_list->push_back(rs_device); } @@ -73,7 +78,7 @@ void lrs_device_watcher::notify_connected_devices_on_wake_up( std::function< voi auto connected_dev_list = _ctx.query_devices(); for( auto connected_dev : connected_dev_list ) { - std::cout << "Device '" << connected_dev.get_info(RS2_CAMERA_INFO_SERIAL_NUMBER) << "' - detected" << std::endl; + std::cout << connected_dev.get_description() << " - detected" << std::endl; add_device_cb( connected_dev ); _rs_device_list->push_back(connected_dev); } From 5710317478ce287077422c9af24e2741e21a18cf Mon Sep 17 00:00:00 2001 From: Eran Date: Tue, 26 Dec 2023 08:48:59 +0200 Subject: [PATCH 06/12] fix DDS deactivation if no 'dds' key in settings --- src/dds/rsdds-device-factory.cpp | 16 +++++++--------- third-party/realdds/src/dds-participant.cpp | 9 ++++++--- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/dds/rsdds-device-factory.cpp b/src/dds/rsdds-device-factory.cpp index 504231165c..3b1dc8eb36 100644 --- a/src/dds/rsdds-device-factory.cpp +++ b/src/dds/rsdds-device-factory.cpp @@ -83,23 +83,21 @@ static std::mutex domain_context_by_id_mutex; rsdds_device_factory::rsdds_device_factory( std::shared_ptr< context > const & ctx, callback && cb ) : super( ctx ) { - nlohmann::json const & dds_settings = rsutils::json::nested( ctx->get_settings(), std::string( "dds", 3 ) ); - if( dds_settings.is_object() && rsutils::json::get( dds_settings, std::string( "enabled", 7 ), true ) ) + rsutils::json::nested dds_settings( ctx->get_settings(), std::string( "dds", 3 ) ); + if( dds_settings.is_object() && dds_settings.find( std::string( "enabled", 7 ) ).default_value( true ) ) { - auto domain_id = rsutils::json::get< realdds::dds_domain_id >( dds_settings, std::string( "domain", 6 ), 0 ); - std::string participant_name = rsutils::json::get< std::string >( dds_settings, - std::string( "participant", 11 ), - rsutils::os::executable_name() ); + auto domain_id = dds_settings.find( std::string( "domain", 6 ) ).default_value< realdds::dds_domain_id >( 0 ); + auto participant_name_j = dds_settings.find( std::string( "participant", 11 ) ); + auto participant_name = participant_name_j.default_value( rsutils::os::executable_name() ); std::lock_guard< std::mutex > lock( domain_context_by_id_mutex ); auto & domain = domain_context_by_id[domain_id]; _participant = domain.participant.instance(); if( ! _participant->is_valid() ) { - _participant->init( domain_id, participant_name, std::move( dds_settings ) ); + _participant->init( domain_id, participant_name, dds_settings.default_object() ); } - else if( rsutils::json::has_value( dds_settings, std::string( "participant", 11 ) ) - && participant_name != _participant->name() ) + else if( participant_name_j.exists() && participant_name != _participant->name() ) { throw std::runtime_error( rsutils::string::from() << "A DDS participant '" << _participant->name() << "' already exists in domain " diff --git a/third-party/realdds/src/dds-participant.cpp b/third-party/realdds/src/dds-participant.cpp index 55819b4f6c..6347d1d1b6 100644 --- a/third-party/realdds/src/dds-participant.cpp +++ b/third-party/realdds/src/dds-participant.cpp @@ -242,9 +242,12 @@ void dds_participant::init( dds_domain_id domain_id, std::string const & partici "failed creating participant " + participant_name + " on domain id " + std::to_string( domain_id ) ); } - if( ! settings.is_object() ) - DDS_THROW( runtime_error, "provided settings are invalid" ); - _settings = settings; + if( settings.is_object() ) + _settings = settings; + else if( settings.is_null() ) + _settings = nlohmann::json::object(); + else + DDS_THROW( runtime_error, "provided settings are invalid: " << settings ); LOG_DEBUG( "participant '" << participant_name << "' (" << realdds::print_guid( guid() ) << ") is up on domain " << domain_id << " with settings: " << _settings.dump( 4 ) ); From efd9485558aeb204d65bba1406c238de231875d6 Mon Sep 17 00:00:00 2001 From: Eran Date: Tue, 26 Dec 2023 08:52:32 +0200 Subject: [PATCH 07/12] fixes in realdds/scripts --- third-party/realdds/scripts/devices.py | 2 ++ third-party/realdds/scripts/fps.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/third-party/realdds/scripts/devices.py b/third-party/realdds/scripts/devices.py index 5870a18f67..58e1215303 100644 --- a/third-party/realdds/scripts/devices.py +++ b/third-party/realdds/scripts/devices.py @@ -35,6 +35,8 @@ def e( *a, **kw ): dds.debug( args.debug ) +settings = {} + participant = dds.participant() participant.init( dds.load_rs_settings( settings ), args.domain ) diff --git a/third-party/realdds/scripts/fps.py b/third-party/realdds/scripts/fps.py index 36e8f9577d..d91bf79793 100644 --- a/third-party/realdds/scripts/fps.py +++ b/third-party/realdds/scripts/fps.py @@ -53,7 +53,7 @@ def e( *a, **kw ): # Create the device and initialize # The server must be up and running, or the init will time out! -device = dds.device( participant, participant.create_guid(), info ) +device = dds.device( participant, info ) try: i( 'Looking for device at', info.topic_root, '...' ) device.wait_until_ready() # If unavailable before timeout, this throws From 0de85100e30a94c7f86959c92597b3b4d146ade5 Mon Sep 17 00:00:00 2001 From: Eran Date: Tue, 26 Dec 2023 10:51:38 +0200 Subject: [PATCH 08/12] dynamic column width in rs-enumerate-devices -s --- .../rs-enumerate-devices.cpp | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/tools/enumerate-devices/rs-enumerate-devices.cpp b/tools/enumerate-devices/rs-enumerate-devices.cpp index f9adb2ce4f..d2c1ede52a 100644 --- a/tools/enumerate-devices/rs-enumerate-devices.cpp +++ b/tools/enumerate-devices/rs-enumerate-devices.cpp @@ -418,11 +418,6 @@ int main(int argc, char** argv) try if (short_view || compact_view) { - cout << left << setw(30) << "Device Name" - << setw(20) << "Serial Number" - << setw(20) << "Firmware Version" - << endl; - auto dev_info = []( rs2::device dev, rs2_camera_info info ) { if( dev.supports( info ) ) @@ -430,13 +425,30 @@ int main(int argc, char** argv) try return "N/A"; }; + size_t w_name = 28; + size_t w_sn = 18; + for( auto i = 0u; i < devices.size(); ++i ) + { + auto dev = devices[i]; + + w_name = std::max( strlen( dev_info( dev, RS2_CAMERA_INFO_NAME ) ), w_name ); + w_sn = std::max( strlen( dev_info( dev, RS2_CAMERA_INFO_SERIAL_NUMBER ) ), w_sn ); + } + w_name += 2; + w_sn += 2; + + cout << left << setw(w_name) << "Device Name" + << setw(w_sn) << "Serial Number" + << "Firmware Version" + << endl; + for (auto i = 0u; i < devices.size(); ++i) { auto dev = devices[i]; - cout << left << setw(30) << dev_info(dev,RS2_CAMERA_INFO_NAME) - << setw(20) << dev_info(dev,RS2_CAMERA_INFO_SERIAL_NUMBER) - << setw(20) << dev_info(dev,RS2_CAMERA_INFO_FIRMWARE_VERSION) + cout << left << setw(w_name) << dev_info(dev,RS2_CAMERA_INFO_NAME) + << setw(w_sn) << dev_info(dev,RS2_CAMERA_INFO_SERIAL_NUMBER) + << dev_info(dev,RS2_CAMERA_INFO_FIRMWARE_VERSION) << endl; } From 48ef97f0261abfddadf0b38e909fbcf2c07c7beb Mon Sep 17 00:00:00 2001 From: Eran Date: Wed, 27 Dec 2023 07:40:13 +0200 Subject: [PATCH 09/12] fix DDS 'log' notification timestamp output --- third-party/realdds/include/realdds/dds-device.h | 2 +- third-party/realdds/py/pyrealdds.cpp | 4 ++-- third-party/realdds/src/dds-device-impl.cpp | 4 ++-- third-party/realdds/src/dds-device-impl.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/third-party/realdds/include/realdds/dds-device.h b/third-party/realdds/include/realdds/dds-device.h index b11b464b9e..6e5118491d 100644 --- a/third-party/realdds/include/realdds/dds-device.h +++ b/third-party/realdds/include/realdds/dds-device.h @@ -75,7 +75,7 @@ class dds_device rsutils::subscription on_metadata_available( on_metadata_available_callback && ); typedef std::function< void( - dds_time const & timestamp, char type, std::string const & text, nlohmann::json const & data ) > + dds_nsec timestamp, char type, std::string const & text, nlohmann::json const & data ) > on_device_log_callback; rsutils::subscription on_device_log( on_device_log_callback && cb ); diff --git a/third-party/realdds/py/pyrealdds.cpp b/third-party/realdds/py/pyrealdds.cpp index 59c88a33b3..cab2ec5a0b 100644 --- a/third-party/realdds/py/pyrealdds.cpp +++ b/third-party/realdds/py/pyrealdds.cpp @@ -898,10 +898,10 @@ PYBIND11_MODULE(NAME, m) { { FN_FWD_CALL( dds_device, "on_metadata_available", callback( self, json_to_py( *pj ) ); ) } ) ); } ) .def( "on_device_log", - []( dds_device & self, std::function< void( dds_device &, dds_time const &, char, std::string const &, py::object && ) > callback ) + []( dds_device & self, std::function< void( dds_device &, dds_nsec, char, std::string const &, py::object && ) > callback ) { return std::make_shared< subscription >( self.on_device_log( - [&self, callback]( dds_time const & timestamp, char type, std::string const & text, nlohmann::json const & data ) + [&self, callback]( dds_nsec timestamp, char type, std::string const & text, nlohmann::json const & data ) { FN_FWD_CALL( dds_device, "on_device_log", callback( self, timestamp, type, text, json_to_py( data ) ); ) } ) ); } ) .def( "on_notification", diff --git a/third-party/realdds/src/dds-device-impl.cpp b/third-party/realdds/src/dds-device-impl.cpp index f0af09cf23..47d376efd0 100644 --- a/third-party/realdds/src/dds-device-impl.cpp +++ b/third-party/realdds/src/dds-device-impl.cpp @@ -356,7 +356,7 @@ void dds_device::impl::on_log( nlohmann::json const & j, eprosima::fastdds::dds: throw std::runtime_error( "not an array" ); if( entry.size() < 3 || entry.size() > 4 ) throw std::runtime_error( "bad array length" ); - auto timestamp = time_from( rsutils::json::get< dds_nsec >( entry, 0 ) ); + auto timestamp = rsutils::json::get< dds_nsec >( entry, 0 ); auto const & stype = rsutils::json::string_ref( entry[1] ); if( stype.length() != 1 || ! strchr( "EWID", stype[0] ) ) throw std::runtime_error( "type not one of 'EWID'" ); @@ -365,7 +365,7 @@ void dds_device::impl::on_log( nlohmann::json const & j, eprosima::fastdds::dds: nlohmann::json const & data = entry.size() > 3 ? entry[3] : rsutils::json::null_json; if( ! _on_device_log.raise( timestamp, type, text, data ) ) - LOG_DEBUG( "[" << debug_name() << "][" << timestr( timestamp ) << "][" << type << "] " << text + LOG_DEBUG( "[" << debug_name() << "][" << timestamp << "][" << type << "] " << text << " [" << data << "]" ); } catch( std::exception const & e ) diff --git a/third-party/realdds/src/dds-device-impl.h b/third-party/realdds/src/dds-device-impl.h index 7fa8b14bba..3839e8cff9 100644 --- a/third-party/realdds/src/dds-device-impl.h +++ b/third-party/realdds/src/dds-device-impl.h @@ -94,7 +94,7 @@ class dds_device::impl return _on_metadata_available.subscribe( std::move( cb ) ); } - using on_device_log_signal = rsutils::signal< dds_time const &, // timestamp + using on_device_log_signal = rsutils::signal< dds_nsec, // timestamp char, // type std::string const &, // text nlohmann::json const & >; // data From f8ae6df6eb78dbe61a7a063c7bf87319c33ba4dc Mon Sep 17 00:00:00 2001 From: Eran Date: Wed, 27 Dec 2023 08:19:59 +0200 Subject: [PATCH 10/12] fixup! change realdds::topics::device_info to be json-based change && to const &, per CR --- .../realdds/include/realdds/topics/device-info-msg.h | 8 ++++---- third-party/realdds/src/topics/device-info-msg.cpp | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/third-party/realdds/include/realdds/topics/device-info-msg.h b/third-party/realdds/include/realdds/topics/device-info-msg.h index 78ea8d3ec2..87c343e242 100644 --- a/third-party/realdds/include/realdds/topics/device-info-msg.h +++ b/third-party/realdds/include/realdds/topics/device-info-msg.h @@ -19,16 +19,16 @@ class device_info //bool locked = true; std::string const & name() const; - void set_name( std::string && ); + void set_name( std::string const & ); std::string const & topic_root() const; - void set_topic_root( std::string && ); + void set_topic_root( std::string const & ); std::string const & serial_number() const; - void set_serial_number( std::string && ); + void set_serial_number( std::string const & ); nlohmann::json const & to_json() const; - static device_info from_json( nlohmann::json const & j ); + static device_info from_json( nlohmann::json const & ); // Substring of information already stored in the device-info that can be used to print the device 'name'. // (mostly for use with debug messages) diff --git a/third-party/realdds/src/topics/device-info-msg.cpp b/third-party/realdds/src/topics/device-info-msg.cpp index ebf1947c06..93d033f43c 100644 --- a/third-party/realdds/src/topics/device-info-msg.cpp +++ b/third-party/realdds/src/topics/device-info-msg.cpp @@ -43,9 +43,9 @@ std::string const & device_info::name() const return rsutils::json::nested( _json, name_key ).string_ref_or_empty(); } -void device_info::set_name( std::string && v ) +void device_info::set_name( std::string const & v ) { - _json[name_key] = std::move( v ); + _json[name_key] = v; } @@ -54,9 +54,9 @@ std::string const & device_info::topic_root() const return rsutils::json::nested( _json, topic_root_key ).string_ref_or_empty(); } -void device_info::set_topic_root( std::string && v ) +void device_info::set_topic_root( std::string const & v ) { - _json[topic_root_key] = std::move( v ); + _json[topic_root_key] = v; } @@ -65,9 +65,9 @@ std::string const & device_info::serial_number() const return rsutils::json::nested( _json, serial_number_key ).string_ref_or_empty(); } -void device_info::set_serial_number( std::string && v ) +void device_info::set_serial_number( std::string const & v ) { - _json[serial_number_key] = std::move( v ); + _json[serial_number_key] = v; } From 7d23f87d731c4f031e14c4d0d37b4b29f6b41f3b Mon Sep 17 00:00:00 2001 From: Eran Date: Wed, 27 Dec 2023 09:07:58 +0200 Subject: [PATCH 11/12] fixup! fix DDS deactivation if no 'dds' key in settings --- src/dds/rsdds-device-factory.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dds/rsdds-device-factory.cpp b/src/dds/rsdds-device-factory.cpp index 3b1dc8eb36..dead02a37c 100644 --- a/src/dds/rsdds-device-factory.cpp +++ b/src/dds/rsdds-device-factory.cpp @@ -84,7 +84,8 @@ rsdds_device_factory::rsdds_device_factory( std::shared_ptr< context > const & c : super( ctx ) { rsutils::json::nested dds_settings( ctx->get_settings(), std::string( "dds", 3 ) ); - if( dds_settings.is_object() && dds_settings.find( std::string( "enabled", 7 ) ).default_value( true ) ) + if( ! dds_settings.exists() + || dds_settings->is_object() && dds_settings.find( std::string( "enabled", 7 ) ).default_value( true ) ) { auto domain_id = dds_settings.find( std::string( "domain", 6 ) ).default_value< realdds::dds_domain_id >( 0 ); auto participant_name_j = dds_settings.find( std::string( "participant", 11 ) ); From 538f7612ffacc769b4ea0f8e38fa77da1b65b13a Mon Sep 17 00:00:00 2001 From: Eran Date: Wed, 27 Dec 2023 09:23:45 +0200 Subject: [PATCH 12/12] simplify json::nested with use of null_json --- third-party/rsutils/include/rsutils/json.h | 38 ++++++++++++---------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/third-party/rsutils/include/rsutils/json.h b/third-party/rsutils/include/rsutils/json.h index 35d73a59ee..d072a435dc 100644 --- a/third-party/rsutils/include/rsutils/json.h +++ b/third-party/rsutils/include/rsutils/json.h @@ -125,16 +125,16 @@ T get( nlohmann::json const & j, nlohmann::json::const_iterator const & it ) template< typename... Rest > -nlohmann::json const * _nested( nlohmann::json const & j ) +nlohmann::json const & _nested( nlohmann::json const & j ) { - return &j; + return j; } template< typename... Rest > -nlohmann::json const * _nested( nlohmann::json const & j, std::string const & inner, Rest... rest ) +nlohmann::json const & _nested( nlohmann::json const & j, std::string const & inner, Rest... rest ) { auto it = j.find( inner ); if( it == j.end() ) - return nullptr; + return null_json; return _nested( *it, std::forward< Rest >( rest )... ); } @@ -149,46 +149,48 @@ nlohmann::json const * _nested( nlohmann::json const & j, std::string const & in // class nested { - nlohmann::json const * _pj; + nlohmann::json const & _j; public: - nested() : _pj( nullptr ) {} + nested() : _j( null_json ) {} template< typename... Rest > nested( nlohmann::json const & j, Rest... rest ) - : _pj( _nested( j, std::forward< Rest >( rest )... ) ) + : _j( _nested( j, std::forward< Rest >( rest )... ) ) {} - nlohmann::json const * operator->() const { return _pj; } + nlohmann::json const * operator->() const { return &_j; } - bool exists() const { return _pj; } + bool exists() const { return ! _j.is_null(); } operator bool() const { return exists(); } - nlohmann::json const & get() const { return _pj ? *_pj : null_json; } + nlohmann::json const & get() const { return _j; } operator nlohmann::json const & () const { return get(); } - bool is_array() const { return exists() && _pj->is_array(); } - bool is_object() const { return exists() && _pj->is_object(); } - bool is_string() const { return exists() && _pj->is_string(); } + bool is_array() const { return _j.is_array(); } + bool is_object() const { return _j.is_object(); } + bool is_string() const { return _j.is_string(); } // Dig deeper template< typename... Rest > inline nested find( Rest... rest ) const { - return _pj ? nested( *_pj, std::forward< Rest >( rest )... ) : nested(); + return nested( _j, std::forward< Rest >( rest )... ); } inline nested operator[]( std::string const & key ) const { return find( key ); } // Get the JSON as a value template< class T > T value() const { return json::value< T >( get() ); } - // Get the JSON as a value, or a default if not there + // Get the JSON as a value, or a default if not there (throws if wrong type) template < class T > T default_value( T const & default_value ) const { return json::value< T >( get(), default_value ); } - // Get the object, with a default being an empty one - nlohmann::json const & default_object() const { return is_object() ? *_pj : empty_json_object; } + // Get the object, with a default being an empty one; does not throw + nlohmann::json const & default_object() const { return is_object() ? _j : empty_json_object; } + // Get the object, with a default being an empty one; does not throw + nlohmann::json const & default_string() const { return is_string() ? _j : empty_json_string; } // Get a JSON string by reference (zero copy); it must be a string or it'll throw inline std::string const & string_ref() const { return json::string_ref( get() ); } // Get a JSON string by reference (zero copy); does not throw - inline std::string const & string_ref_or_empty() const { return json::string_ref( exists() ? *_pj : empty_json_string ); } + inline std::string const & string_ref_or_empty() const { return json::string_ref( default_string() ); } };