From 91961c204a762f63b3bcc6cb244da986ea9d612b Mon Sep 17 00:00:00 2001 From: Dmitry Perchanov Date: Tue, 28 May 2024 18:14:31 +0300 Subject: [PATCH 1/4] DFU for D457 recovery device Tracked-by: [RSDSO-19297] - [D457]: LRS applications cannot recognized cameras in recovery mode Signed-off-by: Dmitry Perchanov --- include/librealsense2/hpp/rs_device.hpp | 4 +- src/CMakeLists.txt | 2 + src/backend-device-factory.cpp | 12 ++- src/backend.h | 6 +- src/ds/d400/d400-fw-update-device.cpp | 19 +++- src/ds/d400/d400-fw-update-device.h | 4 +- src/ds/d400/d400-private.h | 9 +- src/fw-update/fw-update-device.cpp | 84 ++++++++++++++- src/fw-update/fw-update-device.h | 13 ++- src/fw-update/fw-update-factory.cpp | 57 ++++++++--- src/fw-update/fw-update-factory.h | 8 +- src/linux/backend-v4l2.cpp | 129 +++++++++++++++++++++++- src/linux/backend-v4l2.h | 18 +++- src/mf/mf-backend.cpp | 5 + src/mf/mf-backend.h | 3 + src/platform/backend-device-group.h | 33 +++++- src/platform/mipi-device-info.h | 42 ++++++++ src/platform/mipi-device.h | 32 ++++++ src/platform/platform-device-info.h | 4 +- src/platform/platform-utils.h | 3 +- src/rsusb-backend/rsusb-backend.cpp | 5 + src/rsusb-backend/rsusb-backend.h | 1 + 22 files changed, 460 insertions(+), 33 deletions(-) create mode 100644 src/platform/mipi-device-info.h create mode 100644 src/platform/mipi-device.h diff --git a/include/librealsense2/hpp/rs_device.hpp b/include/librealsense2/hpp/rs_device.hpp index f5dbd6e3f3..d977f59bef 100644 --- a/include/librealsense2/hpp/rs_device.hpp +++ b/include/librealsense2/hpp/rs_device.hpp @@ -1,5 +1,5 @@ // License: Apache 2.0. See LICENSE file in root directory. -// Copyright(c) 2017 Intel Corporation. All Rights Reserved. +// Copyright(c) 2017-2024 Intel Corporation. All Rights Reserved. #ifndef LIBREALSENSE_RS2_DEVICE_HPP #define LIBREALSENSE_RS2_DEVICE_HPP @@ -61,6 +61,8 @@ namespace rs2 std::string pid = get_info( RS2_CAMERA_INFO_PRODUCT_ID ); if( pid == "ABCD" ) // Specific for D457 return "GMSL"; + if( pid == "BBCD" ) // Specific for D457 Recovery DFU + return "GMSL"; return pid; // for DDS devices, this will be "DDS" } return {}; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4269fed0c0..4223252b9e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -116,6 +116,8 @@ target_sources(${LRS_TARGET} "${CMAKE_CURRENT_LIST_DIR}/platform/hid-data.h" "${CMAKE_CURRENT_LIST_DIR}/platform/hid-device.h" "${CMAKE_CURRENT_LIST_DIR}/platform/hid-device-info.h" + "${CMAKE_CURRENT_LIST_DIR}/platform/mipi-device.h" + "${CMAKE_CURRENT_LIST_DIR}/platform/mipi-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" diff --git a/src/backend-device-factory.cpp b/src/backend-device-factory.cpp index d033b95c95..6157cba595 100644 --- a/src/backend-device-factory.cpp +++ b/src/backend-device-factory.cpp @@ -1,5 +1,5 @@ // License: Apache 2.0. See LICENSE file in root directory. -// Copyright(c) 2023 Intel Corporation. All Rights Reserved. +// Copyright(c) 2023-2024 Intel Corporation. All Rights Reserved. #include "backend-device-factory.h" #include "context.h" @@ -181,6 +181,7 @@ std::vector< std::shared_ptr< device_info > > backend_device_factory::query_devi auto backend = _device_watcher->get_backend(); platform::backend_device_group group( backend->query_uvc_devices(), backend->query_usb_devices(), + backend->query_mipi_devices(), backend->query_hid_devices() ); auto devices = create_devices_from_group( group, requested_mask ); return { devices.begin(), devices.end() }; @@ -214,6 +215,13 @@ backend_device_factory::create_devices_from_group( platform::backend_device_grou std::copy( begin( recovery_devices ), end( recovery_devices ), std::back_inserter( list ) ); } + // Supported mipi recovery devices + { + auto recovery_devices + = fw_update_info::pick_recovery_devices( ctx, devices.mipi_devices, mask ); + std::copy( begin( recovery_devices ), end( recovery_devices ), std::back_inserter( list ) ); + } + if( mask & RS2_PRODUCT_LINE_NON_INTEL ) { auto uvc_devices @@ -225,4 +233,4 @@ backend_device_factory::create_devices_from_group( platform::backend_device_grou } -} // namespace librealsense \ No newline at end of file +} // namespace librealsense diff --git a/src/backend.h b/src/backend.h index 7674300c7d..ae756ef8c5 100644 --- a/src/backend.h +++ b/src/backend.h @@ -1,10 +1,11 @@ // License: Apache 2.0. See LICENSE file in root directory. -// Copyright(c) 2015 Intel Corporation. All Rights Reserved. +// Copyright(c) 2015-2024 Intel Corporation. All Rights Reserved. #pragma once #include "platform/uvc-device-info.h" #include "platform/hid-device-info.h" +#include "platform/mipi-device-info.h" #include "platform/stream-profile.h" #include "platform/frame-object.h" @@ -27,6 +28,7 @@ namespace librealsense class device_watcher; class hid_device; class uvc_device; + class mipi_device; class command_transfer; @@ -42,6 +44,8 @@ namespace librealsense virtual std::shared_ptr create_hid_device(hid_device_info info) const = 0; virtual std::vector query_hid_devices() const = 0; + virtual std::vector query_mipi_devices() const = 0; + virtual std::shared_ptr create_device_watcher() const = 0; virtual std::string get_device_serial(uint16_t device_vid, uint16_t device_pid, const std::string& device_uid) const diff --git a/src/ds/d400/d400-fw-update-device.cpp b/src/ds/d400/d400-fw-update-device.cpp index 822faa6ddd..ec18af4a1b 100644 --- a/src/ds/d400/d400-fw-update-device.cpp +++ b/src/ds/d400/d400-fw-update-device.cpp @@ -1,5 +1,5 @@ // License: Apache 2.0. See LICENSE file in root directory. -// Copyright(c) 2019 Intel Corporation. All Rights Reserved. +// Copyright(c) 2019-2024 Intel Corporation. All Rights Reserved. #include "d400-fw-update-device.h" #include "d400-private.h" @@ -18,6 +18,16 @@ ds_d400_update_device::ds_d400_update_device( _serial_number = parse_serial_number(_serial_number_buffer); } + ds_d400_update_device::ds_d400_update_device( + std::shared_ptr< const device_info > const & dev_info, + std::shared_ptr< platform::mipi_device > const & mipi_device ) + : update_device( dev_info, mipi_device, "D400" ) + { + auto info = mipi_device->get_info(); + _name = ds::rs400_sku_names.find(info.pid) != ds::rs400_sku_names.end() ? ds::rs400_sku_names.at(info.pid) : "unknown"; + _serial_number = info.serial_number; + } + bool ds_d400_update_device::check_fw_compatibility(const std::vector& image) const { @@ -27,7 +37,12 @@ ds_d400_update_device::ds_d400_update_device( rsutils::string::from() << "Unsupported firmware binary image provided - " << image.size() << " bytes" ); std::string fw_version = ds::extract_firmware_version_string(image); - auto it = ds::d400_device_to_fw_min_version.find(_usb_device->get_info().pid); + uint16_t pid; + if (_usb_device != nullptr ) + pid = _usb_device->get_info().pid; + else if (_mipi_device != nullptr ) + pid = _mipi_device->get_info().pid; + auto it = ds::d400_device_to_fw_min_version.find(pid); if (it == ds::d400_device_to_fw_min_version.end()) throw librealsense::invalid_value_exception( rsutils::string::from() << "Min and Max firmware versions have not been defined for this device: " diff --git a/src/ds/d400/d400-fw-update-device.h b/src/ds/d400/d400-fw-update-device.h index ee9de524e5..a1ed524a33 100644 --- a/src/ds/d400/d400-fw-update-device.h +++ b/src/ds/d400/d400-fw-update-device.h @@ -1,5 +1,5 @@ // License: Apache 2.0. See LICENSE file in root directory. -// Copyright(c) 2019 Intel Corporation. All Rights Reserved. +// Copyright(c) 2019-2024 Intel Corporation. All Rights Reserved. #pragma once @@ -12,6 +12,8 @@ namespace librealsense public: ds_d400_update_device( std::shared_ptr< const device_info > const &, std::shared_ptr< platform::usb_device > const & usb_device ); + ds_d400_update_device( std::shared_ptr< const device_info > const &, + std::shared_ptr< platform::mipi_device > const & mipi_device ); virtual ~ds_d400_update_device() = default; virtual bool check_fw_compatibility(const std::vector& image) const override; diff --git a/src/ds/d400/d400-private.h b/src/ds/d400/d400-private.h index efd58cde69..d0c3049d3b 100644 --- a/src/ds/d400/d400-private.h +++ b/src/ds/d400/d400-private.h @@ -1,5 +1,5 @@ // License: Apache 2.0. See LICENSE file in root directory. -// Copyright(c) 2015 Intel Corporation. All Rights Reserved. +// Copyright(c) 2015-2024 Intel Corporation. All Rights Reserved. #pragma once @@ -37,6 +37,7 @@ namespace librealsense const uint16_t RS405_PID = 0x0B5B; // D405 const uint16_t RS455_PID = 0x0B5C; // D455 const uint16_t RS457_PID = 0xabcd; // D457 + const uint16_t RS457_RECOVERY_PID = 0xbbcd; // D457 DFU Recovery // d400 Devices supported by the current version static const std::set rs400_sku_pid = { @@ -124,6 +125,7 @@ namespace librealsense { RS405_PID, "Intel RealSense D405" }, { RS455_PID, "Intel RealSense D455" }, { RS457_PID, "Intel RealSense D457" }, + { RS457_RECOVERY_PID, "Intel RealSense D457 Recovery"}, }; static std::map d400_device_to_fw_min_version = { @@ -150,7 +152,8 @@ namespace librealsense {RS416_RGB_PID, "5.8.15.0" }, {RS405_PID, "5.12.11.8" }, {RS455_PID, "5.13.0.50" }, - {RS457_PID, "5.13.1.1" } + {RS457_PID, "5.13.1.1" }, + {RS457_RECOVERY_PID, "5.13.1.1" } }; std::vector filter_d400_device_by_capability( @@ -330,4 +333,4 @@ namespace librealsense }; } // namespace ds -} // namespace librealsense \ No newline at end of file +} // namespace librealsense diff --git a/src/fw-update/fw-update-device.cpp b/src/fw-update/fw-update-device.cpp index cfa86a3b95..3ab2c5652d 100644 --- a/src/fw-update/fw-update-device.cpp +++ b/src/fw-update/fw-update-device.cpp @@ -1,5 +1,5 @@ // License: Apache 2.0. See LICENSE file in root directory. -// Copyright(c) 2019 Intel Corporation. All Rights Reserved. +// Copyright(c) 2019-2024 Intel Corporation. All Rights Reserved. #include "fw-update-device.h" #include "../types.h" @@ -13,7 +13,12 @@ #include #include #include +#include +#include +#include +#define DEFAULT_TIMEOUT 100 +#define FW_UPDATE_INTERFACE_NUMBER 0 namespace librealsense { std::string get_formatted_fw_version(uint32_t fw_last_version) @@ -174,12 +179,31 @@ namespace librealsense } } + update_device::update_device( std::shared_ptr< const device_info > const & dev_info, + std::shared_ptr< platform::mipi_device > const & mipi_device, + const std::string & product_line ) + : _dev_info( dev_info ) + , _mipi_device( mipi_device ) + , _physical_port( mipi_device->get_info().dfu_device_path ) + , _pid( rsutils::string::from() << std::uppercase << rsutils::string::hexdump( mipi_device->get_info().pid )) + , _product_line( product_line ) + , _serial_number( mipi_device->get_info().serial_number ) + { + std::ifstream fw_path_in_device(_physical_port.c_str()); + if (!fw_path_in_device) + { + throw std::runtime_error("Firmware Update failed - wrong path or permissions missing"); + return; + } + fw_path_in_device.close(); + } + update_device::~update_device() { } - void update_device::update(const void* fw_image, int fw_image_size, rs2_update_progress_callback_sptr update_progress_callback) const + void update_device::update_usb(const void* fw_image, int fw_image_size, rs2_update_progress_callback_sptr update_progress_callback) const { // checking fw compatibility (covering the case of recovery device with wrong product line fw ) std::vector buffer((uint8_t*)fw_image, (uint8_t*)fw_image + fw_image_size); @@ -265,6 +289,62 @@ namespace librealsense throw std::runtime_error("Firmware manifest failed"); } + void update_device::update_mipi(const void* fw_image, int fw_image_size, rs2_update_progress_callback_sptr update_progress_callback) const + { + // checking fw compatibility (covering the case of recovery device with wrong product line fw ) + std::vector buffer((uint8_t*)fw_image, (uint8_t*)fw_image + fw_image_size); + const size_t transfer_size = 1024; + + size_t remaining_bytes = fw_image_size; + uint16_t blocks_count = uint16_t( fw_image_size / transfer_size ); + uint16_t block_number = 0; + + size_t offset = 0; + uint32_t transferred = 0; + + if (!check_fw_compatibility(buffer)) + throw librealsense::invalid_value_exception("Device: " + get_serial_number() + " failed to update firmware\nImage is unsupported for this device or corrupted"); + // Write signed firmware to appropriate file descriptor + + std::ofstream fw_path_in_device(_physical_port.c_str(), std::ios::binary); + if (!fw_path_in_device) + { + throw std::runtime_error("Firmware Update failed - wrong path or permissions missing"); + return; + } + while (remaining_bytes > 0) + { + size_t chunk_size = std::min(transfer_size, remaining_bytes); + + auto curr_block = ((uint8_t*)fw_image + offset); + + fw_path_in_device.write(reinterpret_cast(curr_block), chunk_size); + + block_number++; + remaining_bytes -= chunk_size; + offset += chunk_size; + + float progress = (float)block_number / (float)blocks_count; + LOG_DEBUG("fw update progress: " << progress); + if (update_progress_callback) + update_progress_callback->on_update_progress(progress); + } + LOG_INFO("Firmware Update for MIPI device done."); + fw_path_in_device.close(); + } + + void update_device::update(const void* fw_image, int fw_image_size, rs2_update_progress_callback_sptr update_progress_callback) const + { + if(_pid == "ABCD" || _pid == "BBCD") + { + update_mipi(fw_image, fw_image_size, update_progress_callback); + } + else + { + update_usb(fw_image, fw_image_size, update_progress_callback); + } + } + sensor_interface& update_device::get_sensor(size_t i) { throw std::runtime_error("try to get sensor from fw loader device"); diff --git a/src/fw-update/fw-update-device.h b/src/fw-update/fw-update-device.h index 6bd18099bb..019474c335 100644 --- a/src/fw-update/fw-update-device.h +++ b/src/fw-update/fw-update-device.h @@ -5,6 +5,7 @@ #include #include "fw-update-device-interface.h" #include "usb/usb-device.h" +#include "platform/mipi-device.h" namespace librealsense { @@ -19,7 +20,7 @@ namespace librealsense RS2_DFU_STATUS_VERIFY = 0x07, // Programmed memory failed verification. RS2_DFU_STATUS_ADDRESS = 0x08, // Cannot program memory due to received address that is out of range. RS2_DFU_STATUS_NOTDONE = 0x09, // Received DFU_DNLOAD with wLength = 0, but device does not think it has all of the data yet. - RS2_DFU_STATUS_FIRMWARE = 0x0A, // Device’s firmware is corrupt.It cannot return to run - time (non - DFU) operations. + RS2_DFU_STATUS_FIRMWARE = 0x0A, // Device�s firmware is corrupt.It cannot return to run - time (non - DFU) operations. RS2_DFU_STATUS_VENDOR = 0x0B, // iString indicates a vendor - specific RS2_DFU_STATUS_or. RS2_DFU_STATUS_USBR = 0x0C, // Device detected unexpected USB reset signaling. RS2_DFU_STATUS_POR = 0x0D, // Device detected unexpected power on reset. @@ -102,10 +103,15 @@ namespace librealsense update_device( std::shared_ptr< const device_info > const &, std::shared_ptr< platform::usb_device > const & usb_device, const std::string & _product_line ); + + update_device( std::shared_ptr< const device_info > const &, + std::shared_ptr< platform::mipi_device > const & mipi_device, + const std::string & _product_line ); + virtual ~update_device(); virtual void update(const void* fw_image, int fw_image_size, rs2_update_progress_callback_sptr = nullptr) const override; - + virtual sensor_interface& get_sensor(size_t i) override; virtual const sensor_interface& get_sensor(size_t i) const override; @@ -143,6 +149,8 @@ namespace librealsense virtual void enable_recording(std::function recording_function) override; protected: + void update_usb(const void* fw_image, int fw_image_size, rs2_update_progress_callback_sptr = nullptr) const; + void update_mipi(const void* fw_image, int fw_image_size, rs2_update_progress_callback_sptr = nullptr) const; rs2_dfu_state get_dfu_state(std::shared_ptr messenger) const; void detach(std::shared_ptr messenger) const; bool wait_for_state(std::shared_ptr messenger, const rs2_dfu_state state, size_t timeout = 1000) const; @@ -160,6 +168,7 @@ namespace librealsense const int FW_UPDATE_INTERFACE_NUMBER = 0; const std::shared_ptr< const device_info > _dev_info; const platform::rs_usb_device _usb_device; + const platform::rs_mipi_device _mipi_device; std::vector _serial_number_buffer; std::string _highest_fw_version; std::string _last_fw_version; diff --git a/src/fw-update/fw-update-factory.cpp b/src/fw-update/fw-update-factory.cpp index bc1e380e14..579267bfe5 100644 --- a/src/fw-update/fw-update-factory.cpp +++ b/src/fw-update/fw-update-factory.cpp @@ -1,5 +1,5 @@ // License: Apache 2.0. See LICENSE file in root directory. -// Copyright(c) 2019 Intel Corporation. All Rights Reserved. +// Copyright(c) 2019-2024 Intel Corporation. All Rights Reserved. #include "fw-update-factory.h" #include "fw-update-device.h" @@ -42,25 +42,57 @@ namespace librealsense return list; } + std::vector< std::shared_ptr< fw_update_info > > fw_update_info::pick_recovery_devices( + std::shared_ptr< context > ctx, const std::vector< platform::mipi_device_info > & mipi_devices, int mask ) + { + std::vector< std::shared_ptr< fw_update_info > > list; + for (auto&& mipi : mipi_devices) + { + list.push_back(std::make_shared(ctx, mipi)); + } + return list; + } + std::shared_ptr fw_update_info::create_device() { auto devices = platform::usb_enumerator::query_devices_info(); - auto const & dfu_id = get_group().usb_devices.front().id; - for (auto&& info : devices) - { - if( info.id == dfu_id ) + auto & dfu_id = get_group().usb_devices.front().id; + + auto const & mipi_id = get_group().mipi_devices.front().id; + + if (&dfu_id != nullptr) { + for (auto&& info : devices) + { + if( info.id == dfu_id ) + { + auto usb = platform::usb_enumerator::create_usb_device(info); + if (!usb) + continue; + switch( info.pid ) + { + case ds::RS_D400_RECOVERY_PID: + case ds::RS_D400_USB2_RECOVERY_PID: + return std::make_shared< ds_d400_update_device >( shared_from_this(), usb ); + case ds::D555E_RECOVERY_PID: + return std::make_shared< ds_d500_update_device >( shared_from_this(), usb ); + default: + // Do nothing + break; + } + } + } + } + else { + for (auto&& info: get_group().mipi_devices) { - auto usb = platform::usb_enumerator::create_usb_device(info); - if (!usb) + auto mipi = platform::mipi_device::create_mipi_device(info); + if (!mipi) continue; switch( info.pid ) { - case ds::RS_D400_RECOVERY_PID: - case ds::RS_D400_USB2_RECOVERY_PID: - return std::make_shared< ds_d400_update_device >( shared_from_this(), usb ); - case ds::D555E_RECOVERY_PID: - return std::make_shared< ds_d500_update_device >( shared_from_this(), usb ); + case 0xbbcd: + return std::make_shared< ds_d400_update_device >( shared_from_this(), mipi ); default: // Do nothing break; @@ -70,4 +102,5 @@ namespace librealsense throw std::runtime_error( rsutils::string::from() << "Failed to create FW update device, device id: " << dfu_id ); } + } diff --git a/src/fw-update/fw-update-factory.h b/src/fw-update/fw-update-factory.h index 7d0dcaf5f9..b085177b14 100644 --- a/src/fw-update/fw-update-factory.h +++ b/src/fw-update/fw-update-factory.h @@ -1,5 +1,5 @@ // License: Apache 2.0. See LICENSE file in root directory. -// Copyright(c) 2019 Intel Corporation. All Rights Reserved. +// Copyright(c) 2019-2024 Intel Corporation. All Rights Reserved. #pragma once @@ -19,9 +19,15 @@ namespace librealsense 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 ); + static std::vector< std::shared_ptr< fw_update_info > > pick_recovery_devices( + std::shared_ptr< context > ctx, const std::vector< platform::mipi_device_info > & mipi_devices, int mask ); + explicit fw_update_info(std::shared_ptr ctx, platform::usb_device_info const & dfu) : platform_device_info( ctx, { { dfu } } ) {} + explicit fw_update_info(std::shared_ptr ctx, platform::mipi_device_info const & dfu) + : platform_device_info( ctx, { { dfu } } ) {} + std::string get_address() const override { return "recovery:" + super::get_address(); } private: diff --git a/src/linux/backend-v4l2.cpp b/src/linux/backend-v4l2.cpp index 974827d488..822b197438 100644 --- a/src/linux/backend-v4l2.cpp +++ b/src/linux/backend-v4l2.cpp @@ -1,5 +1,5 @@ // License: Apache 2.0. See LICENSE file in root directory. -// Copyright(c) 2015 Intel Corporation. All Rights Reserved. +// Copyright(c) 2015-2024 Intel Corporation. All Rights Reserved. #include "backend-v4l2.h" #include @@ -696,6 +696,64 @@ namespace librealsense return video_paths; } + std::vector v4l_uvc_device::get_mipi_dfu_paths() + { + std::vector dfu_paths; + static const std::regex dfu_dev_pattern("./d4xx-dfu."); + // Enumerate all d4xx dfu devices present on the system + DIR * dir = opendir("/sys/class/d4xx-class"); + if(!dir) + { + LOG_INFO("Cannot access /sys/class/d4xx-class"); + return dfu_paths; + } + while (dirent * entry = readdir(dir)) + { + std::string name = entry->d_name; + if(name == "." || name == "..") continue; + std::string path = "/sys/class/d4xx-class/" + name; + std::string real_path{}; + char buff[PATH_MAX] = {0}; + if (realpath(path.c_str(), buff) != nullptr) + { + real_path = std::string(buff); + if (real_path.find("virtual") == std::string::npos) + continue; + if (!std::regex_search(real_path, dfu_dev_pattern)) + { + continue; + } + // if (get_devname_from_video_path(real_path, name)) + std::ifstream uevent_file(real_path + "/uevent"); + if (!uevent_file) + { + LOG_ERROR("Cannot access " + real_path + "/uevent"); + continue; + } + std::string uevent_line, devname; + while (std::getline(uevent_file, uevent_line) && (devname.empty())) + { + if (uevent_line.find("DEVNAME=") != std::string::npos) + { + devname = uevent_line.substr(uevent_line.find_last_of('=') + 1); + } + } + uevent_file.close(); + if (devname.empty()) + { + LOG_ERROR("No DEVNAME found for " + real_path); + continue; + } + if ( std::find(dfu_paths.begin(), dfu_paths.end(), devname) == dfu_paths.end() ) + { + dfu_paths.push_back(devname); + } + } + } + closedir(dir); + return dfu_paths; + } + bool v4l_uvc_device::is_usb_path_valid(const std::string& usb_video_path, const std::string& dev_name, std::string& busnum, std::string& devnum, std::string& devpath) { @@ -887,7 +945,8 @@ namespace librealsense // Note - jetson can use only bus_info, as card is different for each sensor and metadata node. info.unique_id = bus_info + "-" + std::to_string(cam_id); // use bus_info as per camera unique id for mipi // Get DFU node for MIPI camera - std::array dfu_device_paths = {"/dev/d4xx-dfu504", "/dev/d4xx-dfu-30-0010"}; + std::vector dfu_device_paths = get_mipi_dfu_paths(); + for (const auto& dfu_device_path: dfu_device_paths) { int vfd = open(dfu_device_path.c_str(), O_RDONLY | O_NONBLOCK); if (vfd >= 0) { @@ -909,11 +968,64 @@ namespace librealsense return std::regex_search(video_path, uvc_pattern); } + void v4l_mipi_device::foreach_mipi_device( + std::function action) + { + typedef std::pair node_info; + std::vector mipi_devices; + + std::vector mipi_dfu_paths = get_mipi_dfu_paths(); + for(auto it = mipi_dfu_paths.begin(); mipi_dfu_paths.size() && it != mipi_dfu_paths.end(); ++it) + { + auto mipi_dfu_path = "/dev/" + *it; + std::string dfu_ver; + for (int retry = 10; retry; retry--) { + std::ifstream fw_path_in_device(mipi_dfu_path); + std::getline(fw_path_in_device, dfu_ver); + if (dfu_ver.size()) { + fw_path_in_device.close(); + break; + } + fw_path_in_device.close(); + } + // look for "recovery" string, if no - skip. + if (dfu_ver.find("recovery") == std::string::npos) + continue; + mipi_device_info info{}; + info.pid = 0xbbcd; + info.vid = 0x8086; + info.id = *it; + info.device_path = mipi_dfu_path; + info.unique_id = *it; + info.dfu_device_path = mipi_dfu_path; + // The expected string is "DFU info: recovery: 209443110028" + std::string delimiter = ":"; + dfu_ver.erase(0, dfu_ver.find(delimiter) + delimiter.length()); + dfu_ver.erase(0, dfu_ver.find(delimiter) + delimiter.length()); + // Trim leading whitespace + dfu_ver.erase(0, dfu_ver.find_first_not_of(' ')); + info.serial_number = dfu_ver; + mipi_devices.emplace_back(info, *it); + } + try + { + // Dispatch registration for enumerated MIPI Recovery devices + for (auto&& dev : mipi_devices) + action(dev.first, dev.second); + } + catch(const std::exception & e) + { + LOG_ERROR("Registration of MIPI recovery device failed: " << e.what()); + } + } + void v4l_uvc_device::foreach_uvc_device( std::function action) { std::vector video_paths = get_video_paths(); + std::vector mipi_dfu_paths = get_mipi_dfu_paths(); typedef std::pair node_info; std::vector uvc_nodes,uvc_devices; std::vector mipi_rs_enum_nodes; @@ -2769,6 +2881,7 @@ namespace librealsense std::vector v4l_backend::query_uvc_devices() const { std::vector uvc_nodes; + v4l_uvc_device::foreach_uvc_device( [&uvc_nodes](const uvc_device_info& i, const std::string&) { @@ -2792,6 +2905,18 @@ namespace librealsense return device_infos; } + std::vector v4l_backend::query_mipi_devices() const + { + std::vector mipi_nodes; + + v4l_mipi_device::foreach_mipi_device( + [&mipi_nodes](const mipi_device_info& i, const std::string&) + { + mipi_nodes.push_back(i); + }); + + return mipi_nodes; + } std::shared_ptr v4l_backend::create_hid_device(hid_device_info info) const { return std::make_shared(info); diff --git a/src/linux/backend-v4l2.h b/src/linux/backend-v4l2.h index 6eb46b8851..e4c39fc662 100644 --- a/src/linux/backend-v4l2.h +++ b/src/linux/backend-v4l2.h @@ -1,5 +1,5 @@ // License: Apache 2.0. See LICENSE file in root directory. -// Copyright(c) 2015 Intel Corporation. All Rights Reserved. +// Copyright(c) 2015-2024 Intel Corporation. All Rights Reserved. #pragma once @@ -318,6 +318,7 @@ namespace librealsense const std::string&)> action); static std::vector get_video_paths(); + static std::vector get_mipi_dfu_paths(); static bool is_usb_path_valid(const std::string& usb_video_path, const std::string &dev_name, std::string &busnum, std::string &devnum, std::string &devpath); @@ -473,6 +474,19 @@ namespace librealsense { public: v4l_mipi_device(const uvc_device_info& info, bool use_memory_map = true); + v4l_mipi_device(const mipi_device_info& info, bool use_memory_map = true); + + static void foreach_mipi_device( + std::function action); + + static std::vector get_video_paths(); + + static mipi_device_info get_info_from_mipi_device_path( + const std::string& video_path, const std::string& name); + + static void get_mipi_device_info(const std::string& dev_name, + std::string& bus_info, std::string& card); virtual ~v4l_mipi_device(); @@ -501,6 +515,8 @@ namespace librealsense std::shared_ptr create_hid_device(hid_device_info info) const override; std::vector query_hid_devices() const override; + std::vector query_mipi_devices() const override; + std::shared_ptr create_device_watcher() const override; }; } diff --git a/src/mf/mf-backend.cpp b/src/mf/mf-backend.cpp index 9b1ce2cbd7..2067888d71 100644 --- a/src/mf/mf-backend.cpp +++ b/src/mf/mf-backend.cpp @@ -176,6 +176,11 @@ namespace librealsense return devices; } + std::vector wmf_backend::query_mipi_devices() const + { + return std::vector(); + } + class win_event_device_watcher : public device_watcher { public: diff --git a/src/mf/mf-backend.h b/src/mf/mf-backend.h index 41a5ac3756..87da8f6b42 100644 --- a/src/mf/mf-backend.h +++ b/src/mf/mf-backend.h @@ -25,6 +25,9 @@ namespace librealsense std::shared_ptr create_hid_device(hid_device_info info) const override; std::vector query_hid_devices() const override; + + std::vector query_mipi_devices() const override; + std::shared_ptr create_device_watcher() const override; std::string get_device_serial(uint16_t device_vid, uint16_t device_pid, const std::string& device_uid) const override; diff --git a/src/platform/backend-device-group.h b/src/platform/backend-device-group.h index 24a535cf35..0e5a46e9f0 100644 --- a/src/platform/backend-device-group.h +++ b/src/platform/backend-device-group.h @@ -1,5 +1,5 @@ // License: Apache 2.0. See LICENSE file in root directory. -// Copyright(c) 2023 Intel Corporation. All Rights Reserved. +// Copyright(c) 2023-2024 Intel Corporation. All Rights Reserved. #pragma once @@ -8,6 +8,7 @@ #include "hid-device-info.h" #include "uvc-device-info.h" +#include "mipi-device-info.h" #include #include @@ -60,6 +61,22 @@ struct backend_device_group { } + backend_device_group( const std::vector< uvc_device_info > & uvc_devices, + const std::vector< usb_device_info > & usb_devices, + const std::vector< mipi_device_info > & mipi_devices, + const std::vector< hid_device_info > & hid_devices ) + : uvc_devices( uvc_devices ) + , usb_devices( usb_devices ) + , mipi_devices( mipi_devices ) + , hid_devices( hid_devices ) + { + } + + backend_device_group( const std::vector< mipi_device_info > & mipi_devices ) + : mipi_devices( mipi_devices ) + { + } + backend_device_group( const std::vector< usb_device_info > & usb_devices ) : usb_devices( usb_devices ) { @@ -74,6 +91,7 @@ struct backend_device_group std::vector< uvc_device_info > uvc_devices; std::vector< usb_device_info > usb_devices; + std::vector< mipi_device_info > mipi_devices; std::vector< hid_device_info > hid_devices; bool operator==( const backend_device_group & other ) const @@ -98,6 +116,13 @@ struct backend_device_group s += "\n\n"; } + s += mipi_devices.size() > 0 ? "mipi devices:\n" : ""; + for( auto mipi : mipi_devices ) + { + s += mipi; + s += "\n\n"; + } + s += hid_devices.size() > 0 ? "hid devices: \n" : ""; for( auto hid : hid_devices ) { @@ -125,6 +150,12 @@ struct backend_device_group == second_data.usb_devices.end() ) return false; } + for( auto & mipi : mipi_devices ) + { + if( std::find( second_data.mipi_devices.begin(), second_data.mipi_devices.end(), mipi ) + == second_data.mipi_devices.end() ) + return false; + } for( auto & hid : hid_devices ) { if( std::find( second_data.hid_devices.begin(), second_data.hid_devices.end(), hid ) diff --git a/src/platform/mipi-device-info.h b/src/platform/mipi-device-info.h new file mode 100644 index 0000000000..682e4866d8 --- /dev/null +++ b/src/platform/mipi-device-info.h @@ -0,0 +1,42 @@ +// License: Apache 2.0. See LICENSE file in root directory. +// Copyright(c) 2024 Intel Corporation. All Rights Reserved. + +#pragma once + +#include +#include + + +namespace librealsense { +namespace platform { + + +struct mipi_device_info +{ + std::string id; + uint16_t vid; + uint16_t pid; + std::string unique_id; + std::string device_path; + std::string dfu_device_path; + std::string serial_number; + + operator std::string() + { + std::ostringstream s; + s << "id- " << id << "\nvid- " << std::hex << vid << "\npid- " << std::hex << pid << "\nunique_id- " + << unique_id << "\npath- " << device_path; + + return s.str(); + } +}; + + +inline bool operator==( const mipi_device_info & a, const mipi_device_info & b ) +{ + return ( a.id == b.id ) && ( a.vid == b.vid ) && ( a.pid == b.pid ) && ( a.unique_id == b.unique_id ) + && ( a.device_path == b.device_path ); +} + +} // namespace platform +} // namespace librealsense diff --git a/src/platform/mipi-device.h b/src/platform/mipi-device.h new file mode 100644 index 0000000000..ad64326652 --- /dev/null +++ b/src/platform/mipi-device.h @@ -0,0 +1,32 @@ +// License: Apache 2.0. See LICENSE file in root directory. +// Copyright(c) 2024 Intel Corporation. All Rights Reserved. + +#pragma once + +#include +#include +#include "mipi-device-info.h" + +namespace librealsense { +namespace platform { + +class mipi_device; +typedef std::shared_ptr rs_mipi_device; + +class mipi_device +{ +public: + mipi_device(const mipi_device_info& info) : _info(info) {} + virtual ~mipi_device() = default; + static rs_mipi_device create_mipi_device(const mipi_device_info& info) + { + return std::make_shared(info); + } + const mipi_device_info get_info() const { return _info; }; +private: + const mipi_device_info _info; +}; + + +} // namespace platform +} // namespace librealsense diff --git a/src/platform/platform-device-info.h b/src/platform/platform-device-info.h index 0f4afb2c99..447345386c 100644 --- a/src/platform/platform-device-info.h +++ b/src/platform/platform-device-info.h @@ -1,5 +1,5 @@ // License: Apache 2.0. See LICENSE file in root directory. -// Copyright(c) 2023 Intel Corporation. All Rights Reserved. +// Copyright(c) 2023-2024 Intel Corporation. All Rights Reserved. #pragma once @@ -39,6 +39,8 @@ class platform_device_info : public device_info return _group.uvc_devices.front().device_path; if( ! _group.usb_devices.empty() ) return _group.usb_devices.front().id; + if( ! _group.mipi_devices.empty() ) + return _group.mipi_devices.front().id; throw std::runtime_error( "non-standard platform-device-info" ); } diff --git a/src/platform/platform-utils.h b/src/platform/platform-utils.h index 1eb20e77f3..8c0c7bdda4 100644 --- a/src/platform/platform-utils.h +++ b/src/platform/platform-utils.h @@ -1,5 +1,5 @@ // License: Apache 2.0. See LICENSE file in root directory. -// Copyright(c) 2023 Intel Corporation. All Rights Reserved. +// Copyright(c) 2023-2024 Intel Corporation. All Rights Reserved. #pragma once @@ -15,6 +15,7 @@ namespace platform { struct uvc_device_info; struct hid_device_info; struct usb_device_info; +struct mipi_device_info; // Helper functions for device list manipulation: diff --git a/src/rsusb-backend/rsusb-backend.cpp b/src/rsusb-backend/rsusb-backend.cpp index 6fa2a737e9..745941d85d 100644 --- a/src/rsusb-backend/rsusb-backend.cpp +++ b/src/rsusb-backend/rsusb-backend.cpp @@ -64,5 +64,10 @@ namespace librealsense { return query_hid_devices_info(); } + + std::vector rs_backend::query_mipi_devices() const + { + return std::vector(); + } } } diff --git a/src/rsusb-backend/rsusb-backend.h b/src/rsusb-backend/rsusb-backend.h index 5a35f0b297..1018293e6d 100644 --- a/src/rsusb-backend/rsusb-backend.h +++ b/src/rsusb-backend/rsusb-backend.h @@ -27,6 +27,7 @@ namespace librealsense // Not supported std::shared_ptr create_hid_device(hid_device_info info) const override; std::vector query_hid_devices() const override; + std::vector query_mipi_devices() const override; }; } } From ca181b8a6e3554b4e14f4179b0c37aeec7778835 Mon Sep 17 00:00:00 2001 From: Dmitry Perchanov Date: Sun, 2 Jun 2024 11:47:55 +0300 Subject: [PATCH 2/4] rs-fw-update: inform user of necessary action for d457 Signed-off-by: Dmitry Perchanov --- tools/fw-update/rs-fw-update.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/fw-update/rs-fw-update.cpp b/tools/fw-update/rs-fw-update.cpp index 290a90142c..620812e723 100644 --- a/tools/fw-update/rs-fw-update.cpp +++ b/tools/fw-update/rs-fw-update.cpp @@ -340,6 +340,7 @@ try try { update_serial_number = recovery_device.get_info( RS2_CAMERA_INFO_FIRMWARE_UPDATE_ID ); + bool d457_recovery_device = strcmp( recovery_device.get_info( RS2_CAMERA_INFO_PRODUCT_ID ), "BBCD" ) == 0; volatile bool recovery_device_found = false; ctx.set_devices_changed_callback( [&]( rs2::event_information & info ) { for( auto && d : info.get_new_devices() ) @@ -362,6 +363,7 @@ try print_device_info( recovery_device ); update( recovery_device, fw_image ); std::cout << "Waiting for new device..." << std::endl; + if (!d457_recovery_device) { std::unique_lock< std::mutex > lk( mutex ); if( ! recovery_device_found @@ -374,6 +376,12 @@ try } } std::cout << std::endl << "Recovery done" << std::endl; + if (d457_recovery_device) + { + std::cout << std::endl << "For GMSL device please reload d4xx driver:" << std::endl; + std::cout << "sudo rmmod d4xx && sudo modprobe d4xx" << std::endl; + std::cout << "or reboot the system" << std::endl; + } return EXIT_SUCCESS; } catch (...) From 102432a040bc2db7b8912e24705b79955966c13a Mon Sep 17 00:00:00 2001 From: Dmitry Perchanov Date: Sun, 2 Jun 2024 14:24:56 +0300 Subject: [PATCH 3/4] fw-update: GUI user notification for d457 recovery Signed-off-by: Dmitry Perchanov --- common/fw-update-helper.cpp | 47 +++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/common/fw-update-helper.cpp b/common/fw-update-helper.cpp index ff1c538758..badc98f457 100644 --- a/common/fw-update-helper.cpp +++ b/common/fw-update-helper.cpp @@ -128,29 +128,33 @@ namespace rs2 void firmware_update_manager::process_mipi() { + bool is_mipi_recovery = !(strcmp(_dev.get_info(RS2_CAMERA_INFO_PRODUCT_ID), "BBCD")); if (!_is_signed) { fail("Signed FW update for MIPI device - This FW file is not signed "); return; } - auto dev_updatable = _dev.as(); - if(!(dev_updatable && dev_updatable.check_firmware_compatibility(_fw))) + if (!is_mipi_recovery) { - fail("Firmware Update failed - fw version must be newer than version 5.13.1.1"); - return; + auto dev_updatable = _dev.as(); + if(!(dev_updatable && dev_updatable.check_firmware_compatibility(_fw))) + { + fail("Firmware Update failed - fw version must be newer than version 5.13.1.1"); + return; + } } - log("Burning Signed Firmware on MIPI device"); - - // Enter DFU mode - auto device_debug = _dev.as(); - uint32_t dfu_opcode = 0x1e; - device_debug.build_command(dfu_opcode, 1); - + if (!is_mipi_recovery) + { + // Enter DFU mode + auto device_debug = _dev.as(); + uint32_t dfu_opcode = 0x1e; + device_debug.build_command(dfu_opcode, 1); + } _progress = 30; - + rs2_camera_info _dfu_port_info = (is_mipi_recovery)?(RS2_CAMERA_INFO_PHYSICAL_PORT):(RS2_CAMERA_INFO_DFU_DEVICE_PATH); // Write signed firmware to appropriate file descriptor - std::ofstream fw_path_in_device(_dev.get_info(RS2_CAMERA_INFO_DFU_DEVICE_PATH), std::ios::binary); + std::ofstream fw_path_in_device(_dev.get_info(_dfu_port_info), std::ios::binary); if (fw_path_in_device) { fw_path_in_device.write(reinterpret_cast(_fw.data()), _fw.size()); @@ -160,10 +164,20 @@ namespace rs2 fail("Firmware Update failed - wrong path or permissions missing"); return; } - LOG_INFO("Firmware Update for MIPI device done."); + log("FW update process completed successfully."); + LOG_INFO("FW update process completed successfully."); fw_path_in_device.close(); _progress = 100; + if (is_mipi_recovery) + { + log("For GMSL MIPI device please reboot, or reload d4xx driver\n"\ + "sudo rmmod d4xx && sudo modprobe d4xx\n"\ + "and restart the realsense-viewer"); + LOG_INFO("For GMSL MIPI device please reboot, or reload d4xx driver\n"\ + "sudo rmmod d4xx && sudo modprobe d4xx\n"\ + "and restart the realsense-viewer"); + } _done = true; // need to find a way to update the fw version field in the viewer } @@ -173,7 +187,10 @@ namespace rs2 invoker invoke) { // if device is D457, and fw is signed - using mipi specific procedure - if (!strcmp(_dev.get_info(RS2_CAMERA_INFO_PRODUCT_ID), "ABCD") && _is_signed) + if (_is_signed + && (!strcmp(_dev.get_info(RS2_CAMERA_INFO_PRODUCT_ID), "ABCD") + || !strcmp(_dev.get_info(RS2_CAMERA_INFO_PRODUCT_ID), "BBCD")) + ) { process_mipi(); return; From 8139036fa1974c65720aca45e55accd8da8c7eed Mon Sep 17 00:00:00 2001 From: Dmitry Perchanov Date: Sun, 2 Jun 2024 15:55:14 +0300 Subject: [PATCH 4/4] backend-v4l2: fix dfu path for legacy Signed-off-by: Dmitry Perchanov --- src/linux/backend-v4l2.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/linux/backend-v4l2.cpp b/src/linux/backend-v4l2.cpp index 822b197438..24f76cde40 100644 --- a/src/linux/backend-v4l2.cpp +++ b/src/linux/backend-v4l2.cpp @@ -948,10 +948,11 @@ namespace librealsense std::vector dfu_device_paths = get_mipi_dfu_paths(); for (const auto& dfu_device_path: dfu_device_paths) { - int vfd = open(dfu_device_path.c_str(), O_RDONLY | O_NONBLOCK); + auto mipi_dfu_chardev = "/dev/" + dfu_device_path; + int vfd = open(mipi_dfu_chardev.c_str(), O_RDONLY | O_NONBLOCK); if (vfd >= 0) { // Use legacy DFU device node used in firmware_update_manager - info.dfu_device_path = dfu_device_path; + info.dfu_device_path = mipi_dfu_chardev; ::close(vfd); // file exists, close file and continue to assign it break; }