From 83dd01e976b9a6c5ace2921e7064235370a6de8b Mon Sep 17 00:00:00 2001 From: Eran Date: Tue, 2 Apr 2024 10:31:03 +0300 Subject: [PATCH] add enum support in dds-adapter --- .../dds/dds-adapter/lrs-device-controller.cpp | 102 ++++++++++++++++-- 1 file changed, 92 insertions(+), 10 deletions(-) diff --git a/tools/dds/dds-adapter/lrs-device-controller.cpp b/tools/dds/dds-adapter/lrs-device-controller.cpp index 8aef35094e..90b59dfd88 100644 --- a/tools/dds/dds-adapter/lrs-device-controller.cpp +++ b/tools/dds/dds-adapter/lrs-device-controller.cpp @@ -126,6 +126,40 @@ static std::string stream_name_from_rs2( rs2::sensor const & sensor ) } +std::vector< char const * > get_option_enum_values( rs2::sensor const & sensor, + rs2_option const opt, + rs2::option_range const & range, + float const current_value, + size_t * p_current_index, + size_t * p_default_index ) +{ + // Same logic as in Viewer's option-model... + if( range.step < 0.9f ) + return {}; + + size_t current_index = 0, default_index = 0; + std::vector< const char * > labels; + for( auto i = range.min; i <= range.max; i += range.step ) + { + auto label = sensor.get_option_value_description( opt, i ); + if( ! label ) + return {}; // Missing value - not an enum + + if( std::fabs( i - current_value ) < 0.001f ) + current_index = labels.size(); + if( std::fabs( i - range.def ) < 0.001f ) + default_index = labels.size(); + + labels.push_back( label ); + } + if( p_current_index ) + *p_current_index = current_index; + if( p_default_index ) + *p_default_index = default_index; + return labels; +} + + static json json_from_roi( rs2::region_of_interest const & roi ) { return realdds::dds_rect_option::type{ roi.min_x, roi.min_y, roi.max_x, roi.max_y }.to_json(); @@ -286,20 +320,35 @@ std::vector< std::shared_ptr< realdds::dds_stream_server > > lrs_device_controll json j = json::array(); json props = json::array(); j += option_name; - json option_value; // null - no value + // Even read-only options have ranges in librealsense + auto const range = sensor.get_option_range( option_id ); try { - option_value = sensor.get_option( option_id ); + // For now, assume (legacy) librealsense options are all floats + float option_value = sensor.get_option( option_id ); // may throw + size_t current_index, default_index; + auto const values = get_option_enum_values( sensor, option_id, range, option_value, ¤t_index, &default_index ); + if( ! values.empty() ) + { + // Translate to enum + j += values[current_index]; + j += values; + j += values[default_index]; + } + else + { + j += option_value; + j += range.min; + j += range.max; + j += range.step; + j += range.def; + } } catch( ... ) { // Some options can be queried only if certain conditions exist skip them for now props += "optional"; - } - j += option_value; - { - // Even read-only options have ranges in librealsense - auto const range = sensor.get_option_range( option_id ); + j += rsutils::null_json; j += range.min; j += range.max; j += range.step; @@ -326,7 +375,7 @@ std::vector< std::shared_ptr< realdds::dds_stream_server > > lrs_device_controll // AE ROI is exposed as an interface in the librealsense API and through a "Region of Interest" // rectangle option in DDS json j = json::array(); - j += "Region of Interest"; + j += rs2_option_to_string( RS2_OPTION_REGION_OF_INTEREST ); json option_value; // null - no value try { @@ -731,7 +780,10 @@ lrs_device_controller::lrs_device_controller( rs2::device dev, std::shared_ptr< switch( changed_option->type ) { case RS2_OPTION_TYPE_FLOAT: - value = changed_option->as_float; + if( auto e = std::dynamic_pointer_cast< realdds::dds_enum_option >( dds_option ) ) + value = e->get_choices().at( int( changed_option->as_float ) ); + else + value = changed_option->as_float; break; case RS2_OPTION_TYPE_STRING: value = changed_option->as_string; @@ -919,7 +971,37 @@ void lrs_device_controller::set_option( const std::shared_ptr< realdds::dds_opti } else { - sensor.set_option( option_name_to_id( option->get_name() ), new_value ); + // The librealsense API uses floats, so we need to convert from non-floats + float float_value; + switch( new_value.type() ) + { + case json::value_t::number_float: + case json::value_t::number_integer: + case json::value_t::number_unsigned: + float_value = new_value; + break; + + case json::value_t::boolean: + float_value = new_value.get< bool >(); + break; + + case json::value_t::string: + // Only way is for this to be an enum... + if( auto e = std::dynamic_pointer_cast< realdds::dds_enum_option >( option ) ) + { + auto const & choices = e->get_choices(); + auto it = std::find( choices.begin(), choices.end(), new_value.string_ref() ); + if( it == choices.end() ) + throw std::runtime_error( rsutils::string::from() << "not a valid enum value: " << new_value ); + float_value = float( it - choices.begin() ); + break; + } + // fall thru + default: + throw std::runtime_error( rsutils::string::from() << "unsupported value: " << new_value ); + } + + sensor.set_option( option_name_to_id( option->get_name() ), float_value ); } }