Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JSON-based device-info & fix for no 'dds' settings #12540

Merged
merged 12 commits into from
Jan 1, 2024
Merged
42 changes: 42 additions & 0 deletions include/librealsense2/hpp/rs_device.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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: "[<type>] <name> s/n <#>"
*/
std::string get_description() const
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we need a C API corresponding to all CPP APIs?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so, though we could certainly do it -- this only sits at the top of the hourglass

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to Evgeni we need to be able to do in C whatever we do in CPP.
The APIs should be synchronized and the CPP just a wrapper to the C

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But it is: this is using the C APIs. I am not adding another API here. I am making the code reusable. Are you suggesting I add yet another API that does this inside librealsense?

{
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<class T>
T first() const
{
Expand Down
12 changes: 2 additions & 10 deletions src/dds/rs-dds-device-info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
}


Expand Down
23 changes: 18 additions & 5 deletions src/dds/rs-dds-device-proxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/dds/rs-dds-sensor-proxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
39 changes: 23 additions & 16 deletions src/dds/rsdds-device-factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,23 +83,22 @@ 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.exists()
|| 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 "
Expand Down Expand Up @@ -145,15 +144,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 ) )
{
Expand Down
2 changes: 1 addition & 1 deletion third-party/realdds/include/realdds/dds-device.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 );

Expand Down
28 changes: 18 additions & 10 deletions third-party/realdds/include/realdds/topics/device-info-msg.h
Original file line number Diff line number Diff line change
@@ -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 <nlohmann/json_fwd.hpp>
#include <nlohmann/json.hpp>

#include <rsutils/string/slice.h>

Expand All @@ -12,15 +11,24 @@ 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;

nlohmann::json to_json() const;
static device_info from_json( nlohmann::json const & j );
//std::string serial;
//std::string product_line;
//bool locked = true;

std::string const & name() const;
void set_name( std::string const & );

std::string const & topic_root() const;
void set_topic_root( std::string const & );

std::string const & serial_number() const;
void set_serial_number( std::string const & );

nlohmann::json const & to_json() const;
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)
Expand Down
27 changes: 8 additions & 19 deletions third-party/realdds/py/pyrealdds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
} );
Expand Down Expand Up @@ -909,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",
Expand Down Expand Up @@ -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();
Expand Down
2 changes: 2 additions & 0 deletions third-party/realdds/scripts/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 )

Expand Down
2 changes: 1 addition & 1 deletion third-party/realdds/scripts/fps.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion third-party/realdds/src/dds-device-broadcaster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() );
}
}

Expand Down
18 changes: 9 additions & 9 deletions third-party/realdds/src/dds-device-impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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() )
Expand Down Expand Up @@ -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" );

Expand Down Expand Up @@ -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'" );
Expand All @@ -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 )
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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]()
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion third-party/realdds/src/dds-device-impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading
Loading