diff --git a/common/fw-update-helper.cpp b/common/fw-update-helper.cpp index fa2580110a..104d134981 100644 --- a/common/fw-update-helper.cpp +++ b/common/fw-update-helper.cpp @@ -271,11 +271,8 @@ namespace rs2 if ( !log_backup_status.empty() ) log(log_backup_status); - - - - next_progress = 40; + next_progress = _progress + 10; if (_is_signed) { diff --git a/src/ds/d500/d500-fw-update-device.cpp b/src/ds/d500/d500-fw-update-device.cpp index c6c2be21f3..7687a2e977 100644 --- a/src/ds/d500/d500-fw-update-device.cpp +++ b/src/ds/d500/d500-fw-update-device.cpp @@ -37,17 +37,65 @@ ds_d500_update_device::ds_d500_update_device( std::shared_ptr< const device_info void ds_d500_update_device::update(const void* fw_image, int fw_image_size, rs2_update_progress_callback_sptr update_progress_callback) const { - update_device::update( fw_image, fw_image_size ); - - static constexpr float D500_FW_DFU_TIME = 180.0; // [sec] - // We calculate the sleep time needed for each cycle to get to 100% progress bar - // On D500 devices after transferring the FW image the internal DFU progress start on the device - float iteration_sleep_time_ms = (static_cast(D500_FW_DFU_TIME) / 100.0f) * 1000.0f; - for(int i = 1; i <= 100; i++) - { + update_device::update( fw_image, fw_image_size, update_progress_callback ); + } + + bool ds_d500_update_device::wait_for_manifest_completion(std::shared_ptr messenger, const rs2_dfu_state state, + std::chrono::seconds timeout_seconds, rs2_update_progress_callback_sptr update_progress_callback) const + { + std::chrono::seconds elapsed_seconds; + auto start = std::chrono::system_clock::now(); + rs2_dfu_state dfu_state = RS2_DFU_STATE_APP_IDLE; + dfu_status_payload status; + int percentage_of_transfer = 0; + int iteration = 0; + // progress should start increase even in the 2nd iteration, + // when this DFU progress is enabled by FW + int max_iteration_number_for_progress_start = 10; + + do { + uint32_t transferred = 0; + auto sts = messenger->control_transfer(0xa1 /*DFU_GETSTATUS_PACKET*/, RS2_DFU_GET_STATUS, 0, 0, (uint8_t*)&status, sizeof(status), transferred, 5000); + dfu_state = status.get_state(); + percentage_of_transfer = static_cast(status.iString); + + // the below code avoids process stuck when using a d5XX device, + // which has a fw version without the DFU progress feature + if (percentage_of_transfer == 0 && + ++iteration == max_iteration_number_for_progress_start) + return true; + + std::stringstream ss; + ss << "DFU_GETSTATUS called, state is: " << to_string(dfu_state); + ss << ", iString equals: " << percentage_of_transfer << ", and bwPollTimeOut equals: " << status.bwPollTimeout << std::endl; + LOG_DEBUG(ss.str().c_str()); + if (update_progress_callback) - update_progress_callback->on_update_progress( i / 100.f ); - std::this_thread::sleep_for(std::chrono::milliseconds(static_cast(iteration_sleep_time_ms))); - } + { + auto progress_for_bar = compute_progress(static_cast(percentage_of_transfer), 20.f, 100.f, 5.f) / 100.f; + update_progress_callback->on_update_progress(progress_for_bar); + } + + if (sts != platform::RS2_USB_STATUS_SUCCESS) + LOG_DEBUG("control xfer error: " << platform::usb_status_to_string[sts]); + + //test for dfu error state + if (status.is_error_state()) { + return false; + } + + // FW doesn't set the bwPollTimeout value, therefore it is wrong to use status.bwPollTimeout + std::this_thread::sleep_for(std::chrono::seconds(1)); + + auto curr = std::chrono::system_clock::now(); + elapsed_seconds = std::chrono::duration_cast(curr - start); + if (elapsed_seconds > timeout_seconds) + { + LOG_ERROR("DFU in MANIFEST STATUS Timeout"); + return false; + } + } while (percentage_of_transfer < 100 && dfu_state == RS2_DFU_STATE_DFU_MANIFEST); + + return true; } } diff --git a/src/ds/d500/d500-fw-update-device.h b/src/ds/d500/d500-fw-update-device.h index e856313fa8..48b18b9952 100644 --- a/src/ds/d500/d500-fw-update-device.h +++ b/src/ds/d500/d500-fw-update-device.h @@ -16,6 +16,8 @@ namespace librealsense virtual bool check_fw_compatibility(const std::vector& image) const override; virtual void update(const void* fw_image, int fw_image_size, rs2_update_progress_callback_sptr = nullptr) const override; + virtual bool wait_for_manifest_completion(std::shared_ptr messenger, const rs2_dfu_state state, + std::chrono::seconds timeout_seconds, rs2_update_progress_callback_sptr update_progress_callback) const override; private: std::string parse_serial_number(const std::vector& buffer) const; diff --git a/src/fw-update/fw-update-device.cpp b/src/fw-update/fw-update-device.cpp index 9455a4719e..75141fa3c8 100644 --- a/src/fw-update/fw-update-device.cpp +++ b/src/fw-update/fw-update-device.cpp @@ -14,8 +14,6 @@ #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) @@ -81,6 +79,35 @@ namespace librealsense LOG_INFO("DFU status: " << lock_status << " , DFU version is: " << payload.dfu_version); } + std::string update_device::to_string(rs2_dfu_state state) const + { + switch (state) + { + case(RS2_DFU_STATE_APP_IDLE): + return "APP_IDLE"; + case(RS2_DFU_STATE_APP_DETACH): + return "APP_DETACH"; + case(RS2_DFU_STATE_DFU_DOWNLOAD_SYNC): + return "DFU_DOWNLOAD_SYNC"; + case(RS2_DFU_STATE_DFU_DOWNLOAD_BUSY): + return "DFU_DOWNLOAD_BUSY"; + case(RS2_DFU_STATE_DFU_DOWNLOAD_IDLE): + return "DFU_DOWNLOAD_IDLE"; + case(RS2_DFU_STATE_DFU_MANIFEST_SYNC): + return "DFU_MANIFEST_SYNC"; + case(RS2_DFU_STATE_DFU_MANIFEST): + return "DFU_MANIFEST"; + case(RS2_DFU_STATE_DFU_MANIFEST_WAIT_RESET): + return "DFU_MANIFEST_WAIT_RESET"; + case(RS2_DFU_STATE_DFU_UPLOAD_IDLE): + return "DFU_UPLOAD_IDLE"; + case(RS2_DFU_STATE_DFU_ERROR): + return "DFU_ERROR"; + default: + return "DFU_STATE_???"; + } + } + bool update_device::wait_for_state(std::shared_ptr messenger, const rs2_dfu_state state, size_t timeout) const { std::chrono::milliseconds elapsed_milliseconds; @@ -112,6 +139,21 @@ namespace librealsense return false; } + float update_device::compute_progress(float progress, float start, float end, float threshold) const + { + if (threshold < 1.f) + throw std::invalid_argument("Avoid division by zero"); + return start + (ceil(progress * threshold) / threshold) * (end - start) / 100.f; + } + + bool update_device::wait_for_manifest_completion(std::shared_ptr messenger, const rs2_dfu_state state, + std::chrono::seconds timeout_seconds, rs2_update_progress_callback_sptr update_progress_callback) const + { + // used for devices which get the progress percentage in the GET_DFU_STATUS call + + return true; + } + update_device::update_device( std::shared_ptr< const device_info > const & dev_info, std::shared_ptr< platform::usb_device > const & usb_device, const std::string & product_line ) @@ -195,7 +237,10 @@ namespace librealsense 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); + { + auto progress_for_bar = compute_progress(progress, 0.f, 20.f, 5.f) / 100.f; + update_progress_callback->on_update_progress(progress_for_bar); + } } // After the final block of firmware has been sent to the device and the status solicited, the host sends a @@ -206,6 +251,12 @@ namespace librealsense if (sts != platform::RS2_USB_STATUS_SUCCESS) throw std::runtime_error("Failed to send final FW packet"); + + // measuring the progress of the writing to flash (when enabled by FW) + if (!wait_for_manifest_completion(messenger, RS2_DFU_STATE_DFU_MANIFEST, std::chrono::seconds(200), update_progress_callback)) + throw std::runtime_error("Firmware manifest completion failed"); + + // After the zero length DFU_DNLOAD request terminates the Transfer // phase, the device is ready to manifest the new firmware. As described // previously, some devices may accumulate the firmware image and perform diff --git a/src/fw-update/fw-update-device.h b/src/fw-update/fw-update-device.h index 143358b165..ac27eab822 100644 --- a/src/fw-update/fw-update-device.h +++ b/src/fw-update/fw-update-device.h @@ -146,13 +146,19 @@ namespace librealsense 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; + virtual bool wait_for_manifest_completion(std::shared_ptr messenger, const rs2_dfu_state state, + std::chrono::seconds timeout_seconds, rs2_update_progress_callback_sptr update_progress_callback) const; void read_device_info(std::shared_ptr messenger); const std::string & get_name() const { return _name; } const std::string & get_product_line() const { return _product_line; } const std::string & get_serial_number() const { return _serial_number; } + std::string to_string(platform::usb_status state) const; + std::string to_string(rs2_dfu_state state) const; + float compute_progress(float progress, float start, float end, float threshold) const; - + const int DEFAULT_TIMEOUT = 100; + const int FW_UPDATE_INTERFACE_NUMBER = 0; const std::shared_ptr< const device_info > _dev_info; const platform::rs_usb_device _usb_device; std::vector _serial_number_buffer;