fw-update-device.cpp
Go to the documentation of this file.
1 // License: Apache 2.0. See LICENSE file in root directory.
2 // Copyright(c) 2019 Intel Corporation. All Rights Reserved.
3 
4 #include "fw-update-device.h"
5 #include "../types.h"
6 #include "../context.h"
7 #include "../ds5/ds5-private.h"
8 
9 #include <chrono>
10 #include <stdexcept>
11 #include <algorithm>
12 #include <thread>
13 
14 #define DEFAULT_TIMEOUT 100
15 #define FW_UPDATE_INTERFACE_NUMBER 0
16 namespace librealsense
17 {
19  {
20  uint8_t* ptr = (uint8_t*)(&fw_last_version);
21  std::vector<uint8_t> buffer(ptr, ptr + sizeof(fw_last_version));
22  std::stringstream fw_version;
23  std::string delimiter = "";
24  for (auto i = 1; i <= buffer.size(); i++)
25  {
26  fw_version << delimiter << static_cast<int>(buffer[buffer.size() - i]);
27  delimiter = ".";
28  }
29  return fw_version.str();
30  }
31 
32  rs2_dfu_state update_device::get_dfu_state(std::shared_ptr<platform::usb_messenger> messenger) const
33  {
35  uint32_t transferred = 0;
36  auto res = messenger->control_transfer(0xa1 /*DFU_GETSTATUS_PACKET*/, RS2_DFU_GET_STATE, 0, 0, &state, 1, transferred, DEFAULT_TIMEOUT);
38  throw backend_exception("Permission Denied!\n"
39  "This is often an indication of outdated or missing udev-rules.\n"
40  "If using Debian package, run sudo apt-get install librealsense2-dkms\n"
41  "If building from source, run ./scripts/setup_udev_rules.sh",
44  }
45 
46  void update_device::detach(std::shared_ptr<platform::usb_messenger> messenger) const
47  {
48  auto timeout = 1000;
49  uint32_t transferred = 0;
50  auto res = messenger->control_transfer(0x21 /*DFU_DETACH_PACKET*/, RS2_DFU_DETACH, timeout, 0, NULL, 0, transferred, timeout);
52  LOG_WARNING("DFU - failed to detach device");
53  }
54 
55  void update_device::read_device_info(std::shared_ptr<platform::usb_messenger> messenger)
56  {
57  auto state = get_dfu_state(messenger);
58 
60  throw std::runtime_error("DFU detach failed!");
61 
62  dfu_fw_status_payload payload;
63  uint32_t transferred = 0;
64  auto sts = messenger->control_transfer(0xa1, RS2_DFU_UPLOAD, 0, 0, reinterpret_cast<uint8_t*>(&payload), sizeof(payload), transferred, DEFAULT_TIMEOUT);
66  throw std::runtime_error("Failed to read info from DFU device!");
67 
68  _serial_number_buffer = std::vector<uint8_t>(sizeof(payload.serial_number));
69  _serial_number_buffer.assign((uint8_t*)&payload.serial_number, (uint8_t*)&payload.serial_number + sizeof(payload.serial_number));
70  _is_dfu_locked = payload.dfu_is_locked;
73 
74  std::string lock_status = _is_dfu_locked ? "device is locked" : "device is unlocked";
75  LOG_INFO("This device is in DFU mode, previously-installed firmware: " << _last_fw_version <<
76  ", the highest firmware ever installed: " << _highest_fw_version);
77 
78  LOG_INFO("DFU status: " << lock_status << " , DFU version is: " << payload.dfu_version);
79  }
80 
81  bool update_device::wait_for_state(std::shared_ptr<platform::usb_messenger> messenger, const rs2_dfu_state state, size_t timeout) const
82  {
83  std::chrono::milliseconds elapsed_milliseconds;
85  do {
87  uint32_t transferred = 0;
88  auto sts = messenger->control_transfer(0xa1 /*DFU_GETSTATUS_PACKET*/, RS2_DFU_GET_STATUS, 0, 0, (uint8_t*)&status, sizeof(status), transferred, 5000);
89 
91  return false;
92 
93  if (status.is_in_state(state)) {
94  return true;
95  }
96 
97  //test for dfu error state
98  if (status.is_error_state()) {
99  return false;
100  }
101 
102  // FW doesn't set the bwPollTimeout value, therefore it is wrong to use status.bwPollTimeout
103  std::this_thread::sleep_for(std::chrono::milliseconds(DEFAULT_TIMEOUT));
104 
105  auto curr = std::chrono::system_clock::now();
106  elapsed_milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(curr - start);
107  } while (elapsed_milliseconds < std::chrono::milliseconds(timeout));
108 
109  return false;
110  }
111 
112  update_device::update_device(const std::shared_ptr<context>& ctx, bool register_device_notifications, std::shared_ptr<platform::usb_device> usb_device)
113  : _context(ctx), _usb_device(usb_device), _physical_port( usb_device->get_info().id )
114  {
115  if (auto messenger = _usb_device->open(FW_UPDATE_INTERFACE_NUMBER))
116  {
117  auto state = get_dfu_state(messenger);
118  LOG_DEBUG("DFU state is: " << state);
120  detach(messenger);
121 
122  read_device_info(messenger);
123  }
124  else
125  {
126  std::stringstream s;
127  s << "access failed for " << std::hex << _usb_device->get_info().vid << ":"
128  <<_usb_device->get_info().pid << " uid: " << _usb_device->get_info().id << std::dec;
129  LOG_ERROR(s.str().c_str());
130  throw std::runtime_error(s.str().c_str());
131  }
132  }
133 
135  {
136 
137  }
138 
139  void update_device::update(const void* fw_image, int fw_image_size, update_progress_callback_ptr update_progress_callback) const
140  {
141  auto messenger = _usb_device->open(FW_UPDATE_INTERFACE_NUMBER);
142 
143  const size_t transfer_size = 1024;
144 
145  size_t remaining_bytes = fw_image_size;
146  uint16_t blocks_count = uint16_t( fw_image_size / transfer_size );
147  uint16_t block_number = 0;
148 
149  size_t offset = 0;
150  uint32_t transferred = 0;
151  int retries = 10;
152 
153  while (remaining_bytes > 0)
154  {
155  size_t chunk_size = std::min(transfer_size, remaining_bytes);
156 
157  auto curr_block = ((uint8_t*)fw_image + offset);
158  auto sts = messenger->control_transfer(0x21 /*DFU_DOWNLOAD_PACKET*/, RS2_DFU_DOWNLOAD, block_number, 0, curr_block, uint32_t(chunk_size), transferred, 5000);
160  {
161  auto state = get_dfu_state(messenger);
162  // the update process may be interrupted by another thread that trys to create another fw_update_device.
163  // this retry mechanism should overcome such scenario.
164  // we limit the number of retries in order to avoid infinite loop.
165  if (state == RS2_DFU_STATE_DFU_IDLE && retries--)
166  continue;
167 
168  auto sn = get_serial_number();
169  if(_is_dfu_locked)
170  throw std::runtime_error("Device: " + sn + " is locked for update.\nUse firmware version higher than: " + _highest_fw_version);
171  else
172  throw std::runtime_error("Device: " + sn + " failed to download firmware\nPlease verify that no other librealsense application is running");
173  }
174 
175  block_number++;
176  remaining_bytes -= chunk_size;
177  offset += chunk_size;
178 
179  float progress = (float)block_number / (float)blocks_count;
180  LOG_DEBUG("fw update progress: " << progress);
181  if (update_progress_callback)
182  update_progress_callback->on_update_progress(progress);
183  }
184 
185  // After the final block of firmware has been sent to the device and the status solicited, the host sends a
186  // DFU_DNLOAD request with the wLength field cleared to 0 and then solicits the status again.If the
187  // result indicates that the device is ready and there are no errors, then the Transfer phase is complete and
188  // the Manifestation phase begins.
189  auto sts = messenger->control_transfer(0x21 /*DFU_DOWNLOAD_PACKET*/, RS2_DFU_DOWNLOAD, block_number, 0, NULL, 0, transferred, DEFAULT_TIMEOUT);
191  throw std::runtime_error("Failed to send final FW packet");
192 
193  // After the zero length DFU_DNLOAD request terminates the Transfer
194  // phase, the device is ready to manifest the new firmware. As described
195  // previously, some devices may accumulate the firmware image and perform
196  // the entire reprogramming operation at one time. Others may have only a
197  // small amount remaining to be reprogrammed, and still others may have
198  // none. Regardless, the device enters the dfuMANIFEST-SYNC state and
199  // awaits the solicitation of the status report by the host. Upon receipt
200  // of the anticipated DFU_GETSTATUS, the device enters the dfuMANIFEST
201  // state, where it completes its reprogramming operations.
202 
203  // WaitForDFU state sends several DFU_GETSTATUS requests, until we hit
204  // either RS2_DFU_STATE_DFU_MANIFEST_WAIT_RESET or RS2_DFU_STATE_DFU_ERROR status.
205  // This command also reset the device
207  throw std::runtime_error("Firmware manifest failed");
208  }
209 
211  {
212  throw std::runtime_error("try to get sensor from fw loader device");
213  }
214 
216  {
217  throw std::runtime_error("update_device does not support get_sensor API");
218  }
219 
221  {
222  return 0;
223  }
224 
226  {
227  //TODO_MK
228  }
229 
230  std::shared_ptr<matcher> update_device::create_matcher(const frame_holder& frame) const
231  {
232  return nullptr;
233  }
234 
235  std::shared_ptr<context> update_device::get_context() const
236  {
237  return _context;
238  }
239 
241  {
242  throw std::runtime_error("update_device does not support get_device_data API");//TODO_MK
243  }
244 
245  std::pair<uint32_t, rs2_extrinsics> update_device::get_extrinsics(const stream_interface& stream) const
246  {
247  throw std::runtime_error("update_device does not support get_extrinsics API");
248  }
249 
251  {
252  return true;
253  }
254 
255  std::vector<tagged_profile> update_device::get_profiles_tags() const
256  {
257  return std::vector<tagged_profile>();
258  }
259 
261  {
262 
263  }
264 
266  {
267  return false;
268  }
269 
271  {
272  switch (info)
273  {
275  case RS2_CAMERA_INFO_NAME: return get_name();
278  default:
279  throw std::runtime_error("update_device does not support " + std::string(rs2_camera_info_to_string(info)));
280  }
281  }
282 
284  {
285  switch (info)
286  {
291  return true;
292 
293  default:
294  return false;
295  }
296  }
297 
298  void update_device::create_snapshot(std::shared_ptr<info_interface>& snapshot) const
299  {
300 
301  }
302  void update_device::enable_recording(std::function<void(const info_interface&)> record_action)
303  {
304 
305  }
306 }
rs2_camera_info
Read-only strings that can be queried from the device. Not all information attributes are available o...
Definition: rs_sensor.h:22
virtual sensor_interface & get_sensor(size_t i) override
GLdouble s
virtual const std::string & get_serial_number() const =0
#define LOG_WARNING(...)
Definition: src/types.h:241
virtual bool is_valid() const override
const platform::rs_usb_device _usb_device
def progress(args)
Definition: log.py:43
unsigned short uint16_t
Definition: stdint.h:79
GLsizei const GLchar *const * string
unsigned char uint8_t
Definition: stdint.h:78
GLenum GLfloat * buffer
virtual std::pair< uint32_t, rs2_extrinsics > get_extrinsics(const stream_interface &stream) const override
virtual std::vector< tagged_profile > get_profiles_tags() const override
GLenum GLuint id
status
Defines return codes that SDK interfaces use. Negative values indicate errors, a zero value indicates...
virtual std::shared_ptr< matcher > create_matcher(const frame_holder &frame) const override
std::shared_ptr< rs2_update_progress_callback > update_progress_callback_ptr
Definition: src/types.h:1077
update_device(const std::shared_ptr< context > &ctx, bool register_device_notifications, std::shared_ptr< platform::usb_device > usb_device)
#define DEFAULT_TIMEOUT
def info(name, value, persistent=False)
Definition: test.py:301
const std::shared_ptr< context > _context
virtual void enable_recording(std::function< void(const info_interface &)> recording_function) override
unsigned int uint32_t
Definition: stdint.h:80
virtual void hardware_reset() override
void read_device_info(std::shared_ptr< platform::usb_messenger > messenger)
virtual size_t get_sensors_count() const override
GLuint start
virtual void create_snapshot(std::shared_ptr< info_interface > &snapshot) const override
rs2_dfu_state get_dfu_state(std::shared_ptr< platform::usb_messenger > messenger) const
#define LOG_ERROR(...)
Definition: src/types.h:242
bool wait_for_state(std::shared_ptr< platform::usb_messenger > messenger, const rs2_dfu_state state, size_t timeout=1000) const
virtual const std::string & get_name() const =0
virtual void update(const void *fw_image, int fw_image_size, update_progress_callback_ptr=nullptr) const override
std::vector< std::shared_ptr< stream_profile_interface >> stream_profiles
Definition: streaming.h:165
virtual std::shared_ptr< context > get_context() const override
virtual const std::string & get_product_line() const =0
virtual platform::backend_device_group get_device_data() const override
LOG_INFO("Log message using LOG_INFO()")
const char * rs2_camera_info_to_string(rs2_camera_info info)
Definition: rs.cpp:1266
virtual bool compress_while_record() const override
std::string get_formatted_fw_version(uint32_t fw_last_version)
GLbitfield GLuint64 timeout
std::vector< uint8_t > _serial_number_buffer
int min(int a, int b)
Definition: lz4s.c:73
virtual void tag_profiles(stream_profiles profiles) const override
#define FW_UPDATE_INTERFACE_NUMBER
#define NULL
Definition: tinycthread.c:47
int i
GLuint res
Definition: glext.h:8856
#define LOG_DEBUG(...)
Definition: src/types.h:239
virtual const std::string & get_info(rs2_camera_info info) const override
virtual bool supports_info(rs2_camera_info info) const override
void detach(std::shared_ptr< platform::usb_messenger > messenger) const
GLintptr offset
bool is_in_state(const rs2_dfu_state state) const


librealsense2
Author(s): Sergey Dorodnicov , Doron Hirshberg , Mark Horn , Reagan Lopez , Itay Carpis
autogenerated on Mon May 3 2021 02:47:15