diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a99f0b0991..4920d54a94 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -66,6 +66,8 @@ target_sources(${LRS_TARGET} "${CMAKE_CURRENT_LIST_DIR}/algo.cpp" "${CMAKE_CURRENT_LIST_DIR}/archive.cpp" "${CMAKE_CURRENT_LIST_DIR}/backend.cpp" + "${CMAKE_CURRENT_LIST_DIR}/backend-device-factory.cpp" + "${CMAKE_CURRENT_LIST_DIR}/backend-device-factory.h" "${CMAKE_CURRENT_LIST_DIR}/context.cpp" "${CMAKE_CURRENT_LIST_DIR}/device.cpp" "${CMAKE_CURRENT_LIST_DIR}/device-info.cpp" @@ -108,6 +110,8 @@ target_sources(${LRS_TARGET} "${CMAKE_CURRENT_LIST_DIR}/platform/hid-device.h" "${CMAKE_CURRENT_LIST_DIR}/platform/hid-device-info.h" "${CMAKE_CURRENT_LIST_DIR}/platform/playback-device-info.h" + "${CMAKE_CURRENT_LIST_DIR}/platform/platform-utils.h" + "${CMAKE_CURRENT_LIST_DIR}/platform/platform-utils.cpp" "${CMAKE_CURRENT_LIST_DIR}/platform/stream-profile.h" "${CMAKE_CURRENT_LIST_DIR}/core/time-service.h" "${CMAKE_CURRENT_LIST_DIR}/platform/uvc-device.h" diff --git a/src/backend-device-factory.cpp b/src/backend-device-factory.cpp new file mode 100644 index 0000000000..f6e5218e8f --- /dev/null +++ b/src/backend-device-factory.cpp @@ -0,0 +1,172 @@ +// License: Apache 2.0. See LICENSE file in root directory. +// Copyright(c) 2023 Intel Corporation. All Rights Reserved. + +#include "backend-device-factory.h" +#include "context.h" +#include "backend.h" +#include "platform/platform-device-info.h" +#include "platform/device-watcher.h" + +#include "ds/d400/d400-info.h" +#include "ds/d500/d500-info.h" +#include "fw-update/fw-update-factory.h" +#include "platform-camera.h" + +#include + + +namespace { + + +// Returns true if the left group is completely accounted for in the right group +// +bool group_contained_in( librealsense::platform::backend_device_group const & first_data, + librealsense::platform::backend_device_group const & second_data ) +{ + for( auto && uvc : first_data.uvc_devices ) + { + if( std::find( second_data.uvc_devices.begin(), second_data.uvc_devices.end(), uvc ) + == second_data.uvc_devices.end() ) + return false; + } + for( auto && usb : first_data.usb_devices ) + { + if( std::find( second_data.usb_devices.begin(), second_data.usb_devices.end(), usb ) + == second_data.usb_devices.end() ) + return false; + } + for( auto && hid : first_data.hid_devices ) + { + if( std::find( second_data.hid_devices.begin(), second_data.hid_devices.end(), hid ) + == second_data.hid_devices.end() ) + return false; + } + return true; +} + + +std::vector< std::shared_ptr< librealsense::platform::platform_device_info > > +subtract_sets( const std::vector< std::shared_ptr< librealsense::platform::platform_device_info > > & first, + const std::vector< std::shared_ptr< librealsense::platform::platform_device_info > > & second ) +{ + std::vector< std::shared_ptr< librealsense::platform::platform_device_info > > results; + std::for_each( + first.begin(), + first.end(), + [&]( std::shared_ptr< librealsense::platform::platform_device_info > const & data ) + { + if( std::find_if( + second.begin(), + second.end(), + [&]( std::shared_ptr< librealsense::platform::platform_device_info > const & new_dev ) + { + return group_contained_in( data->get_group(), new_dev->get_group() ); + } ) + == second.end() ) + { + results.push_back( data ); + } + } ); + return results; +} + + +} // namespace + + +namespace librealsense { + + +backend_device_factory::backend_device_factory( context & ctx, callback && cb ) + : _device_watcher( ctx.get_backend().create_device_watcher() ) + , _context( ctx ) +{ + assert( _device_watcher->is_stopped() ); + _device_watcher->start( + [this, cb = std::move( cb )]( platform::backend_device_group const & old, + platform::backend_device_group const & curr ) + { + auto old_list = create_devices_from_group( old, RS2_PRODUCT_LINE_ANY ); + auto new_list = create_devices_from_group( curr, RS2_PRODUCT_LINE_ANY ); + + std::vector< rs2_device_info > devices_removed; + for( auto & device_removed : subtract_sets( old_list, new_list ) ) + { + devices_removed.push_back( { _context.shared_from_this(), device_removed } ); + LOG_DEBUG( "Device disconnected: " << device_removed->get_address() ); + } + + std::vector< rs2_device_info > devices_added; + for( auto & device_added : subtract_sets( new_list, old_list ) ) + { + devices_added.push_back( { _context.shared_from_this(), device_added } ); + LOG_DEBUG( "Device connected: " << device_added->get_address() ); + } + + if( devices_removed.size() + devices_added.size() ) + { + cb( devices_removed, devices_added ); + } + } ); +} + + +backend_device_factory::~backend_device_factory() +{ + if( _device_watcher ) + _device_watcher->stop(); +} + + +std::vector< std::shared_ptr< device_info > > backend_device_factory::query_devices( unsigned requested_mask ) const +{ + if( (requested_mask & RS2_PRODUCT_LINE_SW_ONLY) || (_context.get_device_mask() & RS2_PRODUCT_LINE_SW_ONLY) ) + return {}; // We don't carry any software devices + + auto & backend = _context.get_backend(); + platform::backend_device_group group( backend.query_uvc_devices(), + backend.query_usb_devices(), + backend.query_hid_devices() ); + auto devices = create_devices_from_group( group, requested_mask ); + return { devices.begin(), devices.end() }; +} + + +std::vector< std::shared_ptr< platform::platform_device_info > > +backend_device_factory::create_devices_from_group( platform::backend_device_group devices, int requested_mask ) const +{ + std::vector< std::shared_ptr< platform::platform_device_info > > list; + unsigned const mask = context::combine_device_masks( requested_mask, _context.get_device_mask() ); + if( ! ( mask & RS2_PRODUCT_LINE_SW_ONLY ) ) + { + if( mask & RS2_PRODUCT_LINE_D400 ) + { + auto d400_devices = d400_info::pick_d400_devices( _context.shared_from_this(), devices ); + std::copy( std::begin( d400_devices ), end( d400_devices ), std::back_inserter( list ) ); + } + + if( mask & RS2_PRODUCT_LINE_D500 ) + { + auto d500_devices = d500_info::pick_d500_devices( _context.shared_from_this(), devices ); + std::copy( begin( d500_devices ), end( d500_devices ), std::back_inserter( list ) ); + } + + // Supported recovery devices + { + auto recovery_devices + = fw_update_info::pick_recovery_devices( _context.shared_from_this(), devices.usb_devices, mask ); + std::copy( begin( recovery_devices ), end( recovery_devices ), std::back_inserter( list ) ); + } + + if( mask & RS2_PRODUCT_LINE_NON_INTEL ) + { + auto uvc_devices + = platform_camera_info::pick_uvc_devices( _context.shared_from_this(), devices.uvc_devices ); + std::copy( begin( uvc_devices ), end( uvc_devices ), std::back_inserter( list ) ); + } + } + return list; +} + + +} // namespace librealsense diff --git a/src/backend-device-factory.h b/src/backend-device-factory.h new file mode 100644 index 0000000000..43a490c9cc --- /dev/null +++ b/src/backend-device-factory.h @@ -0,0 +1,61 @@ +// License: Apache 2.0. See LICENSE file in root directory. +// Copyright(c) 2023 Intel Corporation. All Rights Reserved. + +#pragma once + +#include +#include +#include + + +struct rs2_device_info; + + +namespace librealsense { + + +class device_info; +class context; + + +namespace platform { +class device_watcher; +struct backend_device_group; +class platform_device_info; +} // namespace platform + + +// This factory creates "backend devices", or devices that require the backend to be detected and used. In other words, +// UVC devices. +// +// The factory abstracts away platform-specific concepts such that all the user has to do is supply a callback to know +// when changes in the list of devices have been made. +// +// Any devices created here will have a device-info that derives from platform::platform_device_info. This factory +// manages these device-info objects such that lifetime is tracked and updated appropriately, without the caller's +// knowledge. +// +class backend_device_factory +{ + context & _context; + std::shared_ptr< platform::device_watcher > const _device_watcher; + + using callback = std::function< void( std::vector< rs2_device_info > & rs2_devices_info_removed, + std::vector< rs2_device_info > & rs2_devices_info_added ) >; + +public: + backend_device_factory( context &, callback && ); + ~backend_device_factory(); + + // Query any subset of available devices and return them as device-info objects + // Devices will match both the requested mask and the device-mask from the context settings + // + std::vector< std::shared_ptr< device_info > > query_devices( unsigned mask ) const; + +private: + std::vector< std::shared_ptr< platform::platform_device_info > > + create_devices_from_group( platform::backend_device_group, int mask ) const; +}; + + +} // namespace librealsense diff --git a/src/context.cpp b/src/context.cpp index df47baaa4f..85e34e313a 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -3,21 +3,9 @@ #include "context.h" -#include "ds/d400/d400-info.h" -#include "ds/d500/d500-info.h" -#include "device.h" -#include "ds/ds-timestamp.h" -#include #include "media/playback/playback-device-info.h" -#include "types.h" -#include "stream.h" #include "environment.h" -#include "fw-update/fw-update-factory.h" -#include "proc/color-formats-converter.h" -#include "platform-camera.h" #include -#include -#include "software-device.h" #ifdef BUILD_WITH_DDS @@ -51,79 +39,17 @@ static std::map< realdds::dds_domain_id, dds_domain_context > dds_domain_context #include using json = nlohmann::json; -namespace { - -template< class T > -bool contains( const T & first, const T & second ) -{ - return first == second; -} - -template<> -bool contains( librealsense::platform::backend_device_group const & first_data, - librealsense::platform::backend_device_group const & second_data ) -{ - for( auto && uvc : first_data.uvc_devices ) - { - if( std::find( second_data.uvc_devices.begin(), second_data.uvc_devices.end(), uvc ) - == second_data.uvc_devices.end() ) - return false; - } - for( auto && usb : first_data.usb_devices ) - { - if( std::find( second_data.usb_devices.begin(), second_data.usb_devices.end(), usb ) - == second_data.usb_devices.end() ) - return false; - } - for( auto && hid : first_data.hid_devices ) - { - if( std::find( second_data.hid_devices.begin(), second_data.hid_devices.end(), hid ) - == second_data.hid_devices.end() ) - return false; - } - for( auto && pd : first_data.playback_devices ) - { - if( std::find( second_data.playback_devices.begin(), second_data.playback_devices.end(), pd ) - == second_data.playback_devices.end() ) - return false; - } - return true; -} - -std::vector< std::shared_ptr< librealsense::device_info > > -subtract_sets( const std::vector< std::shared_ptr< librealsense::device_info > > & first, - const std::vector< std::shared_ptr< librealsense::device_info > > & second ) -{ - std::vector< std::shared_ptr< librealsense::device_info > > results; - std::for_each( - first.begin(), - first.end(), - [&]( std::shared_ptr< librealsense::device_info > const & data ) - { - if( std::find_if( - second.begin(), - second.end(), - [&]( std::shared_ptr< librealsense::device_info > const & new_dev ) - { - if( auto pnew = std::dynamic_pointer_cast< librealsense::platform::platform_device_info >( new_dev ) ) - if( auto pold = std::dynamic_pointer_cast( data ) ) - return contains( pold->get_group(), pnew->get_group() ); - return data->is_same_as( new_dev ); - } ) - == second.end() ) - { - results.push_back( data ); - } - } ); - return results; -} - -} // namespace - namespace librealsense { - context::context() - : _devices_changed_callback( nullptr, []( rs2_devices_changed_callback* ) {} ) + context::context( json const & settings ) + : _backend( platform::create_backend() ) + , _settings( settings ) + , _device_mask( rsutils::json::get< unsigned >( settings, "device-mask", RS2_PRODUCT_LINE_ANY ) ) + , _devices_changed_callback( nullptr, []( rs2_devices_changed_callback * ) {} ) + , _backend_device_factory( + *this, + [this]( std::vector< rs2_device_info > & removed, std::vector< rs2_device_info > & added ) + { invoke_devices_changed_callbacks( removed, added ); } ) { static bool version_logged = false; if( ! version_logged ) @@ -131,39 +57,8 @@ namespace librealsense version_logged = true; LOG_DEBUG( "Librealsense VERSION: " << RS2_API_VERSION_STR ); } - } - context::context( backend_type type ) - : context() - { - _backend = platform::create_backend(); -#ifdef BUILD_WITH_DDS - { - realdds::dds_domain_id domain_id = 0; - auto & domain = dds_domain_context_by_id[domain_id]; - _dds_participant = domain.participant.instance(); - if( ! _dds_participant->is_valid() ) - _dds_participant->init( domain_id, rsutils::os::executable_name(), {} ); - _dds_watcher = domain.device_watcher.instance( _dds_participant ); - } -#endif //BUILD_WITH_DDS - - _device_watcher = _backend->create_device_watcher(); - assert(_device_watcher->is_stopped()); - } - - - context::context( json const & settings ) - : context() - { - _settings = settings; - - _backend = platform::create_backend(); // standard type - - _device_watcher = _backend->create_device_watcher(); - assert( _device_watcher->is_stopped() ); - #ifdef BUILD_WITH_DDS nlohmann::json dds_settings = rsutils::json::get< nlohmann::json >( settings, std::string( "dds", 3 ), nlohmann::json::object() ); @@ -208,98 +103,66 @@ namespace librealsense context::~context() { - //ensure that the device watchers will stop before the _devices_changed_callback will be deleted - - if ( _device_watcher ) - _device_watcher->stop(); #ifdef BUILD_WITH_DDS if( _dds_watcher ) _dds_watcher->stop(); #endif //BUILD_WITH_DDS } - static unsigned calc_mask( nlohmann::json const & settings, unsigned requested_mask, unsigned * p_device_mask = nullptr ) + + /*static*/ unsigned context::combine_device_masks( unsigned const requested_mask, unsigned const mask_in_settings ) { - // The 'device-mask' in our settings can be used to disable certain device types from showing up in the context: - unsigned device_mask = RS2_PRODUCT_LINE_ANY; unsigned mask = requested_mask; - if( rsutils::json::get_ex( settings, "device-mask", &device_mask ) ) - { - // The normal bits enable, so enable only those that are on - mask &= device_mask & ~RS2_PRODUCT_LINE_SW_ONLY; - // But the above turned off the SW-only bits, so turn them back on again - if( (device_mask & RS2_PRODUCT_LINE_SW_ONLY) || (requested_mask & RS2_PRODUCT_LINE_SW_ONLY) ) - mask |= RS2_PRODUCT_LINE_SW_ONLY; - } - if( p_device_mask ) - *p_device_mask = device_mask; + // The normal bits enable, so enable only those that are on + mask &= mask_in_settings & ~RS2_PRODUCT_LINE_SW_ONLY; + // But the above turned off the SW-only bits, so turn them back on again + if( (mask_in_settings & RS2_PRODUCT_LINE_SW_ONLY) || (requested_mask & RS2_PRODUCT_LINE_SW_ONLY) ) + mask |= RS2_PRODUCT_LINE_SW_ONLY; return mask; } + std::vector> context::query_devices( int requested_mask ) const { - unsigned device_mask; - auto const mask = calc_mask( _settings, unsigned( requested_mask ), &device_mask ); - platform::backend_device_group devices; - if( ! ( mask & RS2_PRODUCT_LINE_SW_ONLY ) ) - { - devices.uvc_devices = _backend->query_uvc_devices(); - devices.usb_devices = _backend->query_usb_devices(); - devices.hid_devices = _backend->query_hid_devices(); - } - auto const list = create_devices( devices, _playback_devices, mask ); - LOG_INFO( "Found " << list.size() << " RealSense devices (mask 0x" << std::hex << mask << "= " << requested_mask - << " requested & " << device_mask << " from device-mask in settings)" << std::dec ); + auto list = _backend_device_factory.query_devices( requested_mask ); + query_software_devices( list, requested_mask ); + LOG_INFO( "Found " << list.size() << " RealSense devices (0x" << std::hex << requested_mask << " requested & 0x" + << get_device_mask() << " from device-mask in settings)" << std::dec ); for( auto & item : list ) LOG_INFO( "... " << item->get_address() ); return list; } - std::vector< std::shared_ptr< device_info > > - context::create_devices( platform::backend_device_group devices, - const std::map< std::string, std::weak_ptr< device_info > > & playback_devices, - int requested_mask ) const + + void context::query_software_devices( std::vector< std::shared_ptr< device_info > > & list, unsigned requested_mask ) const { - std::vector> list; - unsigned mask = calc_mask( _settings, requested_mask ); + unsigned mask = combine_device_masks( requested_mask, get_device_mask() ); - auto t = const_cast(this); // While generally a bad idea, we need to provide mutable reference to the devices + auto t = const_cast(this); // While generally a bad idea, we need to provide mutable reference to the devices // to allow them to modify context later on auto ctx = t->shared_from_this(); - if( mask & RS2_PRODUCT_LINE_D400 && ! ( mask & RS2_PRODUCT_LINE_SW_ONLY ) ) - { - auto d400_devices = d400_info::pick_d400_devices(ctx, devices); - std::copy(begin(d400_devices), end(d400_devices), std::back_inserter(list)); - } - - if( mask & RS2_PRODUCT_LINE_D500 && ! ( mask & RS2_PRODUCT_LINE_SW_ONLY ) ) - { - auto d500_devices = d500_info::pick_d500_devices( ctx, devices ); - std::copy( begin( d500_devices ), end( d500_devices ), std::back_inserter( list ) ); - } - #ifdef BUILD_WITH_DDS if( _dds_watcher ) _dds_watcher->foreach_device( [&]( std::shared_ptr< realdds::dds_device > const & dev ) -> bool { - if( ! dev->is_ready() ) + if( !dev->is_ready() ) { LOG_DEBUG( "device '" << dev->device_info().debug_name() << "' is not yet ready" ); return true; } if( dev->device_info().product_line == "D400" ) { - if( ! ( mask & RS2_PRODUCT_LINE_D400 ) ) + if( !(mask & RS2_PRODUCT_LINE_D400) ) return true; } else if( dev->device_info().product_line == "D500" ) { - if( ! ( mask & RS2_PRODUCT_LINE_D500 ) ) + if( !(mask & RS2_PRODUCT_LINE_D500) ) return true; } - else if( ! ( mask & RS2_PRODUCT_LINE_NON_INTEL ) ) + else if( !(mask & RS2_PRODUCT_LINE_NON_INTEL) ) { return true; } @@ -310,65 +173,14 @@ namespace librealsense } ); #endif //BUILD_WITH_DDS - // Supported recovery devices - if( ( ( mask & RS2_PRODUCT_LINE_D400 ) || ( mask & RS2_PRODUCT_LINE_D500 ) ) - && ! ( mask & RS2_PRODUCT_LINE_SW_ONLY ) ) + for( auto && item : _playback_devices ) { - auto recovery_devices = fw_update_info::pick_recovery_devices(ctx, devices.usb_devices, mask); - std::copy(begin(recovery_devices), end(recovery_devices), std::back_inserter(list)); + if( auto dev = item.second.lock() ) + list.push_back( dev ); } - - if( mask & RS2_PRODUCT_LINE_NON_INTEL && ! ( mask & RS2_PRODUCT_LINE_SW_ONLY ) ) - { - auto uvc_devices = platform_camera_info::pick_uvc_devices(ctx, devices.uvc_devices); - std::copy(begin(uvc_devices), end(uvc_devices), std::back_inserter(list)); - } - - for (auto&& item : playback_devices) - { - if (auto dev = item.second.lock()) - list.push_back(dev); - } - - return list; } - void context::on_device_changed(platform::backend_device_group old, - platform::backend_device_group curr, - const std::map>& old_playback_devices, - const std::map>& new_playback_devices) - { - auto old_list = create_devices(old, old_playback_devices, RS2_PRODUCT_LINE_ANY); - auto new_list = create_devices(curr, new_playback_devices, RS2_PRODUCT_LINE_ANY); - - if( librealsense::list_changed< std::shared_ptr< device_info > >( - old_list, - new_list, - []( std::shared_ptr< device_info > first, std::shared_ptr< device_info > second ) - { return first->is_same_as( second ); } ) ) - { - std::vector rs2_devices_info_removed; - - auto devices_info_removed = subtract_sets(old_list, new_list); - for (size_t i = 0; i < devices_info_removed.size(); i++) - { - rs2_devices_info_removed.push_back({ shared_from_this(), devices_info_removed[i] }); - LOG_DEBUG( "Device disconnected: " << devices_info_removed[i]->get_address() ); - } - - std::vector rs2_devices_info_added; - auto devices_info_added = subtract_sets(new_list, old_list); - for (size_t i = 0; i < devices_info_added.size(); i++) - { - rs2_devices_info_added.push_back({ shared_from_this(), devices_info_added[i] }); - LOG_DEBUG( "Device connected: " << devices_info_added[i]->get_address() ); - } - - invoke_devices_changed_callbacks( rs2_devices_info_removed, rs2_devices_info_added ); - } - } - void context::invoke_devices_changed_callbacks( std::vector & rs2_devices_info_removed, std::vector & rs2_devices_info_added ) { @@ -414,13 +226,6 @@ namespace librealsense } } - void context::start_device_watcher() - { - _device_watcher->start([this](platform::backend_device_group old, platform::backend_device_group curr) - { - on_device_changed(old, curr, _playback_devices, _playback_devices); - }); - } #ifdef BUILD_WITH_DDS void context::start_dds_device_watcher() @@ -450,11 +255,6 @@ namespace librealsense std::lock_guard lock(_devices_changed_callbacks_mtx); auto callback_id = unique_id::generate_id(); _devices_changed_callbacks.insert(std::make_pair(callback_id, std::move(callback))); - - if (_device_watcher->is_stopped()) - { - start_device_watcher(); - } return callback_id; } @@ -462,77 +262,12 @@ namespace librealsense { std::lock_guard lock(_devices_changed_callbacks_mtx); _devices_changed_callbacks.erase(cb_id); - - if (_devices_changed_callback == nullptr && _devices_changed_callbacks.size() == 0) // There are no register callbacks any more _device_watcher can be stopped - { - _device_watcher->stop(); - } } void context::set_devices_changed_callback(devices_changed_callback_ptr callback) { std::lock_guard lock(_devices_changed_callbacks_mtx); _devices_changed_callback = std::move(callback); - - if (_device_watcher->is_stopped()) - { - start_device_watcher(); - } - } - - std::vector filter_by_product(const std::vector& devices, const std::set& pid_list) - { - std::vector result; - for (auto&& info : devices) - { - if (pid_list.count(info.pid)) - result.push_back(info); - } - return result; - } - - // TODO: Make template - std::vector filter_by_product(const std::vector& devices, const std::set& pid_list) - { - std::vector result; - for (auto&& info : devices) - { - if (pid_list.count(info.pid)) - result.push_back(info); - } - return result; - } - - std::vector, std::vector>> group_devices_and_hids_by_unique_id( - const std::vector>& devices, - const std::vector& hids) - { - std::vector, std::vector>> results; - uint16_t vid; - uint16_t pid; - - for (auto&& dev : devices) - { - std::vector hid_group; - auto unique_id = dev.front().unique_id; - auto device_serial = dev.front().serial; - - for (auto&& hid : hids) - { - if( ! hid.unique_id.empty() ) - { - std::stringstream(hid.vid) >> std::hex >> vid; - std::stringstream(hid.pid) >> std::hex >> pid; - - if (hid.unique_id == unique_id) - { - hid_group.push_back(hid); - } - } - } - results.push_back(std::make_pair(dev, hid_group)); - } - return results; } std::shared_ptr context::add_device(const std::string& file) @@ -545,9 +280,12 @@ namespace librealsense << "File \"" << file << "\" already loaded to context" ); } auto dinfo = std::make_shared< playback_device_info >( shared_from_this(), file ); - auto prev_playback_devices = _playback_devices; _playback_devices[file] = dinfo; - on_device_changed({}, {}, prev_playback_devices, _playback_devices); + + std::vector< rs2_device_info > rs2_device_info_added{ { shared_from_this(), dinfo } }; + std::vector< rs2_device_info > rs2_device_info_removed; + invoke_devices_changed_callbacks( rs2_device_info_removed, rs2_device_info_added ); + return dinfo; } @@ -558,95 +296,27 @@ namespace librealsense auto it = _playback_devices.find(address); if (it != _playback_devices.end() && it->second.lock()) throw librealsense::invalid_value_exception( "File \"" + address + "\" already loaded to context" ); - auto prev_playback_devices = _playback_devices; _playback_devices[address] = dev; - on_device_changed({}, {}, prev_playback_devices, _playback_devices); + + std::vector< rs2_device_info > rs2_device_info_added{ { shared_from_this(), dev } }; + std::vector< rs2_device_info > rs2_device_info_removed; + invoke_devices_changed_callbacks( rs2_device_info_removed, rs2_device_info_added ); } void context::remove_device(const std::string& file) { auto it = _playback_devices.find(file); - if(it == _playback_devices.end() || !it->second.lock()) - { - //Not found + if(it == _playback_devices.end() ) return; - } - auto prev_playback_devices =_playback_devices; + auto dev_info = it->second.lock(); _playback_devices.erase(it); - on_device_changed({},{}, prev_playback_devices, _playback_devices); - } - std::vector> group_devices_by_unique_id(const std::vector& devices) - { - std::map> map; - for (auto&& info : devices) + if( dev_info ) { - map[info.unique_id].push_back(info); - } - std::vector> result; - for (auto&& kvp : map) - { - result.push_back(kvp.second); - } - return result; - } - - // TODO: Sergey - // Make template - void trim_device_list(std::vector& devices, const std::vector& chosen) - { - if (chosen.empty()) - return; - - auto was_chosen = [&chosen](const platform::usb_device_info& info) - { - return find(chosen.begin(), chosen.end(), info) != chosen.end(); - }; - devices.erase(std::remove_if(devices.begin(), devices.end(), was_chosen), devices.end()); - } - - void trim_device_list(std::vector& devices, const std::vector& chosen) - { - if (chosen.empty()) - return; - - auto was_chosen = [&chosen](const platform::uvc_device_info& info) - { - return find(chosen.begin(), chosen.end(), info) != chosen.end(); - }; - devices.erase(std::remove_if(devices.begin(), devices.end(), was_chosen), devices.end()); - } - - bool mi_present(const std::vector& devices, uint32_t mi) - { - for (auto&& info : devices) - { - if (info.mi == mi) - return true; - } - return false; - } - - platform::uvc_device_info get_mi(const std::vector& devices, uint32_t mi) - { - for (auto&& info : devices) - { - if (info.mi == mi) - return info; + std::vector< rs2_device_info > rs2_device_info_added; + std::vector< rs2_device_info > rs2_device_info_removed{ { shared_from_this(), dev_info } }; + invoke_devices_changed_callbacks( rs2_device_info_removed, rs2_device_info_added ); } - throw invalid_value_exception("Interface not found!"); } - std::vector filter_by_mi(const std::vector& devices, uint32_t mi) - { - std::vector results; - for (auto&& info : devices) - { - if (info.mi == mi) - results.push_back(info); - } - return results; - } } - -using namespace librealsense; diff --git a/src/context.h b/src/context.h index c8158f612d..1109b323a4 100644 --- a/src/context.h +++ b/src/context.h @@ -3,23 +3,21 @@ #pragma once -#include "core/streaming.h" - +#include "backend-device-factory.h" #include "device-info.h" -#include "platform/device-watcher.h" +#include "types.h" +#include #include #include -#include - - -#include +#include namespace librealsense { class context; class device_info; + class stream_profile_interface; } struct rs2_device_info @@ -54,11 +52,7 @@ namespace librealsense class device; class context; class playback_device_info; - - enum class backend_type - { - standard - }; + class stream_interface; namespace platform { class backend; @@ -69,13 +63,23 @@ namespace librealsense { context(); public: - explicit context( backend_type type ); - explicit context( nlohmann::json const & ); explicit context( char const * json_settings ); - void stop() { _device_watcher->stop(); } ~context(); + + // The 'device-mask' is specified in the context settings, and governs which devices will be matched by us + // + unsigned get_device_mask() const { return _device_mask; } + + // Given the requested RS2_PRODUCT_LINE mask, returns the final mask when combined with the device-mask field in + // settings. + // + // E.g., if the device-mask specifies only D400 devices, and the user requests only SW devices, the result + // should be only SW D400 devices. + // + static unsigned combine_device_masks( unsigned requested_mask, unsigned mask_in_settings ); + std::vector> query_devices(int mask) const; const platform::backend& get_backend() const { return *_backend; } @@ -83,8 +87,7 @@ namespace librealsense void unregister_internal_device_callback(uint64_t cb_id); void set_devices_changed_callback(devices_changed_callback_ptr callback); - std::vector> create_devices(platform::backend_device_group devices, - const std::map>& playback_devices, int mask) const; + void query_software_devices( std::vector< std::shared_ptr< device_info > > & list, unsigned requested_mask ) const; std::shared_ptr add_device(const std::string& file); void remove_device(const std::string& file); @@ -94,16 +97,11 @@ namespace librealsense const nlohmann::json & get_settings() const { return _settings; } private: - void on_device_changed(platform::backend_device_group old, - platform::backend_device_group curr, - const std::map>& old_playback_devices, - const std::map>& new_playback_devices); void invoke_devices_changed_callbacks( std::vector & rs2_devices_info_removed, std::vector & rs2_devices_info_added ); void raise_devices_changed(const std::vector& removed, const std::vector& added); - void start_device_watcher(); + std::shared_ptr _backend; - std::shared_ptr _device_watcher; std::map> _playback_devices; std::map _devices_changed_callbacks; @@ -115,6 +113,8 @@ namespace librealsense #endif nlohmann::json _settings; // Save operation settings + unsigned const _device_mask; + backend_device_factory _backend_device_factory; devices_changed_callback_ptr _devices_changed_callback; std::map> _streams; @@ -122,17 +122,4 @@ namespace librealsense std::mutex _streams_mutex, _devices_changed_callbacks_mtx; }; - // Helper functions for device list manipulation: - std::vector filter_by_product(const std::vector& devices, const std::set& pid_list); - std::vector, std::vector>> group_devices_and_hids_by_unique_id( - const std::vector>& devices, - const std::vector& hids); - std::vector> group_devices_by_unique_id(const std::vector& devices); - void trim_device_list(std::vector& devices, const std::vector& chosen); - bool mi_present(const std::vector& devices, uint32_t mi); - platform::uvc_device_info get_mi(const std::vector& devices, uint32_t mi); - std::vector filter_by_mi(const std::vector& devices, uint32_t mi); - - std::vector filter_by_product(const std::vector& devices, const std::set& pid_list); - void trim_device_list(std::vector& devices, const std::vector& chosen); } diff --git a/src/device_hub.cpp b/src/device_hub.cpp index f684ecd53c..fd18d8caec 100644 --- a/src/device_hub.cpp +++ b/src/device_hub.cpp @@ -73,8 +73,6 @@ namespace librealsense { if (_device_changes_callback_id) _ctx->unregister_internal_device_callback(_device_changes_callback_id); - - _ctx->stop(); } std::shared_ptr device_hub::create_device(const std::string& serial, bool cycle_devices) diff --git a/src/ds/d400/d400-color.cpp b/src/ds/d400/d400-color.cpp index 300d352c73..f611aa90d5 100644 --- a/src/ds/d400/d400-color.cpp +++ b/src/ds/d400/d400-color.cpp @@ -10,6 +10,7 @@ #include "d400-color.h" #include "d400-info.h" #include +#include #include diff --git a/src/ds/d400/d400-device.cpp b/src/ds/d400/d400-device.cpp index 9b4b9e7dad..45611374e6 100644 --- a/src/ds/d400/d400-device.cpp +++ b/src/ds/d400/d400-device.cpp @@ -17,6 +17,7 @@ #include #include "d400-color.h" #include "d400-nonmonochrome.h" +#include #include #include diff --git a/src/ds/d400/d400-factory.cpp b/src/ds/d400/d400-factory.cpp index 2e10794481..e2c4227a14 100644 --- a/src/ds/d400/d400-factory.cpp +++ b/src/ds/d400/d400-factory.cpp @@ -25,6 +25,8 @@ #include "d400-thermal-monitor.h" #include "sync.h" +#include + #include "firmware_logger_device.h" #include "device-calibration.h" diff --git a/src/ds/d400/d400-motion.cpp b/src/ds/d400/d400-motion.cpp index 5e70ef239b..7d5107ca18 100644 --- a/src/ds/d400/d400-motion.cpp +++ b/src/ds/d400/d400-motion.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include "ds/ds-timestamp.h" #include "d400-options.h" diff --git a/src/ds/d500/d500-color.cpp b/src/ds/d500/d500-color.cpp index 16fd0d1106..25b5a96aa9 100644 --- a/src/ds/d500/d500-color.cpp +++ b/src/ds/d500/d500-color.cpp @@ -10,6 +10,7 @@ #include "d500-color.h" #include "d500-info.h" #include "backend.h" +#include "platform/platform-utils.h" namespace librealsense { diff --git a/src/ds/d500/d500-device.cpp b/src/ds/d500/d500-device.cpp index 209259db32..db2a892d61 100644 --- a/src/ds/d500/d500-device.cpp +++ b/src/ds/d500/d500-device.cpp @@ -7,6 +7,7 @@ #include "metadata-parser.h" #include "metadata.h" #include +#include #include "d500-device.h" #include "d500-private.h" diff --git a/src/ds/d500/d500-factory.cpp b/src/ds/d500/d500-factory.cpp index e090c90372..a948ce6d7d 100644 --- a/src/ds/d500/d500-factory.cpp +++ b/src/ds/d500/d500-factory.cpp @@ -23,6 +23,8 @@ #include "d500-motion.h" #include "sync.h" +#include + #include "firmware_logger_device.h" #include "device-calibration.h" diff --git a/src/ds/ds-motion-common.cpp b/src/ds/ds-motion-common.cpp index 99836ba3f7..ace5b18ec3 100644 --- a/src/ds/ds-motion-common.cpp +++ b/src/ds/ds-motion-common.cpp @@ -9,6 +9,7 @@ #include "environment.h" #include "metadata.h" #include "backend.h" +#include "platform/platform-utils.h" #include "global_timestamp_reader.h" #include "proc/auto-exposure-processor.h" diff --git a/src/fw-update/fw-update-factory.cpp b/src/fw-update/fw-update-factory.cpp index e20bd27778..0dae4753ca 100644 --- a/src/fw-update/fw-update-factory.cpp +++ b/src/fw-update/fw-update-factory.cpp @@ -25,11 +25,10 @@ namespace librealsense } - std::vector> fw_update_info::pick_recovery_devices( - std::shared_ptr ctx, - const std::vector& usb_devices, int mask) + std::vector< std::shared_ptr< fw_update_info > > fw_update_info::pick_recovery_devices( + std::shared_ptr< context > ctx, const std::vector< platform::usb_device_info > & usb_devices, int mask ) { - std::vector> list; + std::vector< std::shared_ptr< fw_update_info > > list; for (auto&& usb : usb_devices) { auto pl = get_product_line(usb); diff --git a/src/fw-update/fw-update-factory.h b/src/fw-update/fw-update-factory.h index 82d1fef053..28a415145c 100644 --- a/src/fw-update/fw-update-factory.h +++ b/src/fw-update/fw-update-factory.h @@ -16,8 +16,8 @@ namespace librealsense public: std::shared_ptr< device_interface > create_device() override; - static std::vector> pick_recovery_devices(std::shared_ptr ctx, - const std::vector& usb_devices, int mask); + static std::vector< std::shared_ptr< fw_update_info > > pick_recovery_devices( + std::shared_ptr< context > ctx, const std::vector< platform::usb_device_info > & usb_devices, int mask ); explicit fw_update_info(std::shared_ptr ctx, platform::usb_device_info const & dfu) : platform_device_info( ctx, { { dfu } } ) {} diff --git a/src/mf/mf-backend.cpp b/src/mf/mf-backend.cpp index e563aa246d..9b1ce2cbd7 100644 --- a/src/mf/mf-backend.cpp +++ b/src/mf/mf-backend.cpp @@ -180,8 +180,7 @@ namespace librealsense { public: win_event_device_watcher(const backend * backend) - : _last( backend->query_uvc_devices(), backend->query_usb_devices(), backend->query_hid_devices() ) - , _backend( backend ) + : _backend( backend ) { } ~win_event_device_watcher() { stop(); } @@ -195,6 +194,9 @@ namespace librealsense LOG_DEBUG( "starting win_event_device_watcher" ); _data._stopped = false; _callback = std::move(callback); + _last = backend_device_group( _backend->query_uvc_devices(), + _backend->query_usb_devices(), + _backend->query_hid_devices() ); _thread = std::thread([this]() { run(); }); } diff --git a/src/platform-camera.cpp b/src/platform-camera.cpp index 33e06f1854..a3c0d26d52 100644 --- a/src/platform-camera.cpp +++ b/src/platform-camera.cpp @@ -7,6 +7,7 @@ #include "stream.h" #include "proc/color-formats-converter.h" #include "backend.h" +#include "platform/platform-utils.h" namespace librealsense { @@ -138,11 +139,11 @@ std::vector< tagged_profile > platform_camera::get_profiles_tags() const } -/*static*/ std::vector< std::shared_ptr< device_info > > +/*static*/ std::vector< std::shared_ptr< platform_camera_info > > platform_camera_info::pick_uvc_devices( const std::shared_ptr< context > & ctx, const std::vector< platform::uvc_device_info > & uvc_devices ) { - std::vector< std::shared_ptr< device_info > > list; + std::vector< std::shared_ptr< platform_camera_info > > list; auto groups = group_devices_by_unique_id( uvc_devices ); for( auto && g : groups ) diff --git a/src/platform-camera.h b/src/platform-camera.h index 630170b293..e6ed8e8885 100644 --- a/src/platform-camera.h +++ b/src/platform-camera.h @@ -40,7 +40,7 @@ class platform_camera_info : public platform::platform_device_info register_device_notifications ); } - static std::vector< std::shared_ptr< device_info > > + static std::vector< std::shared_ptr< platform_camera_info > > pick_uvc_devices( const std::shared_ptr< context > & ctx, const std::vector< platform::uvc_device_info > & uvc_devices ); }; diff --git a/src/platform/backend-device-group.h b/src/platform/backend-device-group.h index 1796814d1b..c992f2210b 100644 --- a/src/platform/backend-device-group.h +++ b/src/platform/backend-device-group.h @@ -8,7 +8,6 @@ #include "hid-device-info.h" #include "uvc-device-info.h" -#include "playback-device-info.h" #include #include @@ -23,7 +22,7 @@ template< class T > bool list_changed( const std::vector< T > & list1, const std::vector< T > & list2, - std::function< bool( T, T ) > equal = []( T first, T second ) { return first == second; } ) + std::function< bool( T const &, T const & ) > equal = []( T const & first, T const & second ) { return first == second; } ) { if( list1.size() != list2.size() ) return true; @@ -47,13 +46,6 @@ bool list_changed( namespace platform { -inline bool operator==( const usb_device_info & a, const usb_device_info & b ) -{ - return ( a.id == b.id ) && ( a.vid == b.vid ) && ( a.pid == b.pid ) && ( a.mi == b.mi ) - && ( a.unique_id == b.unique_id ) && ( a.conn_spec == b.conn_spec ); -} - - struct backend_device_group { backend_device_group() {} @@ -79,20 +71,13 @@ struct backend_device_group { } - backend_device_group( const std::vector< playback_device_info > & playback_devices ) - : playback_devices( playback_devices ) - { - } - std::vector< uvc_device_info > uvc_devices; std::vector< usb_device_info > usb_devices; std::vector< hid_device_info > hid_devices; - std::vector< playback_device_info > playback_devices; bool operator==( const backend_device_group & other ) const { - return ! list_changed( uvc_devices, other.uvc_devices ) && ! list_changed( hid_devices, other.hid_devices ) - && ! list_changed( playback_devices, other.playback_devices ); + return ! list_changed( uvc_devices, other.uvc_devices ) && ! list_changed( hid_devices, other.hid_devices ); } operator std::string() const @@ -119,13 +104,6 @@ struct backend_device_group s += "\n\n"; } - s += playback_devices.size() > 0 ? "playback devices: \n" : ""; - for( auto playback_device : playback_devices ) - { - s += playback_device; - s += "\n\n"; - } - return s; } }; diff --git a/src/platform/platform-utils.cpp b/src/platform/platform-utils.cpp new file mode 100644 index 0000000000..0cfa3a72aa --- /dev/null +++ b/src/platform/platform-utils.cpp @@ -0,0 +1,147 @@ +// License: Apache 2.0. See LICENSE file in root directory. +// Copyright(c) 2023 Intel Corporation. All Rights Reserved. + +#include "platform-utils.h" + +#include "uvc-device-info.h" +#include "hid-device-info.h" +#include + + +namespace librealsense { +namespace platform { + + +std::vector< uvc_device_info > filter_by_product( const std::vector< uvc_device_info > & devices, + const std::set< uint16_t > & pid_list ) +{ + std::vector< uvc_device_info > result; + for( auto && info : devices ) + { + if( pid_list.count( info.pid ) ) + result.push_back( info ); + } + return result; +} + +// TODO: Make template +std::vector< usb_device_info > filter_by_product( const std::vector< usb_device_info > & devices, + const std::set< uint16_t > & pid_list ) +{ + std::vector< usb_device_info > result; + for( auto && info : devices ) + { + if( pid_list.count( info.pid ) ) + result.push_back( info ); + } + return result; +} + +std::vector< std::pair< std::vector< uvc_device_info >, std::vector< hid_device_info > > > +group_devices_and_hids_by_unique_id( const std::vector< std::vector< uvc_device_info > > & devices, + const std::vector< hid_device_info > & hids ) +{ + std::vector< std::pair< std::vector< uvc_device_info >, std::vector< hid_device_info > > > results; + uint16_t vid; + uint16_t pid; + + for( auto && dev : devices ) + { + std::vector< hid_device_info > hid_group; + auto unique_id = dev.front().unique_id; + auto device_serial = dev.front().serial; + + for( auto && hid : hids ) + { + if( ! hid.unique_id.empty() ) + { + std::stringstream( hid.vid ) >> std::hex >> vid; + std::stringstream( hid.pid ) >> std::hex >> pid; + + if( hid.unique_id == unique_id ) + { + hid_group.push_back( hid ); + } + } + } + results.push_back( std::make_pair( dev, hid_group ) ); + } + return results; +} + +std::vector< std::vector< uvc_device_info > > +group_devices_by_unique_id( const std::vector< uvc_device_info > & devices ) +{ + std::map< std::string, std::vector< uvc_device_info > > map; + for( auto && info : devices ) + { + map[info.unique_id].push_back( info ); + } + std::vector< std::vector< uvc_device_info > > result; + for( auto && kvp : map ) + { + result.push_back( kvp.second ); + } + return result; +} + +// TODO: Sergey +// Make template +void trim_device_list( std::vector< usb_device_info > & devices, const std::vector< usb_device_info > & chosen ) +{ + if( chosen.empty() ) + return; + + auto was_chosen = [&chosen]( const usb_device_info & info ) + { + return find( chosen.begin(), chosen.end(), info ) != chosen.end(); + }; + devices.erase( std::remove_if( devices.begin(), devices.end(), was_chosen ), devices.end() ); +} + +void trim_device_list( std::vector< uvc_device_info > & devices, const std::vector< uvc_device_info > & chosen ) +{ + if( chosen.empty() ) + return; + + auto was_chosen = [&chosen]( const uvc_device_info & info ) + { + return find( chosen.begin(), chosen.end(), info ) != chosen.end(); + }; + devices.erase( std::remove_if( devices.begin(), devices.end(), was_chosen ), devices.end() ); +} + +bool mi_present( const std::vector< uvc_device_info > & devices, uint32_t mi ) +{ + for( auto && info : devices ) + { + if( info.mi == mi ) + return true; + } + return false; +} + +uvc_device_info get_mi( const std::vector< uvc_device_info > & devices, uint32_t mi ) +{ + for( auto && info : devices ) + { + if( info.mi == mi ) + return info; + } + throw invalid_value_exception( "Interface not found!" ); +} + +std::vector< uvc_device_info > filter_by_mi( const std::vector< uvc_device_info > & devices, uint32_t mi ) +{ + std::vector< uvc_device_info > results; + for( auto && info : devices ) + { + if( info.mi == mi ) + results.push_back( info ); + } + return results; +} + + +} // namespace platform +} // namespace librealsense diff --git a/src/platform/platform-utils.h b/src/platform/platform-utils.h new file mode 100644 index 0000000000..1eb20e77f3 --- /dev/null +++ b/src/platform/platform-utils.h @@ -0,0 +1,39 @@ +// License: Apache 2.0. See LICENSE file in root directory. +// Copyright(c) 2023 Intel Corporation. All Rights Reserved. + +#pragma once + +#include +#include +#include + + +namespace librealsense { +namespace platform { + + +struct uvc_device_info; +struct hid_device_info; +struct usb_device_info; + + +// Helper functions for device list manipulation: +std::vector< uvc_device_info > filter_by_product( const std::vector< uvc_device_info > & devices, + const std::set< uint16_t > & pid_list ); +std::vector< std::pair< std::vector< uvc_device_info >, std::vector< hid_device_info > > > +group_devices_and_hids_by_unique_id( const std::vector< std::vector< uvc_device_info > > & devices, + const std::vector< hid_device_info > & hids ); +std::vector< std::vector< uvc_device_info > > +group_devices_by_unique_id( const std::vector< platform::uvc_device_info > & devices ); +void trim_device_list( std::vector< uvc_device_info > & devices, const std::vector< uvc_device_info > & chosen ); +bool mi_present( const std::vector< uvc_device_info > & devices, uint32_t mi ); +uvc_device_info get_mi( const std::vector< uvc_device_info > & devices, uint32_t mi ); +std::vector< uvc_device_info > filter_by_mi( const std::vector< uvc_device_info > & devices, uint32_t mi ); + +std::vector< usb_device_info > filter_by_product( const std::vector< usb_device_info > & devices, + const std::set< uint16_t > & pid_list ); +void trim_device_list( std::vector< usb_device_info > & devices, const std::vector< usb_device_info > & chosen ); + + +} // namespace platform +} // namespace librealsense diff --git a/src/rs.cpp b/src/rs.cpp index 8262e528a3..61dd1811fd 100644 --- a/src/rs.cpp +++ b/src/rs.cpp @@ -91,7 +91,6 @@ struct rs2_sensor : public rs2_options struct rs2_context { - ~rs2_context() { ctx->stop(); } std::shared_ptr ctx; }; @@ -176,7 +175,8 @@ rs2_context* rs2_create_context(int api_version, rs2_error** error) BEGIN_API_CA { verify_version_compatibility(api_version); - return new rs2_context{ std::make_shared< librealsense::context >( librealsense::backend_type::standard ) }; + nlohmann::json settings; + return new rs2_context{ std::make_shared< librealsense::context >( settings ) }; } HANDLE_EXCEPTIONS_AND_RETURN(nullptr, api_version) diff --git a/src/usb/usb-types.h b/src/usb/usb-types.h index 8dd392b11e..3716c55ce5 100644 --- a/src/usb/usb-types.h +++ b/src/usb/usb-types.h @@ -169,6 +169,12 @@ namespace librealsense } }; + inline bool operator==( const usb_device_info & a, const usb_device_info & b ) + { + return ( a.id == b.id ) && ( a.vid == b.vid ) && ( a.pid == b.pid ) && ( a.mi == b.mi ) + && ( a.unique_id == b.unique_id ) && ( a.conn_spec == b.conn_spec ); + } + static std::map usb_status_to_string = { {RS2_USB_STATUS_SUCCESS, "RS2_USB_STATUS_SUCCESS"},