diff --git a/include/librealsense2/h/rs_device.h b/include/librealsense2/h/rs_device.h index 156825a08be..c3d9ab86a16 100644 --- a/include/librealsense2/h/rs_device.h +++ b/include/librealsense2/h/rs_device.h @@ -86,6 +86,12 @@ int rs2_supports_device_info(const rs2_device* device, rs2_camera_info info, rs2 */ void rs2_hardware_reset(const rs2_device * device, rs2_error ** error); +/** +* Check if a camera is in recovery mode +* \param[in] device The RealSense device to check +* \param[out] error If non-null, receives any error that occurs during this call, otherwise, errors are ignored*/ +int rs2_is_in_recovery_mode(const rs2_device* device, rs2_error** error); + /** * Build debug_protocol raw data command from opcode, parameters and data. * The result can be used as raw_data_to_send parameter in send_and_receive_raw_data diff --git a/include/librealsense2/hpp/rs_device.hpp b/include/librealsense2/hpp/rs_device.hpp index 7c06c3d757b..3909662afb2 100644 --- a/include/librealsense2/hpp/rs_device.hpp +++ b/include/librealsense2/hpp/rs_device.hpp @@ -130,6 +130,17 @@ namespace rs2 error::handle(e); } + /** + * Find if a camera is in recovery mode + */ + bool is_in_recovery_mode() + { + rs2_error* e = nullptr; + auto result = rs2_is_in_recovery_mode(_dev.get(), &e); + error::handle(e); + return result; + } + device& operator=(const std::shared_ptr dev) { _dev.reset(); diff --git a/src/core/device-interface.h b/src/core/device-interface.h index 478112488c2..ebf100a3b7f 100644 --- a/src/core/device-interface.h +++ b/src/core/device-interface.h @@ -59,6 +59,8 @@ class device_interface virtual bool is_valid() const = 0; + virtual bool is_in_recovery_mode() const = 0; + virtual std::vector< tagged_profile > get_profiles_tags() const = 0; using stream_profiles = std::vector< std::shared_ptr< stream_profile_interface > >; diff --git a/src/dds/rs-dds-device-proxy.cpp b/src/dds/rs-dds-device-proxy.cpp index 4b759d7d8ba..3e5b1985393 100644 --- a/src/dds/rs-dds-device-proxy.cpp +++ b/src/dds/rs-dds-device-proxy.cpp @@ -659,6 +659,11 @@ void dds_device_proxy::hardware_reset() _dds_dev->send_control( control, &reply ); } +bool dds_device_proxy::is_in_recovery_mode() const +{ + return _dds_dev->device_info().is_recovery(); +} + std::string dds_device_proxy::get_opcode_string(int opcode) const { std::string product_line = get_info(RS2_CAMERA_INFO_PRODUCT_LINE); diff --git a/src/dds/rs-dds-device-proxy.h b/src/dds/rs-dds-device-proxy.h index 5e6814499d5..acd4b2f6f42 100644 --- a/src/dds/rs-dds-device-proxy.h +++ b/src/dds/rs-dds-device-proxy.h @@ -82,6 +82,8 @@ class dds_device_proxy void hardware_reset() override; + bool is_in_recovery_mode() const override; + // calibration_change_device public: void register_calibration_change_callback( rs2_calibration_change_callback_sptr callback ) override diff --git a/src/device.h b/src/device.h index cc9bc0af97f..370541a91b0 100644 --- a/src/device.h +++ b/src/device.h @@ -78,6 +78,8 @@ class device bool is_valid() const override { return *_is_alive; } + bool is_in_recovery_mode() const override { return false; } + void tag_profiles(stream_profiles profiles) const override; virtual bool compress_while_record() const override { return true; } diff --git a/src/fw-update/fw-update-device.cpp b/src/fw-update/fw-update-device.cpp index 469d41c298c..e2c7cb2938c 100644 --- a/src/fw-update/fw-update-device.cpp +++ b/src/fw-update/fw-update-device.cpp @@ -398,6 +398,11 @@ namespace librealsense return true; } + bool update_device::is_in_recovery_mode() const + { + return true; + } + std::vector update_device::get_profiles_tags() const { return std::vector(); diff --git a/src/fw-update/fw-update-device.h b/src/fw-update/fw-update-device.h index 3a184fae66c..d4fa81c4f12 100644 --- a/src/fw-update/fw-update-device.h +++ b/src/fw-update/fw-update-device.h @@ -133,6 +133,8 @@ namespace librealsense virtual bool is_valid() const override; + virtual bool is_in_recovery_mode() const override; + virtual std::vector get_profiles_tags() const override; virtual void tag_profiles(stream_profiles profiles) const override; diff --git a/src/media/playback/playback_device.cpp b/src/media/playback/playback_device.cpp index aa5e8b425c3..3c1e7966f47 100644 --- a/src/media/playback/playback_device.cpp +++ b/src/media/playback/playback_device.cpp @@ -429,6 +429,11 @@ bool playback_device::is_valid() const return true; } +bool playback_device::is_in_recovery_mode() const +{ + return false; +} + void playback_device::update_time_base(device_serializer::nanoseconds base_timestamp) { m_base_sys_time = std::chrono::high_resolution_clock::now(); diff --git a/src/media/playback/playback_device.h b/src/media/playback/playback_device.h index 9fcff5891fd..7cbdd52ccce 100644 --- a/src/media/playback/playback_device.h +++ b/src/media/playback/playback_device.h @@ -51,6 +51,7 @@ namespace librealsense std::pair get_extrinsics(const stream_interface& stream) const override; static bool try_extend_snapshot(std::shared_ptr& e, rs2_extension extension_type, void** ext); bool is_valid() const override; + bool is_in_recovery_mode() const override; std::vector get_profiles_tags() const override { return std::vector(); };//no hard-coded default streams for playback void tag_profiles(stream_profiles profiles) const override diff --git a/src/media/record/record_device.cpp b/src/media/record/record_device.cpp index c5ecec3d77f..6b12d607631 100644 --- a/src/media/record/record_device.cpp +++ b/src/media/record/record_device.cpp @@ -465,3 +465,8 @@ bool record_device::is_valid() const { return m_device->is_valid(); } + +bool record_device::is_in_recovery_mode() const +{ + return m_device->is_in_recovery_mode(); +} diff --git a/src/media/record/record_device.h b/src/media/record/record_device.h index 5957eb9acd8..9ffa43a1e17 100644 --- a/src/media/record/record_device.h +++ b/src/media/record/record_device.h @@ -44,6 +44,7 @@ namespace librealsense std::shared_ptr< const device_info > get_device_info() const override; std::pair get_extrinsics(const stream_interface& stream) const override; bool is_valid() const override; + bool is_in_recovery_mode() const override; std::vector get_profiles_tags() const override { return m_device->get_profiles_tags(); }; void tag_profiles(stream_profiles profiles) const override { m_device->tag_profiles(profiles); } diff --git a/src/realsense.def b/src/realsense.def index f79a5bc4c0a..1db0f00a4d8 100644 --- a/src/realsense.def +++ b/src/realsense.def @@ -48,6 +48,7 @@ EXPORTS rs2_start_cpp rs2_stop rs2_hardware_reset + rs2_is_in_recovery_mode rs2_set_notifications_callback rs2_set_notifications_callback_cpp diff --git a/src/rs.cpp b/src/rs.cpp index b5bf2b1c6ba..95bf5c95240 100644 --- a/src/rs.cpp +++ b/src/rs.cpp @@ -1748,6 +1748,14 @@ void rs2_hardware_reset(const rs2_device* device, rs2_error** error) BEGIN_API_C } HANDLE_EXCEPTIONS_AND_RETURN(, device) +int rs2_is_in_recovery_mode(const rs2_device* device, rs2_error** error) BEGIN_API_CALL +{ + VALIDATE_NOT_NULL(device); + VALIDATE_NOT_NULL(device->device); + return device->device->is_in_recovery_mode(); +} +HANDLE_EXCEPTIONS_AND_RETURN(0, device) + // Verify and provide API version encoded as integer value int rs2_get_api_version(rs2_error** error) BEGIN_API_CALL { diff --git a/tools/fw-update/rs-fw-update.cpp b/tools/fw-update/rs-fw-update.cpp index 4d6d974d24d..81db78c4f80 100644 --- a/tools/fw-update/rs-fw-update.cpp +++ b/tools/fw-update/rs-fw-update.cpp @@ -45,12 +45,6 @@ std::vector read_fw_file(std::string file_path) std::vector rv; std::ifstream file(file_path, std::ios::in | std::ios::binary | std::ios::ate); - auto file_deleter = std::unique_ptr< std::ifstream, void (*)(std::ifstream*) >(&file, - [](std::ifstream* file) - { - if (file) - file->close(); - }); if (file.is_open()) { rv.resize(file.tellg()); @@ -175,33 +169,35 @@ void waiting_for_device_to_reconnect(rs2::context& ctx, rs2::cli::value& fw_image) +{ + auto upd = dev.as(); + if ( !upd ) + { + throw std::runtime_error("Device could not be used as updatable device"); + } + // checking compatibility bewtween firmware and device + if ( !upd.check_firmware_compatibility( fw_image ) ) + { + std::stringstream ss; + ss << "This firmware version is not compatible with "; + ss << dev.get_info( RS2_CAMERA_INFO_NAME ) << std::endl; + std::cout << std::endl << ss.str() << std::endl; + return false; + } + return true; +} + int write_fw_to_mipi_device(rs2::context& ctx, rs2::cli::value& serial_number_arg, const rs2::device& dev, const std::vector< uint8_t >& fw_image) { // Write firmware to appropriate file descriptor std::cout << std::endl << "Update can take up to 2 minutes" << std::endl; std::ofstream fw_path_in_device( dev.get_info( RS2_CAMERA_INFO_DFU_DEVICE_PATH ), std::ios::binary ); - auto file_deleter = std::unique_ptr< std::ofstream, void ( * )( std::ofstream * ) >( &fw_path_in_device, - []( std::ofstream * file ) - { - if( file ) - file->close(); - } ); + if( fw_path_in_device ) { - auto upd = dev.as(); - if ( !upd ) - { - throw std::runtime_error("Device could not be used as updatable device"); - } - // checking compatibility bewtween firmware and device - if( !upd.check_firmware_compatibility( fw_image ) ) - { - std::stringstream ss; - ss << "This firmware version is not compatible with "; - ss << dev.get_info( RS2_CAMERA_INFO_NAME ) << std::endl; - std::cout << std::endl << ss.str() << std::endl; + if (!is_fw_compatible(dev, fw_image)) return EXIT_FAILURE; - } bool burn_done = false; std::thread show_progress_thread( @@ -322,7 +318,7 @@ try for (auto&& d : devs) { - if (!d.is< rs2::update_device >()) + if (!d.is_in_recovery_mode()) continue; auto sn = d.get_info(RS2_CAMERA_INFO_FIRMWARE_UPDATE_ID); if (!selected_serial_number.empty() && sn != selected_serial_number) @@ -347,7 +343,7 @@ try ctx.set_devices_changed_callback([&](rs2::event_information& info) { for (auto&& d : info.get_new_devices()) { - if (d.is< rs2::update_device >()) + if (d.is_in_recovery_mode()) continue; auto recovery_sn = d.get_info(RS2_CAMERA_INFO_FIRMWARE_UPDATE_ID); if (recovery_sn == update_serial_number) @@ -363,6 +359,13 @@ try }); std::cout << std::endl << "Recovering device: " << std::endl; print_device_info(recovery_device); + + std::string camera_name = recovery_device.get_info(RS2_CAMERA_INFO_NAME); + // on D555 check FW compatibility also sends FW to the device + if (camera_name.find("D555") != std::string::npos && + (!is_fw_compatible(recovery_device, fw_image))) + return EXIT_FAILURE; + update(recovery_device, fw_image); std::cout << "Waiting for new device..." << std::endl; if (!d457_recovery_device) @@ -404,7 +407,7 @@ try for (auto&& d : info.get_new_devices()) { std::lock_guard lk(mutex); - if (d.is() && (d.get_info(RS2_CAMERA_INFO_FIRMWARE_UPDATE_ID) == update_serial_number)) + if (d.is_in_recovery_mode() && (d.get_info(RS2_CAMERA_INFO_FIRMWARE_UPDATE_ID) == update_serial_number)) new_fw_update_device = d; else new_device = d; @@ -424,7 +427,7 @@ try if (devs.size() == 1) { auto dev = devs[0]; - if (dev.is< rs2::update_device >() && !dev.is< rs2::updatable >()) + if (dev.is_in_recovery_mode() && !dev.is< rs2::updatable >()) { std::cout << std::endl << "Device is in recovery mode, use -r to recover" << std::endl << std::endl; return EXIT_FAILURE; @@ -486,12 +489,6 @@ try { auto temp = backup_arg.getValue(); std::ofstream file(temp.c_str(), std::ios::binary); - auto file_deleter = std::unique_ptr< std::ofstream, void (*)(std::ofstream*) >(&file, - [](std::ofstream* file) - { - if (file) - file->close(); - }); try { file.write((const char*)flash.data(), flash.size()); @@ -543,22 +540,10 @@ try } else { - auto upd = d.as(); - - if ( !upd ) - { - throw std::runtime_error("Device could not be used as updatable device"); - } - // checking compatibility bewtween firmware and device - if( !upd.check_firmware_compatibility( fw_image ) ) - { - std::stringstream ss; - ss << "This firmware version is not compatible with "; - ss << d.get_info(RS2_CAMERA_INFO_NAME) << std::endl; - std::cout << std::endl << ss.str() << std::endl; + if (!is_fw_compatible(d, fw_image)) return EXIT_FAILURE; - } + auto upd = d.as(); upd.enter_update_state(); // Some devices may immediately get in an update state? diff --git a/unit-tests/py/rspy/devices.py b/unit-tests/py/rspy/devices.py index 1c30ccbfa55..623acef91cd 100644 --- a/unit-tests/py/rspy/devices.py +++ b/unit-tests/py/rspy/devices.py @@ -515,7 +515,7 @@ def recovery(): :return: A set of all device serial-numbers that are in recovery mode """ global _device_by_sn - return { device.serial_number for device in _device_by_sn.values() if device.handle.is_update_device() } + return { device.serial_number for device in _device_by_sn.values() if device.handle.is_in_recovery_mode() } def enable_only( serial_numbers, recycle = False, timeout = MAX_ENUMERATION_TIME ): diff --git a/unit-tests/test-fw-update.py b/unit-tests/test-fw-update.py index dea11d99a74..73c9da27d3f 100644 --- a/unit-tests/test-fw-update.py +++ b/unit-tests/test-fw-update.py @@ -180,7 +180,7 @@ def find_image_or_exit( product_name, fw_version_regex = r'(\d+\.){3}(\d+)' ): test.start( "Update FW" ) # check if recovery. If so recover recovered = False -if device.is_update_device(): +if device.is_in_recovery_mode(): log.d( "recovering device ..." ) try: # always flash signed fw when device on recovery befre flashing anything else diff --git a/wrappers/python/pyrs_device.cpp b/wrappers/python/pyrs_device.cpp index f5bf0a9633e..25d691fa093 100644 --- a/wrappers/python/pyrs_device.cpp +++ b/wrappers/python/pyrs_device.cpp @@ -32,6 +32,7 @@ void init_device(py::module &m) { .def("__nonzero__", &rs2::device::operator bool) // Called to implement truth value testing in Python 2 .def("__bool__", &rs2::device::operator bool) // Called to implement truth value testing in Python 3 .def( "is_connected", &rs2::device::is_connected ) + .def("is_in_recovery_mode", &rs2::device::is_in_recovery_mode) .def(BIND_DOWNCAST(device, debug_protocol)) .def(BIND_DOWNCAST(device, playback)) .def(BIND_DOWNCAST(device, recorder))