Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 51 additions & 2 deletions src/dds/rs-dds-device-proxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <src/environment.h>

#include <rsutils/json.h>
#include <rsutils/string/hexarray.h>


namespace librealsense {
Expand Down Expand Up @@ -486,8 +487,56 @@ void dds_device_proxy::hardware_reset()
std::string default_status( "OK", 2 );
if( rsutils::json::get( reply, "status", default_status ) != default_status )
throw std::runtime_error( "Failed to reset: "
+ rsutils::json::get( reply, "status", std::string( "unknown reason" ) ) );
+ rsutils::json::get( reply, "explanation", std::string( "unknown reason" ) ) );
}


} // namespace librealsense
std::vector< uint8_t > dds_device_proxy::send_receive_raw_data( const std::vector< uint8_t > & input )
{
// debug_interface function
auto hexdata = rsutils::string::hexarray::to_string( input );
nlohmann::json control = nlohmann::json::object( { { "id", "hwm" }, { "data", hexdata } } );
nlohmann::json reply;
_dds_dev->send_control( control, &reply );
std::string default_status( "OK", 2 );
if( rsutils::json::get( reply, "status", default_status ) != default_status )
throw std::runtime_error( "Failed HWM: "
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't there an `explanation`` field in case of failure?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's what it's supposed to be getting in the next line... I copy-pasted, maybe there's a bug somewhere else, too -- I'll check.

+ rsutils::json::get( reply, "explanation", std::string( "unknown reason" ) ) );
rsutils::string::hexarray data;
if( ! rsutils::json::get_ex( reply, "data", &data ) )
throw std::runtime_error( "Failed HWM: missing 'data' in reply" );
return data.detach();
}


std::vector< uint8_t > dds_device_proxy::build_command( uint32_t opcode,
uint32_t param1,
uint32_t param2,
uint32_t param3,
uint32_t param4,
uint8_t const * data,
size_t dataLength ) const
{
// debug_interface function
rsutils::string::hexarray hexdata( std::vector< uint8_t >( data, data + dataLength ) );
nlohmann::json control = nlohmann::json::object( { { "id", "hwm" },
{ "data", hexdata },
{ "opcode", opcode },
{ "param1", param1 },
{ "param2", param2 },
{ "param3", param3 },
{ "param4", param4 },
{ "build-command", true } } );
nlohmann::json reply;
_dds_dev->send_control( control, &reply );
std::string default_status( "OK", 2 );
if( rsutils::json::get( reply, "status", default_status ) != default_status )
throw std::runtime_error( "Failed build-command: "
+ rsutils::json::get( reply, "explanation", std::string( "unknown reason" ) ) );
if( ! rsutils::json::get_ex( reply, "data", &hexdata ) )
throw std::runtime_error( "Failed HWM: missing 'data' in reply" );
return hexdata.detach();
}


} // namespace librealsense
16 changes: 15 additions & 1 deletion src/dds/rs-dds-device-proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#pragma once

#include <src/software-device.h>
#include <src/core/debug.h>
#include "sid_index.h"

#include <memory>
Expand Down Expand Up @@ -34,7 +35,9 @@ class stream_profile_interface;
// auto dev2 = dev_list[0];
// dev1 and dev2 are two different rs2 devices, but they both go to the same DDS source!
//
class dds_device_proxy : public software_device
class dds_device_proxy
: public software_device
, public debug_interface
{
std::shared_ptr< realdds::dds_device > _dds_dev;
std::map< std::string, std::vector< std::shared_ptr< stream_profile_interface > > > _stream_name_to_profiles;
Expand All @@ -60,6 +63,17 @@ class dds_device_proxy : public software_device
void tag_profiles( stream_profiles profiles ) const override;

void hardware_reset() override;

// debug_interface
private:
std::vector< uint8_t > send_receive_raw_data( const std::vector< uint8_t > & ) override;
std::vector< uint8_t > build_command( uint32_t opcode,
uint32_t param1 = 0,
uint32_t param2 = 0,
uint32_t param3 = 0,
uint32_t param4 = 0,
uint8_t const * data = nullptr,
size_t dataLength = 0 ) const override;
};


Expand Down
4 changes: 1 addition & 3 deletions src/ds/d500/d500-factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,9 @@ class d555e_device
std::shared_ptr< matcher > create_matcher( const frame_holder & frame ) const override
{
std::vector<stream_interface *> streams = { _depth_stream.get() , _left_ir_stream.get() , _right_ir_stream.get(), _color_stream.get() };
#if 0
std::vector<stream_interface *> mm_streams = { _ds_motion_common->get_accel_stream().get(),
_ds_motion_common->get_gyro_stream().get() };
_ds_motion_common->get_gyro_stream().get() };
streams.insert( streams.end(), mm_streams.begin(), mm_streams.end() );
#endif
return matcher_factory::create( RS2_MATCHER_DEFAULT, streams );
}

Expand Down
4 changes: 2 additions & 2 deletions src/hw-monitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,13 +206,13 @@ namespace librealsense
newCommand.receivedCommandData + newCommand.receivedCommandDataLength);
}

std::vector<uint8_t> hw_monitor::build_command(uint32_t opcode,
/*static*/ std::vector<uint8_t> hw_monitor::build_command(uint32_t opcode,
uint32_t param1,
uint32_t param2,
uint32_t param3,
uint32_t param4,
uint8_t const * data,
size_t dataLength) const
size_t dataLength)
{
int length;
std::vector<uint8_t> result;
Expand Down
4 changes: 2 additions & 2 deletions src/hw-monitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -339,13 +339,13 @@ namespace librealsense

virtual std::vector<uint8_t> send( std::vector<uint8_t> const & data ) const;
virtual std::vector<uint8_t> send( command cmd, hwmon_response * = nullptr, bool locked_transfer = false ) const;
std::vector<uint8_t> build_command(uint32_t opcode,
static std::vector<uint8_t> build_command(uint32_t opcode,
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we need this as static?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In the beginning, I had the build-command code directly call the hw-monitor, but there is no hw-monitor object in the DDS device. So how can you build a command?

Later I decided I didn't want the DDS code to even know what a hardware monitor is, and that we shouldn't assume to know how a device builds its commands, so I removed the hw-monitor references but this stayed.

Currently, I think it's fine making it static as internally that's how it implemented (it calls a static function). Otherwise we would have to turn it into a virtual function and do some other work. I think that it's valid to go that way, but in a different PR and only if needed.

uint32_t param1 = 0,
uint32_t param2 = 0,
uint32_t param3 = 0,
uint32_t param4 = 0,
uint8_t const * data = nullptr,
size_t dataLength = 0) const;
size_t dataLength = 0);

void get_gvd(size_t sz, unsigned char* gvd, uint8_t gvd_cmd) const;
static std::string get_firmware_version_string(const std::vector<uint8_t>& buff, size_t index, size_t length = 4);
Expand Down
12 changes: 11 additions & 1 deletion third-party/realdds/doc/control.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ A [disconnection event](discovery.md#disconnection) can be expected if the reply

Can be used to send internal commands to the hardware and may brick the device if used. May or may not be implemented, and is not documented.

* `opcode` (string) is suggested, but optional
* `data` is required

It is up to the server to validate and make sure everything is as expected.
Expand Down Expand Up @@ -143,6 +142,17 @@ A reply can be expected. Attaching the control is recommended so it's clear what
}
```

#### A more verbose method

You may also instruct the server to **build the HWM** command if you have knowledge of the available opcodes and data needed:

* `opcode` (string) is required
* `param1`, `param2`, `param3`, `param4` are all 32-bit integers whose meaning depends on the `opcode`, and with a default of `0`
* The `data` field, in this case, points to the command data, if needed, and becomes part of the generated HWM

If an optional `build-command` field is present and `true`, then the reply `data` will contain the generated HWM command **without running it**.


#### `hexarray` type

A `hexarray` is a special encoding for a `bytearray`, or array of bytes, in JSON.
Expand Down
4 changes: 2 additions & 2 deletions third-party/realdds/scripts/topic-send.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from argparse import ArgumentTypeError as ArgumentError # NOTE: only ArgumentTypeError passes along the original error string
args = ArgumentParser()
args.add_argument( '--debug', action='store_true', help='enable debug mode' )
args.add_argument( '--quiet', action='store_true', help='No output; just the minimum FPS as a number' )
args.add_argument( '--quiet', action='store_true', help='no output' )
args.add_argument( '--device', metavar='<path>', help='the topic root for the device' )
args.add_argument( '--topic', metavar='<path>', help='the topic on which to send flexible message, if --device is not supplied' )
import json
Expand Down Expand Up @@ -51,7 +51,7 @@ def e( *a, **kw ):
info = dds.message.device_info()
info.name = 'Dummy Device'
info.topic_root = args.device
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
3 changes: 3 additions & 0 deletions third-party/realdds/src/dds-device-impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ static std::string const control_key( "control", 7 );
static std::string const id_log( "log", 3 );
static std::string const entries_key( "entries", 7 );

static std::string const id_hwm( "hwm", 3 );


namespace realdds {

Expand Down Expand Up @@ -105,6 +107,7 @@ void dds_device::impl::set_state( state_t new_state )
{ id_stream_options, &dds_device::impl::on_stream_options },
{ id_open_streams, &dds_device::impl::on_known_notification },
{ id_log, &dds_device::impl::on_log },
{ id_hwm, &dds_device::impl::on_known_notification },
};


Expand Down
45 changes: 45 additions & 0 deletions tools/dds/dds-adapter/lrs-device-controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

#include <rsutils/easylogging/easyloggingpp.h>
#include <rsutils/json.h>
#include <rsutils/string/hexarray.h>
using rsutils::string::hexarray;

#include <realdds/topics/image-msg.h>
#include <realdds/topics/imu-msg.h>
Expand Down Expand Up @@ -842,6 +844,7 @@ bool lrs_device_controller::on_control( std::string const & id, nlohmann::json c
control_handlers{
{ "hw-reset", &lrs_device_controller::on_hardware_reset },
{ "open-streams", &lrs_device_controller::on_open_streams },
{ "hwm", &lrs_device_controller::on_hwm },
};
auto it = control_handlers.find( id );
if( it == control_handlers.end() )
Expand All @@ -858,3 +861,45 @@ bool lrs_device_controller::on_hardware_reset( nlohmann::json const & control, n
}


bool lrs_device_controller::on_hwm( nlohmann::json const & control, nlohmann::json & reply )
{
rs2::debug_protocol dp( _rs_dev );
if( ! dp )
throw std::runtime_error( "device does not have a debug protocol implemented" );

rsutils::string::hexarray data;

uint32_t opcode;
if( rsutils::json::get_ex( control, "opcode", &opcode ) )
{
// In the presence of 'opcode', we're asked to build the command using optional parameters
uint32_t param1 = 0, param2 = 0, param3 = 0, param4 = 0;
rsutils::json::get_ex( control, "param1", &param1 );
rsutils::json::get_ex( control, "param2", &param2 );
rsutils::json::get_ex( control, "param3", &param3 );
rsutils::json::get_ex( control, "param4", &param4 );

rsutils::json::get_ex( control, "data", &data ); // optional

// Build the HWM command
data = dp.build_command( opcode, param1, param2, param3, param4, data.get_bytes() );

// And, if told to not actually run it, we return the HWM command
if( rsutils::json::get< bool >( control, "build-command", false ) )
{
reply["data"] = data;
return true;
}
}
else
{
if( ! rsutils::json::get_ex( control, "data", &data ) )
throw std::runtime_error( "no 'data' in HWM control" );
}

data = dp.send_and_receive_raw_data( data.get_bytes() );
reply["data"] = data;
return true;
}


1 change: 1 addition & 0 deletions tools/dds/dds-adapter/lrs-device-controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class lrs_device_controller

bool on_control( std::string const & id, nlohmann::json const & control, nlohmann::json & reply );
bool on_hardware_reset( nlohmann::json const &, nlohmann::json & );
bool on_hwm( nlohmann::json const &, nlohmann::json & );
bool on_open_streams( nlohmann::json const &, nlohmann::json & );

void override_default_profiles( const std::map< std::string, realdds::dds_stream_profiles > & stream_name_to_profiles,
Expand Down
65 changes: 55 additions & 10 deletions tools/terminal/rs-terminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
#include "parser.hpp"
#include "auto-complete.h"

#include <nlohmann/json.hpp>
#include <thread>


using namespace std;
using namespace TCLAP;
Expand Down Expand Up @@ -162,44 +165,86 @@ rs2::device wait_for_device(const rs2::device_hub& hub, bool print_info = true)
int main(int argc, char** argv)
{
CmdLine cmd("librealsense rs-terminal tool", ' ', RS2_API_VERSION_STR);
SwitchArg debug_arg( "", "debug", "Turn on LibRS debug logs" );
ValueArg<string> xml_arg("l", "load", "Full file path of commands XML file", false, "", "Load commands XML file");
ValueArg<int> device_id_arg("d", "deviceId", "Device ID could be obtain from rs-enumerate-devices example", false, 0, "Select a device to work with");
ValueArg<string> specific_SN_arg("n", "serialNum", "Serial Number can be obtain from rs-enumerate-devices example", false, "", "Select a device serial number to work with");
SwitchArg all_devices_arg("a", "allDevices", "Do this command to all attached Realsense Devices", false);
ValueArg<string> hex_cmd_arg("s", "send", "Hexadecimal raw data", false, "", "Send hexadecimal raw data to device");
ValueArg<string> hex_script_arg("r", "raw", "Full file path of hexadecimal raw data script", false, "", "Send raw data line by line from script file");
ValueArg<string> commands_script_arg("c", "cmd", "Full file path of commands script", false, "", "Send commands line by line from script file");
SwitchArg only_sw_arg( "", "sw-only", "Show only software devices (playback, DDS, etc. -- but not USB/HID/etc.)" );
cmd.add(debug_arg);
cmd.add(xml_arg);
cmd.add(device_id_arg);
cmd.add(specific_SN_arg);
cmd.add(all_devices_arg);
cmd.add(hex_cmd_arg);
cmd.add(hex_script_arg);
cmd.add(commands_script_arg);
cmd.add(only_sw_arg);
#ifdef BUILD_WITH_DDS
ValueArg< int > domain_arg( "", "dds-domain", "Set the DDS domain ID (default to 0)", false, 0, "0-232" );
cmd.add( domain_arg );
#endif
cmd.parse(argc, argv);

#ifdef BUILD_EASYLOGGINGPP
bool debugging = debug_arg.getValue();
rs2::log_to_console( debugging ? RS2_LOG_SEVERITY_DEBUG : RS2_LOG_SEVERITY_ERROR );
#endif

// parse command.xml
rs2::log_to_file(RS2_LOG_SEVERITY_WARN, "librealsense.log");

nlohmann::json settings;
#ifdef BUILD_WITH_DDS
nlohmann::json dds;
dds["domain"] = domain_arg.getValue();
settings["dds"] = std::move( dds );
#endif
if( only_sw_arg.getValue() )
settings["device-mask"] = RS2_PRODUCT_LINE_SW_ONLY | RS2_PRODUCT_LINE_ANY;

// Obtain a list of devices currently present on the system
rs2::context ctx = rs2::context();
rs2::context ctx( settings.dump() );
rs2::device_hub hub(ctx);
rs2::device_list all_device_list = ctx.query_devices();
if( only_sw_arg.getValue() )
{
// For SW-only devices, allow some time for DDS devices to connect
int tries = 5;
cout << "No device detected. Waiting..." << flush;
while( ! all_device_list.size() && tries-- )
{
cout << "." << flush;
std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
all_device_list = ctx.query_devices();
}
cout << endl;
}
if (all_device_list.size() == 0) {
std::cout << "\nLibrealsense is not detecting any devices" << std::endl;
return EXIT_FAILURE;
};

std::vector<rs2::device> rs_device_list;
//Ensure that diviceList only has realsense devices in it. tmpList contains webcams as well
for (uint32_t i = 0; i < all_device_list.size(); i++) {
try {
all_device_list[i].get_info(RS2_CAMERA_INFO_FIRMWARE_VERSION);
rs_device_list.push_back(all_device_list[i]);
}
catch (...) {
continue;
// Ensure that deviceList only has realsense devices in it. tmpList contains webcams as well
if( only_sw_arg.getValue() )
{
rs_device_list = all_device_list;
}
else
{
for (uint32_t i = 0; i < all_device_list.size(); i++) {
try {
all_device_list[i].get_info(RS2_CAMERA_INFO_FIRMWARE_VERSION);
rs_device_list.push_back(all_device_list[i]);
}
catch (...) {
continue;
}
}

}
auto num_rs_devices = rs_device_list.size();
if (rs_device_list.size() == 0) {
Expand Down