tm-device.cpp
Go to the documentation of this file.
1 // License: Apache 2.0. See LICENSE file in root directory.
2 // Copyright(c) 2017 Intel Corporation. All Rights Reserved.
3 
4 #ifndef NOMINMAX
5  #define NOMINMAX
6 #endif
7 
8 #include <memory>
9 #include <thread>
10 #include <inttypes.h> // PRIu64
11 #include "tm-device.h"
12 #include "stream.h"
14 #include "media/ros/ros_reader.h"
15 #include "usb/usb-enumerator.h"
16 
17 // uncomment to get debug messages at info severity
18 //#undef LOG_DEBUG
19 //#define LOG_DEBUG LOG_INFO
20 
21 using namespace std::chrono;
22 
23 #ifdef __APPLE__
24 
25 #include <libkern/OSByteOrder.h>
26 #define htobe64(x) OSSwapHostToBigInt64(x)
27 
28 #endif
29 
31 {
32 #if defined(__linux__) || defined(__APPLE__)
33  return htobe64(val);
34 #else
35  return _byteswap_uint64(val);
36 #endif
37 }
38 
39 #include "t265-messages.h"
40 using namespace t265;
41 
42 #include "message-print.h"
43 
44 #define SENSOR_TYPE_POS (0)
45 #define SENSOR_TYPE_MASK (0x001F << SENSOR_TYPE_POS)
46 #define SENSOR_INDEX_POS (5)
47 #define SENSOR_INDEX_MASK (0x0007 << SENSOR_INDEX_POS)
48 #define SET_SENSOR_ID(_type, _index) ((((_type) << SENSOR_TYPE_POS) & SENSOR_TYPE_MASK) | (((_index) << SENSOR_INDEX_POS) & SENSOR_INDEX_MASK))
49 #define GET_SENSOR_INDEX(_sensorID) ((_sensorID & SENSOR_INDEX_MASK) >> SENSOR_INDEX_POS)
50 #define GET_SENSOR_TYPE(_sensorID) ((_sensorID & SENSOR_TYPE_MASK) >> SENSOR_TYPE_POS)
51 
52 
53 // on the MCCI (Myriad) device, endpoint numbering starts at 0
54 #define ENDPOINT_DEV_IN 0
55 #define ENDPOINT_DEV_OUT 0
56 #define ENDPOINT_DEV_MSGS_IN 1
57 #define ENDPOINT_DEV_MSGS_OUT 1
58 #define ENDPOINT_DEV_INT_IN 2
59 #define ENDPOINT_DEV_INT_OUT 2
60 
61 
62 // on host, endpoint numbering starts at 1 and has a 0x80 when the
63 // direction is into the host
64 #define ENDPOINT_HOST_IN (ENDPOINT_DEV_OUT + 1 + 0x80)
65 #define ENDPOINT_HOST_OUT (ENDPOINT_DEV_IN + 1)
66 #define ENDPOINT_HOST_MSGS_IN (ENDPOINT_DEV_MSGS_OUT + 1 + 0x80)
67 #define ENDPOINT_HOST_MSGS_OUT (ENDPOINT_DEV_MSGS_IN + 1)
68 #define ENDPOINT_HOST_INT_IN (ENDPOINT_DEV_INT_OUT + 1 + 0x80)
69 #define ENDPOINT_HOST_INT_OUT (ENDPOINT_DEV_INT_IN + 1)
70 
71 enum log_level {
72  NO_LOG = 0x0000,
73  LOG_ERR = 0x0001,
74  INFO = 0x0002,
75  WARNING = 0x0003,
76  DEBUG = 0x0004,
77  VERBOSE = 0x0005,
78  TRACE = 0x0006,
80 };
81 
82 #define FREE_CONT 0x8001
83 
84 static const int MAX_TRANSFER_SIZE = 848 * 800 + sizeof(bulk_message_video_stream); // max size on ENDPOINT_HOST_IN
85 static const int USB_TIMEOUT = 10000/*ms*/;
86 static const int BUFFER_SIZE = 1024; // Max size for control transfers
87 
88 const std::map<PixelFormat, rs2_format> tm2_formats_map =
89 {
104 };
105 
107 {
108  return tm2_formats_map.at(static_cast<const PixelFormat>(format));
109 }
110 
111 inline int tm2_sensor_type(rs2_stream rtype)
112 {
113  if(rtype == RS2_STREAM_FISHEYE)
114  return SensorType::Fisheye;
115  else if(rtype == RS2_STREAM_ACCEL)
117  else if(rtype == RS2_STREAM_GYRO)
118  return SensorType::Gyro;
119  else if(rtype == RS2_STREAM_POSE)
120  return SensorType::Pose;
121  else
122  throw librealsense::invalid_value_exception("Invalid stream type");
123 }
124 
125 inline int tm2_sensor_id(rs2_stream type, int stream_index)
126 {
127  int stream_type = tm2_sensor_type(type);
128  if (stream_type == SensorType::Fisheye)
129  stream_index--;
130 
131  return stream_index;
132 }
133 
134 namespace librealsense
135 {
139  };
140 
143  float temperature;
144  };
145 
148  };
149 
151 
153  {
154  public:
155  float query() const override { return _ep.get_temperature(_type).fTemperature; }
156 
157  option_range get_range() const override { return _range; }
158 
159  bool is_enabled() const override { return true; }
160 
161  explicit temperature_option(tm2_sensor& ep, temperature_type type) : _ep(ep), _type(type),
162  _range(option_range{ 0, _ep.get_temperature(_type).fThreshold, 0, 0 }) { }
163 
164  private:
168  };
169 
171  {
172  public:
173  float query() const override { return _ep.get_exposure(); }
174 
175  void set(float value) override { return _ep.set_exposure(value); }
176 
177  const char* get_description() const override { return "Exposure"; }
178 
179  bool is_enabled() const override { return true; }
180 
181  explicit exposure_option(tm2_sensor& ep) : _ep(ep),
182  option_base(option_range{ 200, 16000, 0, 200 }) { }
183 
184  private:
186  };
187 
189  {
190  public:
191  float query() const override { return !_ep.is_manual_exposure(); }
192 
193  void set(float value) override { return _ep.set_manual_exposure(1.f - value); }
194 
195  const char* get_description() const override { return "Auto-Exposure"; }
196 
197  bool is_enabled() const override { return true; }
198 
199  explicit exposure_mode_option(tm2_sensor& ep) : _ep(ep),
200  option_base(option_range{ 0, 1, 1, 1 }) { }
201 
202  private:
204  };
205 
206  class gain_option : public option_base
207  {
208  public:
209  float query() const override
210  {
211  return _ep.get_gain();
212  }
213 
214  void set(float value) override
215  {
216  return _ep.set_gain(value);
217  }
218 
219  const char* get_description() const override { return "Gain"; }
220 
221  bool is_enabled() const override { return true; }
222 
223  explicit gain_option(tm2_sensor& ep) : _ep(ep),
224  option_base(option_range{ 1, 10, 0, 1 }) { }
225 
226  private:
228  };
229 
230  template <SIXDOF_MODE flag, SIXDOF_MODE depends_on, bool invert = false>
232  {
233  public:
234  float query() const override { return !!(s._tm_mode & flag) ^ invert ? 1 : 0; }
235 
236  void set(float value) override {
237  if (s._is_streaming)
238  throw io_exception("Option is read-only while streaming");
239  s._tm_mode = (!!value ^ invert) ? (s._tm_mode | flag) : (s._tm_mode & ~flag);
240  }
241 
242  const char* get_description() const override { return description; }
243 
244  bool is_enabled() const override { return !depends_on || (s._tm_mode & depends_on) ? true : false; }
245 
246  bool is_read_only() const override { return s._is_streaming; }
247 
248  explicit tracking_mode_option(tm2_sensor& sensor, const char *description_) :
249  s(sensor), description(description_), option_base(option_range{ 0, 1, 1, !!(sensor._tm_mode & flag) ^ invert ? 1.f : 0.f }) { }
250 
251  private:
253  const char *description;
254  };
255 
257  {
258  public:
259  const char* get_description() const override
260  {
261  return "Current T265 Asic Temperature (degree celsius)";
262  }
264  };
265 
267  {
268  public:
269 
270  const char* get_description() const override
271  {
272  return "Current T265 IMU Temperature (degree celsius)";
273  }
274  explicit motion_temperature_option(tm2_sensor& ep) :temperature_option(ep, temperature_type::TEMPERATURE_TYPE_MOTION) { }
275  };
276 
278  {
279  public:
281  rs2_metadata_type get(const frame& frm) const override
282  {
284  {
285  if (auto* vf = dynamic_cast<const video_frame*>(&frm))
286  {
287  const video_frame_metadata* md = reinterpret_cast<const video_frame_metadata*>(frm.additional_data.metadata_blob.data());
288  return (rs2_metadata_type)(md->exposure_time);
289  }
290  }
292  {
293  // Note: additional_data.system_time is the arrival time
294  // (backend_time is what we have traditionally called
295  // system_time)
296  if (auto* vf = dynamic_cast<const video_frame*>(&frm))
297  {
298  return (rs2_metadata_type)(vf->additional_data.system_time);
299  }
300  if (auto* mf = dynamic_cast<const motion_frame*>(&frm))
301  {
302  return (rs2_metadata_type)(mf->additional_data.system_time);
303  }
304  if (auto* pf = dynamic_cast<const pose_frame*>(&frm))
305  {
306  return (rs2_metadata_type)(pf->additional_data.system_time);
307  }
308  }
310  {
311  if (auto* vf = dynamic_cast<const video_frame*>(&frm))
312  {
313  return (rs2_metadata_type)(vf->additional_data.timestamp*1e+3);
314  }
315  if (auto* mf = dynamic_cast<const motion_frame*>(&frm))
316  {
317  return (rs2_metadata_type)(mf->additional_data.timestamp*1e+3);
318  }
319  if (auto* pf = dynamic_cast<const pose_frame*>(&frm))
320  {
321  return (rs2_metadata_type)(pf->additional_data.timestamp*1e+3);
322  }
323  }
324  if (_type == RS2_FRAME_METADATA_TEMPERATURE)
325  {
326  if (auto* mf = dynamic_cast<const motion_frame*>(&frm))
327  {
328  const motion_frame_metadata* md = reinterpret_cast<const motion_frame_metadata*>(frm.additional_data.metadata_blob.data());
329  return (rs2_metadata_type)(md->temperature);
330  }
331  }
332  return 0;
333  }
334 
335  bool supports(const frame& frm) const override
336  {
338  {
339  return dynamic_cast<const video_frame*>(&frm) != nullptr;
340  }
341  if (_type == RS2_FRAME_METADATA_TEMPERATURE)
342  {
343  return dynamic_cast<const motion_frame*>(&frm) != nullptr;
344  }
346  {
347  return dynamic_cast<const video_frame*>(&frm) != nullptr || dynamic_cast<const motion_frame*>(&frm) != nullptr;
348  }
350  {
351  return (dynamic_cast<const video_frame*>(&frm) != nullptr) || (dynamic_cast<const motion_frame*>(&frm) != nullptr) || (dynamic_cast<const pose_frame*>(&frm) != nullptr);
352  }
353  return false;
354  }
355  private:
357  };
358 
359  tm2_sensor::tm2_sensor(tm2_device* owner)
360  : sensor_base("Tracking Module", owner, this), _device(owner)
361  {
362  LOG_DEBUG("Making a sensor " << this);
363  _source.set_max_publish_list_size(256); //increase frame source queue size for TM2
364  _data_dispatcher = std::make_shared<dispatcher>(256); // make a queue of the same size to dispatch data messages
365  _data_dispatcher->start();
368  //Replacing md parser for TIME_OF_ARRIVAL and FRAME_TIMESTAMP
373 
374  // Set log level
375  bulk_message_request_log_control log_request = {{ sizeof(log_request), DEV_LOG_CONTROL }};
376  log_request.bVerbosity = log_level::LOG_ERR;
377  log_request.bLogMode = 0x1; // rollover mode
378  bulk_message_response_log_control log_response = {};
379  _device->bulk_request_response(log_request, log_response);
380 
381  // start log thread
382  _log_poll_thread_stop = false;
383  _log_poll_thread = std::thread(&tm2_sensor::log_poll, this);
384 
385  // start time sync thread
386  last_ts = { std::chrono::duration<double, std::milli>(0) };
387  device_to_host_ns = 0;
388  _time_sync_thread_stop = false;
389  _time_sync_thread = std::thread(&tm2_sensor::time_sync, this);
390  }
391 
393  {
394  // We have to do everything in dispose() because the tm2_device gets destroyed
395  // before this destructor gets called (since it is a member
396  // variable)
397  }
398 
400  {
401  // It is important not to throw here because this gets called
402  // from ~tm2_device
403  try {
404  _data_dispatcher->stop();
405  // Use this as a proxy to know if we are still able to communicate with the device
406  bool device_valid = _stream_request && _interrupt_request;
407 
408  if (device_valid && _is_streaming)
409  stop();
410 
411  if (device_valid && _is_opened)
412  close();
413 
414  _time_sync_thread_stop = true;
415  _time_sync_thread.join();
416 
417  if (device_valid) {
418  stop_stream();
419  stop_interrupt();
420  }
421 
422  _log_poll_thread_stop = true;
423  _log_poll_thread.join();
424  }
425  catch (...) {
426  LOG_ERROR("An error has occurred while disposing the sensor!");
427  }
428 
429  }
430 
431  //sensor
434  {
435  stream_profiles results;
436  std::map<uint8_t, std::shared_ptr<stream_profile_interface> > profile_map;
437 
439  char buffer[BUFFER_SIZE];
440  auto response = (bulk_message_response_get_supported_raw_streams *)buffer;
441  _device->bulk_request_response(request, *response, BUFFER_SIZE);
442 
443  // Note the pose stream is special. We need to create one for
444  // librealsense below, but it is not a raw_stream as defined
445  // by our current protocol.
446 
447  _supported_raw_streams.clear();
448  for(int i = 0; i < response->wNumSupportedStreams; i++) {
449  auto tm_stream = response->stream[i];
450 
451  auto sensor_type = GET_SENSOR_TYPE(tm_stream.bSensorID);
452  auto sensor_id = GET_SENSOR_INDEX(tm_stream.bSensorID);
453  if(sensor_type == SensorType::Fisheye) {
454  if (sensor_id > 1) {
455  LOG_ERROR("Fisheye with sensor id > 1: " << sensor_id);
456  continue;
457  }
458 
460  rs2_format format = rs2_format_from_tm2(tm_stream.bPixelFormat);
461  platform::stream_profile p = { tm_stream.wWidth, tm_stream.wHeight, tm_stream.wFramesPerSecond, uint32_t(format) };
462  auto profile = std::make_shared<video_stream_profile>(p);
463  profile->set_dims(p.width, p.height);
464  profile->set_stream_type(stream);
465  profile->set_stream_index(sensor_id + 1); // for nice presentation by the viewer - add 1 to stream index
466  profile->set_format(format);
467  profile->set_framerate(p.fps);
468  profile->set_unique_id(environment::get_instance().generate_stream_id());
469  stream_profile sp = { profile->get_format(), stream, profile->get_stream_index(), p.width, p.height, p.fps };
470  auto intrinsics = get_intrinsics(sp);
471 
472  profile->set_intrinsics([intrinsics]() { return intrinsics; });
474  results.push_back(profile);
475  profile_map[tm_stream.bSensorID] = profile;
476 
477  LOG_INFO("Added a fisheye sensor id: " << sensor_id);
478  }
479  else if(sensor_type == SensorType::Gyro || sensor_type == SensorType::Accelerometer) {
480  std::string sensor_str = sensor_type == SensorType::Gyro ? "gyro" : "accel";
481  if(sensor_id != 0) {
482  LOG_ERROR(sensor_str << " with sensor id != 0: " << sensor_id);
483  continue;
484  }
485 
488  if(stream == RS2_STREAM_GYRO && tm_stream.wFramesPerSecond != 200) {
489  LOG_DEBUG("Skipping gyro FPS " << tm_stream.wFramesPerSecond);
490  continue;
491  }
492  if(stream == RS2_STREAM_ACCEL && tm_stream.wFramesPerSecond != 62) {
493  LOG_DEBUG("Skipping accel FPS " << tm_stream.wFramesPerSecond);
494  continue;
495  }
496  auto profile = std::make_shared<motion_stream_profile>(platform::stream_profile{ uint32_t(format), 0, 0, tm_stream.wFramesPerSecond });
497  profile->set_stream_type(stream);
498  profile->set_stream_index(sensor_id); // for nice presentation by the viewer - add 1 to stream index
499  profile->set_format(format);
500  profile->set_framerate(tm_stream.wFramesPerSecond);
501  profile->set_unique_id(environment::get_instance().generate_stream_id());
503  profile->set_intrinsics([intrinsics]() { return intrinsics; });
504 
506  results.push_back(profile);
507  profile_map[tm_stream.bSensorID] = profile;
508 
509  LOG_INFO("Added a " << sensor_str << " sensor id: " << sensor_id << " at " << tm_stream.wFramesPerSecond << "Hz");
510  }
511  else if(sensor_type == SensorType::Velocimeter) {
512  LOG_INFO("Skipped a velocimeter stream");
513  // Nothing to do for velocimeter streams yet
514  continue;
515  }
516  // This one should never show up, because the device doesn't
517  // actually stream poses over the bulk endpoint
518  else if(sensor_type == SensorType::Pose) {
519  LOG_ERROR("Found a pose stream but should not have one here");
520  continue;
521  }
522  else if(sensor_type == SensorType::Mask) {
523  //TODO: implement Mask
524  continue;
525  }
526  else {
527  LOG_ERROR("Invalid stream type " << sensor_type << " with sensor id: " << sensor_id);
528  throw io_exception("Invalid stream type");
529  }
530 
531  _supported_raw_streams.push_back(tm_stream);
532  }
533  LOG_DEBUG("Total streams " << _supported_raw_streams.size());
534 
535  // Add a "special" pose stream profile, because we handle this
536  // one differently and it is implicitly always available
538  const uint32_t pose_fps = 200;
539  auto profile = std::make_shared<pose_stream_profile>(platform::stream_profile{ uint32_t(format), 0, 0, pose_fps });
540  profile->set_stream_type(RS2_STREAM_POSE);
541  profile->set_stream_index(0);
542  profile->set_format(format);
543  profile->set_framerate(pose_fps);
544  profile->set_unique_id(environment::get_instance().generate_stream_id());
545 
547  // The RS2_STREAM_POSE profile is the reference for extrinsics
548  auto reference_profile = profile;
549  results.push_back(profile);
550  profile_map[SET_SENSOR_ID(SensorType::Pose, 0)] = profile;
551 
552  //add extrinsic parameters
553  for (auto profile : results)
554  {
555  auto current_extrinsics = get_extrinsics(*profile, 0); // TODO remove 0
556  environment::get_instance().get_extrinsics_graph().register_extrinsics(*profile, *reference_profile, current_extrinsics);
557  }
558 
559  auto accel_it = std::find_if(results.begin(), results.end(),
560  [](std::shared_ptr<stream_profile_interface> spi) { return RS2_STREAM_ACCEL == spi->get_stream_type(); });
561  auto gyro_it = std::find_if(results.begin(), results.end(),
562  [](std::shared_ptr<stream_profile_interface> spi) { return RS2_STREAM_GYRO == spi->get_stream_type(); });
563  if ((accel_it != results.end()) && (gyro_it != results.end()))
564  environment::get_instance().get_extrinsics_graph().register_same_extrinsics(*(accel_it->get()), *(gyro_it->get()));
565  return results;
566  }
567 
568  void tm2_sensor::open(const stream_profiles& requests)
569  {
570  LOG_DEBUG("T265 open");
571  std::lock_guard<std::mutex> lock(_tm_op_lock);
572  if (_is_streaming)
573  throw wrong_api_call_sequence_exception("open(...) failed. T265 device is streaming!");
574  else if (_is_opened)
575  throw wrong_api_call_sequence_exception("open(...) failed. T265 device is already opened!");
576 
578  _source.set_sensor(this->shared_from_this());
579 
580  //TODO - TM2_API currently supports a single profile is supported per stream.
581  // this function uses stream index to determine stream profile, and just validates the requested profile.
582  // need to fix this to search among supported profiles per stream. ( use sensor_base::resolve_requests?)
583  if (_loopback)
584  {
585  auto& loopback_sensor = _loopback->get_sensor(0);
586  //TODO: Future work: filter out raw streams according to requested output.
587  loopback_sensor.open(loopback_sensor.get_stream_profiles());
588  }
589 
590  _active_raw_streams.clear();
591  for(auto p : _supported_raw_streams) {
592  p.bOutputMode = 0; // disable output
593  _active_raw_streams.push_back(p);
594  }
595 
596  for (auto&& r : requests) {
597  auto sp = to_profile(r.get());
598  int stream_index = sp.index;
599  rs2_stream stream_type = r->get_stream_type();
600  int tm_sensor_type = tm2_sensor_type(stream_type);
601  int tm_sensor_id = tm2_sensor_id(stream_type, stream_index);
602  LOG_INFO("Request for stream type " << r->get_stream_type() << " with stream index " << stream_index);
603 
604  if(stream_type == RS2_STREAM_POSE) {
605  if(stream_index != 0)
606  throw invalid_value_exception("Invalid profile configuration - pose stream only supports index 0");
607  LOG_DEBUG("Pose output enabled");
608  _pose_output_enabled = true;
609  continue;
610  }
611 
612  bool found = false;
613  for(auto & tm_profile : _active_raw_streams) {
614  if(GET_SENSOR_TYPE(tm_profile.bSensorID) == tm_sensor_type &&
615  GET_SENSOR_INDEX(tm_profile.bSensorID) == tm_sensor_id &&
616  tm_profile.wFramesPerSecond == sp.fps) {
617 
618  if(tm_sensor_type != SensorType::Fisheye ||
619  (tm_profile.wWidth == sp.width && tm_profile.wHeight == sp.height &&
620  rs2_format_from_tm2(tm_profile.bPixelFormat) == sp.format)) {
622  LOG_ERROR("Streaming T265 video over USB " << platform::usb_spec_names.at(_device->usb_info.conn_spec) << " is unreliable, please use USB 3 or only stream poses");
623 
624  found = true;
625  tm_profile.bOutputMode = 1;
626  break;
627  }
628  }
629  }
630  if(!found)
631  throw invalid_value_exception("Invalid profile configuration - no matching stream");
632  }
633 
634  int fisheye_streams = 0;
635  for(auto tm_profile : _active_raw_streams)
636  if(GET_SENSOR_TYPE(tm_profile.bSensorID) == SensorType::Fisheye && tm_profile.bOutputMode)
637  fisheye_streams++;
638 
639  if(fisheye_streams == 1)
640  throw invalid_value_exception("Invalid profile configuration - setting a single FE stream is not supported");
641 
642  int num_active = 0;
643  for(auto p : _active_raw_streams)
644  if(p.bOutputMode)
645  num_active++;
646  if(_pose_output_enabled) num_active++;
647  LOG_INFO("Activated " << num_active << "/" << _active_raw_streams.size() + 1 << " streams");
648 
649  // Construct message to the FW to activate the streams we want
650  char buffer[BUFFER_SIZE];
651  auto request = (bulk_message_request_raw_streams_control *)buffer;
652  request->header.wMessageID = _loopback ? DEV_RAW_STREAMS_PLAYBACK_CONTROL : DEV_RAW_STREAMS_CONTROL;
653  request->wNumEnabledStreams = uint32_t(_active_raw_streams.size());
654  memcpy(request->stream, _active_raw_streams.data(), request->wNumEnabledStreams*sizeof(supported_raw_stream_libtm_message));
655  request->header.dwLength = request->wNumEnabledStreams * sizeof(supported_raw_stream_libtm_message) + sizeof(request->header) + sizeof(request->wNumEnabledStreams);
657  for(int i = 0; i < 5; i++) {
658  _device->bulk_request_response(*request, response, sizeof(response), false);
659  if(response.header.wStatus == DEVICE_BUSY) {
660  LOG_WARNING("Device is busy, trying again");
661  std::this_thread::sleep_for(std::chrono::seconds(1));
662  }
663  else if(response.header.wStatus == INVALID_REQUEST_LEN)
664  throw io_exception("open(...) failed. Invalid stream request packet");
665  else if(response.header.wStatus == INVALID_PARAMETER)
666  throw io_exception("open(...) failed. Invalid stream specification");
667  else if(response.header.wStatus != SUCCESS)
668  throw io_exception(to_string() << "open(...) unknown error " << status_name(response.header));
669  else
670  break;
671  }
672  if(response.header.wStatus == DEVICE_BUSY)
673  throw wrong_api_call_sequence_exception("open(...) failed to configure streams. T265 is running!");
674 
675  bulk_message_request_6dof_control control_request = {{ sizeof(control_request), SLAM_6DOF_CONTROL }};
676  control_request.bEnable = _pose_output_enabled;
677  control_request.bMode = _tm_mode;
678  bulk_message_response_6dof_control control_response = {};
679  _device->bulk_request_response(control_request, control_response, sizeof(control_response), false);
680  if(control_response.header.wStatus == DEVICE_BUSY)
681  throw wrong_api_call_sequence_exception("open(...) failed. T265 is running!");
682  else if(control_response.header.wStatus != SUCCESS)
683  throw io_exception(to_string() << "open(...) unknown error opening " << status_name(response.header));
684 
685  _is_opened = true;
686  set_active_streams(requests);
687  }
688 
690  {
691  std::lock_guard<std::mutex> lock(_tm_op_lock);
692  LOG_DEBUG("T265 close");
693  if (_is_streaming)
694  throw wrong_api_call_sequence_exception("close() failed. T265 device is streaming!");
695  else if (!_is_opened)
696  throw wrong_api_call_sequence_exception("close() failed. T265 device was not opened!");
697 
698  if (_loopback) {
699  auto& loopback_sensor = _loopback->get_sensor(0);
700  loopback_sensor.close();
701  }
702 
703  //reset active profiles
704  _active_raw_streams.clear();
705  _pose_output_enabled = false;
706 
707  _is_opened = false;
708  set_active_streams({});
709  }
710 
712  {
713  //TODO
714  /*
715  auto to_nanos = [](rs2_time_t t) { return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::duration<rs2_time_t, std::milli>(t)).count(); };
716  auto frame_ptr = fref.frame;
717  auto get_md_or_default = [frame_ptr](rs2_frame_metadata_value md) {
718  rs2_metadata_type v = 0;
719  if (frame_ptr->supports_frame_metadata(md))
720  v = frame_ptr->get_frame_metadata(md);
721  return v;
722  };
723 
724 
725  int stream_index = fref.frame->get_stream()->get_stream_index() - 1;
726  auto lrs_stream = fref.frame->get_stream()->get_stream_type();
727  SensorType tm_stream;
728  if (!try_convert(lrs_stream, tm_stream))
729  {
730  LOG_ERROR("Failed to convert lrs stream " << lrs_stream << " to tm stream");
731  return;
732  }
733 
734  //Pass frames to firmware
735  if (auto vframe = As<video_frame>(fref.frame))
736  {
737  TrackingData::VideoFrame f = {};
738  f.sensorIndex = stream_index;
739  //TODO: Librealsense frame numbers are 64 bit. This is a potentional interface gap
740  f.frameId = vframe->additional_data.frame_number;
741  f.profile.set(vframe->get_width(), vframe->get_height(), vframe->get_stride(), convertToTm2PixelFormat(vframe->get_stream()->get_format()));
742  f.exposuretime = get_md_or_default(RS2_FRAME_METADATA_ACTUAL_EXPOSURE);
743  f.frameLength = vframe->get_height()*vframe->get_stride()* (vframe->get_bpp() / 8);
744  f.data = vframe->data.data();
745  f.timestamp = to_nanos(vframe->additional_data.timestamp);
746  f.systemTimestamp = to_nanos(vframe->additional_data.backend_timestamp);
747  f.arrivalTimeStamp = to_nanos(vframe->additional_data.system_time);
748  auto sts = _tm_dev->SendFrame(f);
749  if (sts != Status::SUCCESS)
750  {
751  LOG_ERROR("Failed to send video frame to TM");
752  }
753  }
754  else if (auto mframe = As<motion_frame>(fref.frame))
755  {
756  auto st = mframe->get_stream()->get_stream_type();
757  if (st == RS2_STREAM_ACCEL)
758  {
759  TrackingData::AccelerometerFrame f{};
760  auto mdata = reinterpret_cast<float*>(mframe->data.data());
761  f.acceleration.set(mdata[0], mdata[1], mdata[2]);
762  f.frameId = mframe->additional_data.frame_number;
763  f.sensorIndex = stream_index;
764  f.temperature = get_md_or_default(RS2_FRAME_METADATA_TEMPERATURE);
765  f.timestamp = to_nanos(mframe->additional_data.timestamp);
766  f.systemTimestamp = to_nanos(mframe->additional_data.backend_timestamp);
767  f.arrivalTimeStamp = to_nanos(mframe->additional_data.system_time);
768  auto sts = _tm_dev->SendFrame(f);
769  if (sts != Status::SUCCESS)
770  {
771  LOG_ERROR("Failed to send video frame to TM");
772  }
773  }
774  else if(st == RS2_STREAM_GYRO)
775  {
776  TrackingData::GyroFrame f{};
777  auto mdata = reinterpret_cast<float*>(mframe->data.data());
778  f.angularVelocity.set(mdata[0], mdata[1], mdata[2]);
779  f.frameId = mframe->additional_data.frame_number;
780  f.sensorIndex = stream_index;
781  f.temperature = get_md_or_default(RS2_FRAME_METADATA_TEMPERATURE);
782  f.timestamp = to_nanos(mframe->additional_data.timestamp);
783  f.systemTimestamp = to_nanos(mframe->additional_data.backend_timestamp);
784  f.arrivalTimeStamp = to_nanos(mframe->additional_data.system_time);
785  auto sts = _tm_dev->SendFrame(f);
786  if (sts != Status::SUCCESS)
787  {
788  LOG_ERROR("Failed to send video frame to TM");
789  }
790  }
791  else if (auto mframe = As<pose_frame>(fref.frame))
792  {
793  //Ignore
794  }
795  else
796  {
797  LOG_ERROR("Unhandled motion frame type");
798  }
799  }
800  else
801  {
802  LOG_ERROR("Unhandled frame type");
803  }
804  */
805  }
806 
808  {
809  std::lock_guard<std::mutex> lock(_tm_op_lock);
810  LOG_DEBUG("Starting T265");
811  if (_is_streaming)
812  throw wrong_api_call_sequence_exception("start_streaming(...) failed. T265 device is already streaming!");
813  else if (!_is_opened)
814  throw wrong_api_call_sequence_exception("start_streaming(...) failed. T265 device was not opened!");
815 
816  start_interrupt();
817  start_stream();
818 
819  _source.set_callback(callback);
821 
822  bulk_message_request_start request = {{ sizeof(request), DEV_START }};
823  bulk_message_response_start response = {};
824  _device->bulk_request_response(request, response, sizeof(response), false);
825  if(response.header.wStatus == DEVICE_BUSY)
826  throw wrong_api_call_sequence_exception("open(...) failed. T265 is already started!");
827  else if(response.header.wStatus != SUCCESS)
828  throw io_exception(to_string() << "open(...) unknown error starting " << status_name(response.header));
829 
830  LOG_DEBUG("T265 started");
831 
832  if (_loopback) {
833  auto& loopback_sensor = _loopback->get_sensor(0);
834  auto handle_file_frames = [&](frame_holder fref) {
836  };
837 
838  frame_callback_ptr file_frames_callback = { new internal_frame_callback<decltype(handle_file_frames)>(handle_file_frames),
839  [](rs2_frame_callback* p) { p->release(); } };
840  loopback_sensor.start(file_frames_callback);
841  }
842 
843  _is_streaming = true;
844  }
845 
847  {
848  std::lock_guard<std::mutex> lock(_tm_op_lock);
849  LOG_DEBUG("Stopping T265");
850  if (!_is_streaming)
851  throw wrong_api_call_sequence_exception("stop_streaming() failed. T265 device is not streaming!");
852 
853  if (_loopback) {
854  auto& loopback_sensor = _loopback->get_sensor(0);
855  loopback_sensor.stop();
856  }
857 
858  // Send the stop message
859  bulk_message_request_stop request = {{ sizeof(request), DEV_STOP }};
860  bulk_message_response_stop response = {};
861  _device->bulk_request_response(request, response, sizeof(response), false);
862  if(response.header.wStatus == TIMEOUT)
863  LOG_WARNING("Got a timeout while trying to stop");
864  else if(response.header.wStatus != SUCCESS)
865  throw io_exception(to_string() << "Unknown error stopping " << status_name(response.header));
866 
867  LOG_DEBUG("T265 stopped");
868 
869  stop_stream();
870  stop_interrupt();
871 
873  _is_streaming = false;
874  }
875 
877  {
878  rs2_stream rtype = profile.stream;
879  int rs2_index = profile.index;
880  int sensor_type = tm2_sensor_type(rtype);
881  int sensor_id = tm2_sensor_id(rtype, rs2_index);
882 
884  request.bCameraID = SET_SENSOR_ID(sensor_type, sensor_id);
886  _device->bulk_request_response(request, response);
887 
889  result.width = response.intrinsics.dwWidth;
890  result.height = response.intrinsics.dwHeight;
891  result.ppx = response.intrinsics.flPpx;
892  result.ppy = response.intrinsics.flPpy;
893  result.fx = response.intrinsics.flFx;
894  result.fy = response.intrinsics.flFy;
895  if(response.intrinsics.dwDistortionModel == 1) result.model = RS2_DISTORTION_FTHETA;
896  else if(response.intrinsics.dwDistortionModel == 3) result.model = RS2_DISTORTION_NONE;
897  else if(response.intrinsics.dwDistortionModel == 4) result.model = RS2_DISTORTION_KANNALA_BRANDT4;
898  else
899  throw invalid_value_exception("Invalid distortion model");
900  librealsense::copy_array<true>(result.coeffs, response.intrinsics.flCoeffs);
901 
902  return result;
903  }
904 
906  {
907  rs2_stream rtype = profile.get_stream_type();
908  int rs2_index = profile.get_stream_index();
909  int sensor_type = tm2_sensor_type(rtype);
910  int sensor_id = tm2_sensor_id(rtype, rs2_index);
911 
913  request.bMotionID = SET_SENSOR_ID(sensor_type, sensor_id);
915  _device->bulk_request_response(request, response);
916 
918  librealsense::copy_2darray<true>(result.data, response.intrinsics.flData);
919  librealsense::copy_array<true>(result.noise_variances, response.intrinsics.flNoiseVariances);
920  librealsense::copy_array<true>(result.bias_variances, response.intrinsics.flBiasVariances);
921  return result;
922  }
923 
925  {
926  rs2_stream rtype = profile.get_stream_type();
927  int rs2_index = profile.get_stream_index();
928  int sensor_type = tm2_sensor_type(rtype);
929  int sensor_id = tm2_sensor_id(rtype, rs2_index);
930 
931  bulk_message_request_get_extrinsics request = {{ sizeof(request), DEV_GET_EXTRINSICS }};
932  request.bSensorID = SET_SENSOR_ID(sensor_type, sensor_id);
934  _device->bulk_request_response(request, response);
935 
937  LOG_ERROR("Unexpected reference sensor id " << response.extrinsics.bReferenceSensorID);
938  }
939 
941  librealsense::copy_array<true>(result.rotation, response.extrinsics.flRotation);
942  librealsense::copy_array<true>(result.translation, response.extrinsics.flTranslation);
943 
944  return result;
945  }
946 
948  {
950 
951  int stream_index = stream_profile.get_stream_index() - 1;
952  if(stream_index != 0 && stream_index != 1)
953  throw invalid_value_exception("Invalid fisheye stream");
954 
955  request.bCameraID = SET_SENSOR_ID(SensorType::Fisheye, stream_index);
956  request.intrinsics.dwWidth = intr.width;
957  request.intrinsics.dwHeight = intr.height;
958  request.intrinsics.flFx = intr.fx;
959  request.intrinsics.flFy = intr.fy;
960  request.intrinsics.flPpx = intr.ppx;
961  request.intrinsics.flPpy = intr.ppy;
963  else if(intr.model == RS2_DISTORTION_NONE) request.intrinsics.dwDistortionModel = 3;
965  else
966  throw invalid_value_exception("Invalid distortion model");
968 
970  _device->bulk_request_response(request, response);
971  }
972 
974  {
975  switch (to_profile.get_stream_type()) {
976  case RS2_STREAM_POSE:
977  set_extrinsics_to_ref(from_profile.get_stream_type(), from_profile.get_stream_index(), extr);
978  break;
979  case RS2_STREAM_FISHEYE:
980  {
981  auto inv = [](const rs2_extrinsics& src) {
983  auto dst_rotation = dst.rotation;
984  for (auto i : { 0,3,6,1,4,7,2,5,8 }) { *dst_rotation++ = src.rotation[i]; }
985  dst.translation[0] = - src.rotation[0] * src.translation[0] - src.rotation[3] * src.translation[1] - src.rotation[6] * src.translation[2];
986  dst.translation[1] = - src.rotation[1] * src.translation[0] - src.rotation[4] * src.translation[1] - src.rotation[7] * src.translation[2];
987  dst.translation[2] = - src.rotation[2] * src.translation[0] - src.rotation[5] * src.translation[1] - src.rotation[8] * src.translation[2];
988  return dst;
989  };
990 
991  auto mult = [](const rs2_extrinsics& a, const rs2_extrinsics& b) {
992  rs2_extrinsics tf;
993  tf.rotation[0] = a.rotation[0] * b.rotation[0] + a.rotation[1] * b.rotation[3] + a.rotation[2] * b.rotation[6];
994  tf.rotation[1] = a.rotation[0] * b.rotation[1] + a.rotation[1] * b.rotation[4] + a.rotation[2] * b.rotation[7];
995  tf.rotation[2] = a.rotation[0] * b.rotation[2] + a.rotation[1] * b.rotation[5] + a.rotation[2] * b.rotation[8];
996  tf.rotation[3] = a.rotation[3] * b.rotation[0] + a.rotation[4] * b.rotation[3] + a.rotation[5] * b.rotation[6];
997  tf.rotation[4] = a.rotation[3] * b.rotation[1] + a.rotation[4] * b.rotation[4] + a.rotation[5] * b.rotation[7];
998  tf.rotation[5] = a.rotation[3] * b.rotation[2] + a.rotation[4] * b.rotation[5] + a.rotation[5] * b.rotation[8];
999  tf.rotation[6] = a.rotation[6] * b.rotation[0] + a.rotation[7] * b.rotation[3] + a.rotation[8] * b.rotation[6];
1000  tf.rotation[7] = a.rotation[6] * b.rotation[1] + a.rotation[7] * b.rotation[4] + a.rotation[8] * b.rotation[7];
1001  tf.rotation[8] = a.rotation[6] * b.rotation[2] + a.rotation[7] * b.rotation[5] + a.rotation[8] * b.rotation[8];
1002  tf.translation[0] = a.rotation[0] * b.translation[0] + a.rotation[1] * b.translation[1] + a.rotation[2] * b.translation[2] + a.translation[0];
1003  tf.translation[1] = a.rotation[3] * b.translation[0] + a.rotation[4] * b.translation[1] + a.rotation[5] * b.translation[2] + a.translation[1];
1004  tf.translation[2] = a.rotation[6] * b.translation[0] + a.rotation[7] * b.translation[1] + a.rotation[8] * b.translation[2] + a.translation[2];
1005  return tf;
1006  };
1007 
1008  auto& H_fe1_fe2 = extr;
1009  auto H_fe2_fe1 = inv(H_fe1_fe2);
1010  auto H_fe1_pose = get_extrinsics(from_profile, 0);
1011  auto H_fe2_pose = mult(H_fe2_fe1, H_fe1_pose); //H_fe2_pose = H_fe2_fe1 * H_fe1_pose
1012  set_extrinsics_to_ref(RS2_STREAM_FISHEYE, 2, H_fe2_pose);
1013  break;
1014  }
1015  default:
1016  throw invalid_value_exception("Invalid stream type: set_extrinsics only support fisheye stream");
1017  }
1018  }
1019 
1020  void tm2_sensor::set_extrinsics_to_ref(rs2_stream stream_type, int stream_index, const rs2_extrinsics& extr)
1021  {
1022  int sensor_type = tm2_sensor_type(stream_type);
1023  int sensor_id = tm2_sensor_id(stream_type, stream_index);
1024 
1025  bulk_message_request_set_extrinsics request = {{ sizeof(request), DEV_SET_EXTRINSICS }};
1026  request.bSensorID = SET_SENSOR_ID(sensor_type, sensor_id);
1027  librealsense::copy_array<true>(request.extrinsics.flRotation, extr.rotation);
1028  librealsense::copy_array<true>(request.extrinsics.flTranslation, extr.translation);
1030 
1031  _device->bulk_request_response(request, response);
1032  }
1033 
1035  {
1036  int sensor_type = tm2_sensor_type(stream_profile.get_stream_type());
1037  int sensor_id = tm2_sensor_id(stream_profile.get_stream_type(), stream_profile.get_stream_index());
1038 
1039  if (sensor_id != 0 || (sensor_type != RS2_STREAM_GYRO && sensor_type != RS2_STREAM_ACCEL))
1040  throw invalid_value_exception("Invalid stream index");
1041 
1042  if(sensor_type != SensorType::Gyro || sensor_type != SensorType::Accelerometer)
1043  throw invalid_value_exception("Invalid stream type");
1044 
1046  request.bMotionID = SET_SENSOR_ID(sensor_type, sensor_id);
1047  librealsense::copy_2darray<true>(request.intrinsics.flData, intr.data);
1048  librealsense::copy_array<true>(request.intrinsics.flNoiseVariances, intr.noise_variances);
1049  librealsense::copy_array<true>(request.intrinsics.flBiasVariances, intr.bias_variances);
1050 
1052  _device->bulk_request_response(request, response);
1053  }
1054 
1056  {
1057  bulk_message_request_write_configuration request = {{ sizeof(request), DEV_WRITE_CONFIGURATION }};
1058  request.wTableId = ID_OEM_CAL;
1059  // We send an implicitly 0 length bTable and the right table
1060  // id to tell us to write the calibration
1063  _device->bulk_request_response(request, response);
1064  }
1065 
1067  {
1068  bulk_message_request_reset_configuration request = {{ sizeof(request), DEV_RESET_CONFIGURATION }};
1069  request.wTableId = ID_OEM_CAL;
1071  _device->bulk_request_response(request, response);
1072  }
1073 
1075  {
1076  // TODO: Replace with C++14 move capture
1077  auto frame_holder_ptr = std::make_shared<frame_holder>();
1078  *frame_holder_ptr = std::move(frame);
1079  _data_dispatcher->invoke([this, frame_holder_ptr](dispatcher::cancellable_timer t) {
1080  _source.invoke_callback(std::move(*frame_holder_ptr));
1081  });
1082  }
1083 
1085  {
1086  const pose_data & pose = pose_message.pose;
1087  // pose stream doesn't have a frame number, so we have to keep
1088  // track ourselves
1089  static unsigned long long frame_num = 0;
1090 
1091  auto ts = get_coordinated_timestamp(pose.llNanoseconds);
1092  pose_frame_metadata frame_md = { 0 };
1093  frame_md.arrival_ts = duration_cast<std::chrono::nanoseconds>(ts.arrival_ts).count();
1094 
1095  frame_additional_data additional_data(ts.device_ts.count(), frame_num++, ts.arrival_ts.count(), sizeof(frame_md), (uint8_t*)&frame_md, ts.global_ts.count(), 0, 0, false);
1096 
1097  // Find the frame stream profile
1098  std::shared_ptr<stream_profile_interface> profile = nullptr;
1099  auto profiles = get_stream_profiles();
1100  for (auto&& p : profiles)
1101  {
1102  if (p->get_stream_type() == RS2_STREAM_POSE &&
1103  p->get_stream_index() == 0) // TODO: no reason to retrieve this every time
1104  {
1105  profile = p;
1106  break;
1107  }
1108  }
1109  if (profile == nullptr)
1110  {
1111  LOG_WARNING("Dropped frame. No valid profile");
1112  return;
1113  }
1114 
1116  if (frame.frame)
1117  {
1118  auto pose_frame = static_cast<librealsense::pose_frame*>(frame.frame);
1119  frame->set_timestamp(ts.global_ts.count());
1121  frame->set_stream(profile);
1122 
1123  auto info = reinterpret_cast<librealsense::pose_frame::pose_info*>(pose_frame->data.data());
1124  info->translation = float3{pose.flX, pose.flY, pose.flZ};
1125  info->velocity = float3{pose.flVx, pose.flVy, pose.flVz};
1126  info->acceleration = float3{pose.flAx, pose.flAy, pose.flAz};
1127  info->rotation = float4{pose.flQi, pose.flQj, pose.flQk, pose.flQr};
1128  info->angular_velocity = float3{pose.flVAX, pose.flVAY, pose.flVAZ};
1129  info->angular_acceleration = float3{pose.flAAX, pose.flAAY, pose.flAAZ};
1130  info->tracker_confidence = pose.dwTrackerConfidence;
1131  info->mapper_confidence = pose.dwMapperConfidence;
1132  }
1133  else
1134  {
1135  LOG_INFO("Dropped frame. alloc_frame(...) returned nullptr");
1136  return;
1137  }
1138  dispatch_threaded(std::move(frame));
1139  }
1140 
1142  {
1143  if (!_is_streaming)
1144  {
1145  LOG_WARNING("Frame received with streaming inactive");
1146  return;
1147  }
1148 
1149  float3 data = { message.metadata.flAx, message.metadata.flAy, message.metadata.flAz };
1150  auto sensor_id = GET_SENSOR_INDEX(message.rawStreamHeader.bSensorID);
1152  }
1153 
1155  {
1156  if (!_is_streaming)
1157  {
1158  LOG_WARNING("Frame received with streaming inactive");
1159  return;
1160  }
1161 
1162  float3 data = { message.metadata.flGx, message.metadata.flGy, message.metadata.flGz };
1163  auto sensor_id = GET_SENSOR_INDEX(message.rawStreamHeader.bSensorID);
1165  }
1166 
1168  {
1169  if (!_is_streaming)
1170  {
1171  LOG_WARNING("Frame received with streaming inactive");
1172  return;
1173  }
1174  if (message->metadata.dwFrameLength == 0)
1175  {
1176  LOG_WARNING("Dropped frame. Frame length is 0");
1177  return;
1178  }
1179 
1181 
1183 
1184  video_frame_metadata video_md{};
1185  video_md.arrival_ts = duration_cast<std::chrono::nanoseconds>(ts.arrival_ts).count();
1186  video_md.exposure_time = message->metadata.dwExposuretime;
1187  frame_additional_data additional_data(ts.device_ts.count(), message->rawStreamHeader.dwFrameId, ts.arrival_ts.count(), sizeof(video_md), (uint8_t*)&video_md, ts.global_ts.count(), 0, 0, false);
1188 
1190  last_gain = message->metadata.fGain;
1191 
1192  // TODO: llArrivalNanoseconds?
1193  // Find the frame stream profile
1194  int width, height, stride;
1195  std::shared_ptr<stream_profile_interface> profile = nullptr;
1196  auto profiles = get_stream_profiles();
1197  for (auto&& p : profiles)
1198  {
1199  if (p->get_stream_type() == RS2_STREAM_FISHEYE &&
1200  p->get_stream_index() == GET_SENSOR_INDEX(message->rawStreamHeader.bSensorID) + 1)
1201  {
1202  auto video = dynamic_cast<video_stream_profile_interface*>(p.get()); //this must succeed for fisheye stream
1203  profile = p;
1204  width = stride = video->get_width();
1205  height = video->get_height();
1206  break;
1207  }
1208  }
1209  if (profile == nullptr)
1210  {
1211  LOG_WARNING("Dropped frame. No valid profile");
1212  return;
1213  }
1214 
1215  //Global base time sync may happen between two frames
1216  //Make sure 2nd frame global timestamp is not impacted.
1217  auto delta_dev_ts = ts.device_ts - last_ts.device_ts;
1218  if (delta_dev_ts < delta_dev_ts.zero())
1219  delta_dev_ts = -delta_dev_ts;
1220 
1221  if (delta_dev_ts < std::chrono::microseconds(1000))
1222  ts.global_ts = last_ts.global_ts + delta_dev_ts; // keep stereo pairs times in sync
1223 
1224  last_ts = ts;
1225 
1226  //TODO - extension_type param assumes not depth
1227  frame_holder frame = _source.alloc_frame(RS2_EXTENSION_VIDEO_FRAME, height * stride, additional_data, true);
1228  if (frame.frame)
1229  {
1230  auto video = (video_frame*)(frame.frame);
1231  video->assign(width, height, stride, bpp);
1232  frame->set_timestamp(ts.global_ts.count());
1234  frame->set_stream(profile);
1235  frame->set_sensor(this->shared_from_this()); //TODO? uvc doesn't set it?
1236  video->data.assign(message->metadata.bFrameData, message->metadata.bFrameData + (height * stride));
1237  }
1238  else
1239  {
1240  LOG_INFO("Dropped frame. alloc_frame(...) returned nullptr");
1241  return;
1242  }
1244  }
1245 
1247  {
1249  auto ts_nanos = duration<uint64_t, std::nano>(device_ns);
1250  result.device_ts = duration<double, std::milli>(ts_nanos);
1251  result.global_ts = duration<double, std::milli>(ts_nanos + duration<int64_t, std::nano>(device_to_host_ns));
1252  result.arrival_ts = duration<double, std::milli>(environment::get_instance().get_time_service()->get_time());
1253  return result;
1254  }
1255 
1257  {
1258  std::vector<uint8_t> buffer(BUFFER_SIZE);
1259 
1260  if (_interrupt_request) return false;
1261 
1262  _interrupt_callback = std::make_shared<platform::usb_request_callback>([&](platform::rs_usb_request request) {
1263  uint32_t transferred = request->get_actual_length();
1264  if(transferred == 0) { // something went wrong, exit
1265  LOG_ERROR("Interrupt transfer failed, exiting");
1266  _interrupt_request.reset();
1267  return;
1268  }
1269 
1270  interrupt_message_header* header = (interrupt_message_header*)request->get_buffer().data();
1271  if(header->wMessageID == DEV_GET_POSE)
1273  else if(header->wMessageID == DEV_SAMPLE) {
1274  if(_is_streaming) {
1275  int sensor_type = GET_SENSOR_TYPE(((interrupt_message_raw_stream_header*)header)->bSensorID);
1276  if(sensor_type == SensorType::Accelerometer)
1278  else if(sensor_type == SensorType::Gyro)
1280  else if(sensor_type == SensorType::Velocimeter)
1281  LOG_ERROR("Did not expect to receive a velocimeter message");
1282  else
1283  LOG_ERROR("Received DEV_SAMPLE with unknown type " << sensor_type);
1284  }
1285  }
1286  else if(header->wMessageID == SLAM_ERROR) {
1287  //TODO: current librs ignores these
1288  auto message = (interrupt_message_slam_error *)header;
1289  if (message->wStatus == SLAM_ERROR_CODE_NONE) LOG_INFO("SLAM_ERROR none");
1290  else if(message->wStatus == SLAM_ERROR_CODE_VISION) LOG_WARNING("SLAM_ERROR Vision");
1291  else if(message->wStatus == SLAM_ERROR_CODE_SPEED) LOG_WARNING("SLAM_ERROR Speed");
1292  else if(message->wStatus == SLAM_ERROR_CODE_OTHER) LOG_WARNING("SLAM_ERROR Other");
1293  else LOG_WARNING("SLAM_ERROR Unknown");
1294  }
1295  else if(header->wMessageID == DEV_ERROR) {
1296  LOG_ERROR("DEV_ERROR " << status_name(*((bulk_message_response_header*)header)));
1297  }
1298  else if(header->wMessageID == DEV_STATUS) {
1299  auto response = (bulk_message_response_header*)header;
1300  if(response->wStatus == DEVICE_STOPPED)
1301  LOG_DEBUG("Got device stopped message");
1302  else if(response->wStatus == TEMPERATURE_WARNING)
1303  LOG_WARNING("T265 temperature warning");
1304  else
1305  LOG_WARNING("Unhandled DEV_STATUS " << status_name(*response));
1306  }
1307  else if(header->wMessageID == SLAM_SET_LOCALIZATION_DATA_STREAM) {
1309  }
1310  else if(header->wMessageID == SLAM_RELOCALIZATION_EVENT) {
1311  auto event = (const interrupt_message_slam_relocalization_event *)header;
1312  auto ts = get_coordinated_timestamp(event->llNanoseconds);
1313  std::string msg = to_string() << "T2xx: Relocalization occurred. id: " << event->wSessionId << ", timestamp: " << ts.global_ts.count() << " ms";
1314  LOG_INFO(msg);
1315  raise_relocalization_event(msg, ts.global_ts.count());
1316  }
1317  else
1318  LOG_ERROR("Unknown interrupt message " << message_name(*((bulk_message_response_header*)header)) << " with status " << status_name(*((bulk_message_response_header*)header)));
1319 
1320  _device->submit_request(request);
1321  });
1322 
1324  _device->submit_request(_interrupt_request);
1325  return true;
1326  }
1327 
1329  {
1330  if (_interrupt_request) {
1331  _interrupt_callback->cancel();
1333  _interrupt_request.reset();
1334  }
1335  }
1336  }
1337 
1339  {
1340  std::vector<uint8_t> buffer(MAX_TRANSFER_SIZE);
1341 
1342  if (_stream_request) return false;
1343 
1344  _stream_callback = std::make_shared<platform::usb_request_callback>([&](platform::rs_usb_request request) {
1345  uint32_t transferred = request->get_actual_length();
1346  if(!transferred) {
1347  LOG_ERROR("Stream transfer failed, exiting");
1348  _stream_request.reset();
1349  return;
1350  }
1351 
1352  auto header = (bulk_message_raw_stream_header *)request->get_buffer().data();
1353  if (transferred != header->header.dwLength) {
1354  LOG_ERROR("Bulk received " << transferred << " but header was " << header->header.dwLength << " bytes (max_response_size was " << MAX_TRANSFER_SIZE << ")");
1355  }
1356  LOG_DEBUG("Got " << transferred << " on bulk stream endpoint");
1357 
1358  if(header->header.wMessageID == DEV_STATUS) {
1360  if(res->wStatus == DEVICE_STOPPED)
1361  LOG_DEBUG("Got device stopped message");
1362  else
1363  LOG_WARNING("Unhandled DEV_STATUS " << status_name(*res));
1364  }
1365  else if(header->header.wMessageID == SLAM_GET_LOCALIZATION_DATA_STREAM) {
1366  LOG_DEBUG("GET_LOCALIZATION_DATA_STREAM status " << status_name(*((bulk_message_response_header*)header)));
1368  }
1369  else if(header->header.wMessageID == DEV_SAMPLE) {
1370  if(GET_SENSOR_TYPE(header->bSensorID) == SensorType::Fisheye) {
1371  if(_is_streaming)
1373  }
1374  else
1375  LOG_ERROR("Unexpected DEV_SAMPLE with " << GET_SENSOR_TYPE(header->bSensorID) << " " << GET_SENSOR_INDEX(header->bSensorID));
1376  }
1377  else {
1378  LOG_ERROR("Unexpected message on raw endpoint " << header->header.wMessageID);
1379  }
1380 
1381  _device->submit_request(request);
1382  });
1383 
1385  _device->submit_request(_stream_request);
1386  return true;
1387  }
1388 
1390  {
1391  if (_stream_request) {
1392  _stream_callback->cancel();
1394  _stream_request.reset();
1395  }
1396  }
1397  }
1398 
1399  void tm2_sensor::print_logs(const std::unique_ptr<bulk_message_response_get_and_clear_event_log> & log)
1400  {
1401  int log_size = log->header.dwLength - sizeof(bulk_message_response_header);
1402  int n_entries = log_size / sizeof(device_event_log);
1403  device_event_log * entries = (device_event_log *)log->bEventLog;
1404 
1405  bool start_of_entry = true;
1406  for (size_t i = 0; i < n_entries; i++) {
1407  const auto & e = entries[i];
1409  memcpy(&timestamp, e.timestamp, sizeof(e.timestamp));
1410  LOG_INFO("T265 FW message: " << timestamp << ": [0x" << e.threadID << "/" << e.moduleID << ":" << e.lineNumber << "] " << e.payload);
1411  start_of_entry = e.eventID == FREE_CONT ? false : true;
1412  }
1413  }
1414 
1415  bool tm2_sensor::log_poll_once(std::unique_ptr<bulk_message_response_get_and_clear_event_log> & log_buffer)
1416  {
1417  bulk_message_request_get_and_clear_event_log log_request = {{ sizeof(log_request), DEV_GET_AND_CLEAR_EVENT_LOG }};
1418  bulk_message_response_get_and_clear_event_log *log_response = log_buffer.get();
1419  platform::usb_status usb_response = _device->bulk_request_response(log_request, *log_response, sizeof(bulk_message_response_get_and_clear_event_log), false);
1420  if(usb_response != platform::RS2_USB_STATUS_SUCCESS) return false;
1421 
1422  if(log_response->header.wStatus == INVALID_REQUEST_LEN || log_response->header.wStatus == INTERNAL_ERROR)
1423  LOG_ERROR("T265 log size mismatch " << status_name(log_response->header));
1424  else if(log_response->header.wStatus != SUCCESS)
1425  LOG_ERROR("Unexpected message on log endpoint " << message_name(log_response->header) << " with status " << status_name(log_response->header));
1426 
1427  return true;
1428  }
1429 
1431  {
1432  auto log_buffer = std::unique_ptr<bulk_message_response_get_and_clear_event_log>(new bulk_message_response_get_and_clear_event_log);
1433  while(!_log_poll_thread_stop) {
1434  if(log_poll_once(log_buffer)) {
1435  print_logs(log_buffer);
1436  std::this_thread::sleep_for(std::chrono::milliseconds(100));
1437  }
1438  else {
1439  LOG_INFO("Got bad response, stopping log_poll");
1440  break;
1441  }
1442  }
1443  }
1444 
1446  {
1447  int tried_count = 0;
1448  while(!_time_sync_thread_stop) {
1449  bulk_message_request_get_time request = {{ sizeof(request), DEV_GET_TIME }};
1450  bulk_message_response_get_time response = {};
1451 
1452  auto start = duration<double, std::milli>(environment::get_instance().get_time_service()->get_time());
1453  platform::usb_status usb_response = _device->bulk_request_response(request, response);
1454  if(usb_response != platform::RS2_USB_STATUS_SUCCESS) {
1455  LOG_INFO("Got bad response, stopping time sync");
1456  break;
1457  }
1458  auto finish = duration<double, std::milli>(environment::get_instance().get_time_service()->get_time());
1459  auto usb_delay = (finish - start) / 2;
1460 
1461  //If usb response takes too long, skip update. 0.25ms is 5% of 200Hz
1462  if (!device_to_host_ns && usb_delay >= duration<double, std::milli>(0.25))
1463  {
1464  //In case of slower USB, not to skip after a few tries.
1465  if (tried_count++ < 3) continue;
1466  }
1467 
1468  if (usb_delay < duration<double, std::milli>(0.25) || !device_to_host_ns)
1469  {
1470  double device_ms = (double)response.llNanoseconds*1e-6;
1471  auto device = duration<double, std::milli>(device_ms);
1472  auto diff = duration<double, std::nano>(start + usb_delay - device);
1473  device_to_host_ns = diff.count();
1474  }
1475  LOG_DEBUG("T265 time synced, host_ns: " << device_to_host_ns);
1476 
1477  // Only trigger this approximately every 500ms, but don't
1478  // wait 500ms to stop if we are requested to stop
1479  for(int i = 0; i < 10; i++)
1481  std::this_thread::sleep_for(std::chrono::milliseconds(50));
1482  }
1483  }
1484 
1485  void tm2_sensor::enable_loopback(std::shared_ptr<playback_device> input)
1486  {
1487  std::lock_guard<std::mutex> lock(_tm_op_lock);
1488  if (_is_streaming || _is_opened)
1489  throw wrong_api_call_sequence_exception("T2xx: Cannot enter loopback mode while device is open or streaming");
1490  _loopback = input;
1491  }
1492 
1494  {
1495  std::lock_guard<std::mutex> lock(_tm_op_lock);
1496  _loopback.reset();
1497  }
1498 
1500  {
1501  return _loopback != nullptr;
1502  }
1503 
1504  void tm2_sensor::handle_imu_frame(unsigned long long tm_frame_ts, unsigned long long frame_number, rs2_stream stream_type, int index, float3 imu_data, float temperature)
1505  {
1506  auto ts = get_coordinated_timestamp(tm_frame_ts);
1507 
1508  motion_frame_metadata motion_md{};
1509  motion_md.arrival_ts = duration_cast<std::chrono::nanoseconds>(ts.arrival_ts).count();
1510  motion_md.temperature = temperature;
1511  frame_additional_data additional_data(ts.device_ts.count(), frame_number, ts.arrival_ts.count(), sizeof(motion_md), (uint8_t*)&motion_md, ts.global_ts.count(), 0, 0, false);
1512 
1513  // Find the frame stream profile
1514  std::shared_ptr<stream_profile_interface> profile = nullptr;
1515  auto profiles = get_stream_profiles();
1516  for (auto&& p : profiles)
1517  {
1518  if (p->get_stream_type() == stream_type &&
1519  p->get_stream_index() == index)
1520  {
1521  profile = p;
1522  break;
1523  }
1524  }
1525  if (profile == nullptr)
1526  {
1527  LOG_WARNING("Dropped frame. No valid profile");
1528  return;
1529  }
1530 
1531  frame_holder frame = _source.alloc_frame(RS2_EXTENSION_MOTION_FRAME, 3 * sizeof(float), additional_data, true);
1532  if (frame.frame)
1533  {
1534  auto motion_frame = static_cast<librealsense::motion_frame*>(frame.frame);
1535  frame->set_timestamp(ts.global_ts.count());
1537  frame->set_stream(profile);
1538  auto data = reinterpret_cast<float*>(motion_frame->data.data());
1539  data[0] = imu_data[0];
1540  data[1] = imu_data[1];
1541  data[2] = imu_data[2];
1542  }
1543  else
1544  {
1545  LOG_INFO("Dropped frame. alloc_frame(...) returned nullptr");
1546  return;
1547  }
1548  dispatch_threaded(std::move(frame));
1549  }
1550 
1551  void tm2_sensor::raise_relocalization_event(const std::string& msg, double timestamp_ms)
1552  {
1554  event.timestamp = timestamp_ms;
1555  get_notifications_processor()->raise_notification(event);
1556  }
1557 
1559  {
1561  error.timestamp = duration<double, std::milli>(environment::get_instance().get_time_service()->get_time()).count();
1562  get_notifications_processor()->raise_notification(error);
1563  }
1564 
1566  {
1567  if(_is_streaming)
1568  LOG_ERROR("Received SET_LOCALIZATION_DATA_COMPLETE while streaming");
1569 
1571  LOG_ERROR("Received SET_LOCALIZATION_DATA_COMPLETE without a transfer in progress");
1572 
1573  if (message.wStatus == MESSAGE_STATUS::SUCCESS) {
1575  _async_op.notify_one();
1576  }
1577  else {
1578  LOG_INFO("SET_LOCALIZATION_DATA_COMPLETE error status " << status_name(*((bulk_message_response_header *)&message)));
1579  _async_op_status = _async_fail; // do not notify here because we may get multiple of these messages
1580  }
1581  }
1582 
1584  {
1585  size_t bytes = chunk->header.dwLength - offsetof(interrupt_message_get_localization_data_stream, bLocalizationData);
1586  LOG_DEBUG("Received chunk " << chunk->wIndex << " with status " << chunk->wStatus << " length " << bytes);
1587 
1588  _async_op_res_buffer.reserve(_async_op_res_buffer.size() + bytes);
1589  auto start = (const char*)chunk->bLocalizationData;
1590  _async_op_res_buffer.insert(_async_op_res_buffer.end(), start, start + bytes);
1591  if (chunk->wStatus == SUCCESS) {
1593  _async_op.notify_one();
1594  }
1595  else if (chunk->wStatus != MORE_DATA_AVAILABLE) {
1597  _async_op.notify_one();
1598  }
1599  }
1600 
1602  {
1603  switch (val)
1604  {
1605  case tm2_sensor::_async_init: return "Init";
1606  case tm2_sensor::_async_progress: return "In Progress";
1607  case tm2_sensor::_async_success: return "Success";
1608  case tm2_sensor::_async_fail: return "Fail";
1609  default: return (to_string() << " Unsupported type: " << val);
1610  }
1611  }
1612 
1613  tm2_sensor::async_op_state tm2_sensor::perform_async_transfer(std::function<bool()> transfer_activator,
1614  std::function<void()> on_success, const std::string& op_description) const
1615  {
1616  std::mutex _async_op_lock;
1617  std::unique_lock<std::mutex> lock(_async_op_lock);
1618 
1620  LOG_INFO(op_description << " in progress");
1621 
1622  bool start_success = transfer_activator();
1623  if(!start_success)
1624  return async_op_state::_async_fail;
1625 
1626  if (!_async_op.wait_for(lock, std::chrono::seconds(2), [this] { return _async_op_status != _async_progress;}))
1627  LOG_WARNING(op_description << " aborted on timeout");
1628  else if (_async_op_status == _async_success)
1629  on_success();
1630  else
1631  LOG_ERROR(op_description << " ended with status " << async_op_to_string(_async_op_status));
1632 
1633  auto res = _async_op_status;
1635  LOG_DEBUG(op_description << " completed with " << async_op_to_string(res));
1636 
1637  return res;
1638  }
1639 
1640  bool tm2_sensor::export_relocalization_map(std::vector<uint8_t>& lmap_buf) const
1641  {
1642  std::lock_guard<std::mutex> lock(_tm_op_lock);
1643  auto sensor = _device->get_tm2_sensor();
1644  bool interrupt_started = sensor->start_interrupt();
1645  std::shared_ptr<void> stop_interrupt(nullptr, [&](...) {
1646  if (interrupt_started)
1647  sensor->stop_interrupt();
1648  });
1649  bool stream_started = sensor->start_stream();
1650  std::shared_ptr<void> stop_stream(nullptr, [&](...) {
1651  if (stream_started)
1652  sensor->stop_stream();
1653  });
1654 
1655  // Export first sends SLAM_GET_LOCALIZATION_DATA on bulk
1656  // endpoint and gets an acknowledgement there. That triggers
1657  // the firmware to send map chunks via
1658  // SLAM_GET_LOCALIZATION_DATA_STREAM messages on the stream
1659  // endpoint, eventually ending in SUCCESS
1660  auto res = perform_async_transfer(
1661  [&]() {
1662  _async_op_res_buffer.clear();
1665  int error = _device->bulk_request_response(request, response);
1666  return !error;
1667  },
1668  [&](){
1669  lmap_buf = this->_async_op_res_buffer;
1670  },
1671  "Export localization map");
1672 
1673  if (res != async_op_state::_async_success)
1674  LOG_ERROR("Export localization map failed");
1675 
1676  return res == async_op_state::_async_success;
1677  }
1678 
1679  bool tm2_sensor::import_relocalization_map(const std::vector<uint8_t>& lmap_buf) const
1680  {
1681  if(_is_streaming)
1682  throw wrong_api_call_sequence_exception("Unable to import relocalization map while streaming");
1683 
1684  std::lock_guard<std::mutex> lock(_tm_op_lock);
1685 
1686  auto sensor = _device->get_tm2_sensor();
1687  bool interrupt_started = sensor->start_interrupt();
1688  std::shared_ptr<void> stop_interrupt(nullptr, [&](...) {
1689  if (interrupt_started)
1690  sensor->stop_interrupt();
1691  });
1692  bool stream_started = sensor->start_stream();
1693  std::shared_ptr<void> stop_stream(nullptr, [&](...) {
1694  if (stream_started)
1695  sensor->stop_stream();
1696  });
1697 
1698  // Import the map by sending chunks of with id SLAM_SET_LOCALIZATION_DATA_STREAM
1699  auto res = perform_async_transfer(
1700  [this, &lmap_buf]() {
1701  const int MAX_BIG_DATA_MESSAGE_LENGTH = 10250; //(10240 (10k) + large message header size)
1702  size_t chunk_length = MAX_BIG_DATA_MESSAGE_LENGTH - offsetof(bulk_message_large_stream, bPayload);
1703  size_t map_size = lmap_buf.size();
1704  std::unique_ptr<uint8_t []> buf(new uint8_t[MAX_BIG_DATA_MESSAGE_LENGTH]);
1705  auto message = (bulk_message_large_stream *)buf.get();
1706 
1707  if (map_size == 0) return false;
1708  size_t left_length = map_size;
1709  int chunk_number = 0;
1710  while (left_length > 0) {
1711  message->header.wMessageID = SLAM_SET_LOCALIZATION_DATA_STREAM;
1712  size_t chunk_size = chunk_length;
1714  if (left_length <= chunk_length) {
1715  chunk_size = left_length;
1716  message->wStatus = MESSAGE_STATUS::SUCCESS;
1717  }
1718  message->header.dwLength = uint32_t(chunk_size + offsetof(bulk_message_large_stream, bPayload));
1719  message->wIndex = chunk_number;
1720 
1721  memcpy(message->bPayload, lmap_buf.data() + (map_size - left_length), chunk_size);
1722 
1723  chunk_number++;
1724  left_length -= chunk_size;
1725 
1726  LOG_DEBUG("Sending chunk length " << chunk_size << " of map size " << map_size);
1727  _device->stream_write(&message->header);
1728  }
1729  return true;
1730  },
1731  [&]() {},
1732  "Import localization map");
1733 
1734  if (res != async_op_state::_async_success)
1735  LOG_ERROR("Import localization map failed");
1736 
1737  return res == async_op_state::_async_success;
1738  }
1739 
1740  bool tm2_sensor::set_static_node(const std::string& guid, const float3& pos, const float4& orient_quat) const
1741  {
1742  bulk_message_request_set_static_node request = {{ sizeof(request), SLAM_SET_STATIC_NODE }};
1743  strncpy((char *)&request.bGuid[0], guid.c_str(), MAX_GUID_LENGTH-1);
1744  request.data.flX = pos.x;
1745  request.data.flY = pos.y;
1746  request.data.flZ = pos.z;
1747  request.data.flQi = orient_quat.x;
1748  request.data.flQj = orient_quat.y;
1749  request.data.flQk = orient_quat.z;
1750  request.data.flQr = orient_quat.w;
1752  _device->bulk_request_response(request, response, sizeof(response), false);
1753  if(response.header.wStatus == INTERNAL_ERROR)
1754  return false; // Failed to set static node
1755  else if(response.header.wStatus != SUCCESS) {
1756  LOG_ERROR("Error: " << status_name(response.header) << " setting static node");
1757  return false;
1758  }
1759 
1760  return true;
1761  }
1762 
1763  bool tm2_sensor::get_static_node(const std::string& guid, float3& pos, float4& orient_quat) const
1764  {
1765  bulk_message_request_get_static_node request = {{ sizeof(request), SLAM_GET_STATIC_NODE }};
1766  strncpy((char *)&request.bGuid[0], guid.c_str(), MAX_GUID_LENGTH-1);
1768 
1769  _device->bulk_request_response(request, response, sizeof(response), false);
1770  if(response.header.wStatus == INTERNAL_ERROR)
1771  return false; // Failed to get static node
1772  else if(response.header.wStatus != SUCCESS) {
1773  LOG_ERROR("Error: " << status_name(response.header) << " getting static node");
1774  return false;
1775  }
1776 
1777  pos = float3{response.data.flX, response.data.flY, response.data.flZ};
1778  orient_quat = float4{response.data.flQi, response.data.flQj, response.data.flQk, response.data.flQr};
1779 
1780  return true;
1781  }
1782 
1784  {
1785  bulk_message_request_remove_static_node request = {{ sizeof(request), SLAM_REMOVE_STATIC_NODE }};
1786  strncpy((char *)&request.bGuid[0], guid.c_str(), MAX_GUID_LENGTH-1);
1788 
1789  _device->bulk_request_response(request, response, sizeof(response), false);
1790  if(response.header.wStatus == INTERNAL_ERROR)
1791  return false; // Failed to get static node
1792  else if(response.header.wStatus != SUCCESS) {
1793  LOG_ERROR("Error: " << status_name(response.header) << " deleting static node");
1794  return false;
1795  }
1796  return true;
1797  }
1798 
1799  bool tm2_sensor::load_wheel_odometery_config(const std::vector<uint8_t>& odometry_config_buf) const
1800  {
1801  std::vector<uint8_t> buf;
1802  buf.resize(odometry_config_buf.size() + sizeof(bulk_message_request_header));
1803 
1804  LOG_INFO("Sending wheel odometry with " << buf.size());
1805 
1807  size_t bytes = std::min(odometry_config_buf.size(), size_t(MAX_SLAM_CALIBRATION_SIZE-1));
1808  strncpy((char *)request.calibration_append_string, (char *)odometry_config_buf.data(), bytes);
1809  request.header.dwLength = uint32_t(offsetof(bulk_message_request_slam_append_calibration, calibration_append_string) + bytes);
1810 
1811  //TODO: There is no way on the firmware to know if this succeeds.
1812 
1813  _device->stream_write(&request.header);
1814 
1815  return true;
1816  }
1817 
1818  bool tm2_sensor::send_wheel_odometry(uint8_t wo_sensor_id, uint32_t frame_num, const float3& translational_velocity) const
1819  {
1820  bulk_message_velocimeter_stream request = {{ sizeof(request), DEV_SAMPLE }};
1822  // These two timestamps get set by the firmware when it is received
1823  request.rawStreamHeader.llNanoseconds = 0;
1826 
1827  request.metadata.dwMetadataLength = 4;
1828  request.metadata.flTemperature = 0;
1829  request.metadata.dwFrameLength = 12;
1830  request.metadata.flVx = translational_velocity.x;
1831  request.metadata.flVy = translational_velocity.y;
1832  request.metadata.flVz = translational_velocity.z;
1833 
1835 
1836  return true;
1837  }
1838 
1840  {
1842  bulk_message_request_get_temperature request = {{ sizeof(request), DEV_GET_TEMPERATURE }};
1844  _device->bulk_request_response(request, *response, BUFFER_SIZE);
1845 
1846  if(uint32_t(sensor_id) > response->dwCount)
1847  throw wrong_api_call_sequence_exception("Requested temperature for an unknown sensor id");
1848 
1849  return response->temperature[sensor_id];
1850  }
1851 
1852  void tm2_sensor::set_exposure_and_gain(float exposure_ms, float gain)
1853  {
1854  bulk_message_request_set_exposure request = {{ sizeof(request), DEV_SET_EXPOSURE }};
1856  request.bNumOfVideoStreams = 2;
1857  for(int i = 0; i < 2; i++) {
1859  request.stream[i].dwIntegrationTime = exposure_ms; // TODO: you cannot set fractional ms, is this actually microseconds?
1860  request.stream[i].fGain = gain;
1861  }
1862  bulk_message_response_set_exposure response = {};
1863 
1864  _device->bulk_request_response(request, response);
1865  }
1866 
1868  {
1869  if (!manual_exposure)
1870  throw std::runtime_error("To control exposure you must set sensor to manual exposure mode prior to streaming");
1871 
1873  last_exposure = value;
1874  }
1875 
1877  {
1878  return last_exposure;
1879  }
1880 
1882  {
1883  if (!manual_exposure)
1884  throw std::runtime_error("To control gain you must set sensor to manual exposure mode prior to streaming");
1885 
1887  last_gain = value;
1888  }
1889 
1890  float tm2_sensor::get_gain() const
1891  {
1892  return last_gain;
1893  }
1894 
1896  {
1897  if(_is_streaming)
1898  throw wrong_api_call_sequence_exception("Exposure mode cannot be controlled while streaming!");
1899 
1901  request.bAntiFlickerMode = 0;
1902  request.bVideoStreamsMask = 0;
1903  if(!manual) {
1904  request.bVideoStreamsMask = 0x3; // bitstream 0011 to enable both fisheye autoexposure
1905  }
1906 
1908  _device->bulk_request_response(request, response);
1909 
1910  manual_exposure = manual;
1911  }
1912 
1914  // Device
1915 
1916  tm2_device::tm2_device( std::shared_ptr<context> ctx, const platform::backend_device_group& group, bool register_device_notifications) :
1917  device(ctx, group, register_device_notifications)
1918  {
1919  if(group.usb_devices.size() != 1 || group.uvc_devices.size() != 0 || group.hid_devices.size() !=0)
1920  throw io_exception("Tried to create a T265 with a bad backend_device_group");
1921 
1922  LOG_DEBUG("Creating a T265 device");
1923 
1925  if(!usb_device)
1926  throw io_exception("Unable to create USB device");
1927 
1928  usb_info = usb_device->get_info();
1929  const std::vector<platform::rs_usb_interface> interfaces = usb_device->get_interfaces();
1930  for(auto & iface : interfaces) {
1931  auto endpoints = iface->get_endpoints();
1932  for(const auto & endpoint : endpoints) {
1933  int addr = endpoint->get_address();
1934 
1935  if (addr == ENDPOINT_HOST_IN) endpoint_bulk_in = endpoint;
1936  else if (addr == ENDPOINT_HOST_OUT) endpoint_bulk_out = endpoint;
1937  else if (addr == ENDPOINT_HOST_MSGS_IN) endpoint_msg_in = endpoint;
1938  else if (addr == ENDPOINT_HOST_MSGS_OUT) endpoint_msg_out = endpoint;
1939  else if (addr == ENDPOINT_HOST_INT_IN) endpoint_int_in = endpoint;
1940  else if (addr == ENDPOINT_HOST_INT_OUT) endpoint_int_out = endpoint;
1941  else LOG_ERROR("Unknown endpoint address " << addr);
1942  }
1943  }
1945  throw io_exception("Missing a T265 usb endpoint");
1946 
1947 
1948  usb_messenger = usb_device->open(0); // T265 only has one interface, 0
1949  if(!usb_messenger)
1950  throw io_exception("Unable to open device interface");
1951 
1952  LOG_DEBUG("Successfully opened and claimed interface 0");
1953 
1954  bulk_message_request_set_low_power_mode power_request = {{ sizeof(power_request), DEV_SET_LOW_POWER_MODE }};
1955  bulk_message_response_set_low_power_mode power_response = {};
1956  power_request.bEnabled = 0; // disable low power mode
1957  auto response = bulk_request_response(power_request, power_response);
1958  if(response != platform::RS2_USB_STATUS_SUCCESS)
1959  throw io_exception("Unable to communicate with device");
1960 
1961  bulk_message_request_get_device_info info_request = {{ sizeof(info_request), DEV_GET_DEVICE_INFO }};
1962  bulk_message_response_get_device_info info_response = {};
1963  bulk_request_response(info_request, info_response);
1964 
1965  if(info_response.message.bStatus == 0x1 || info_response.message.dwStatusCode == FW_STATUS_CODE_NO_CALIBRATION_DATA)
1966  throw io_exception("T265 device is uncalibrated");
1967 
1968  std::string serial = to_string() << std::uppercase << std::hex << (bytesSwap(info_response.message.llSerialNumber) >> 16);
1969  LOG_INFO("Serial: " << serial);
1970 
1971  LOG_INFO("Connection type: " << platform::usb_spec_names.at(usb_info.conn_spec));
1972 
1975  std::string firmware = to_string() << std::to_string(info_response.message.bFWVersionMajor) << "." << std::to_string(info_response.message.bFWVersionMinor) << "." << std::to_string(info_response.message.bFWVersionPatch) << "." << std::to_string(info_response.message.dwFWVersionBuild);
1977  LOG_INFO("Firmware version: " << firmware);
1980 
1982  register_info(RS2_CAMERA_INFO_PHYSICAL_PORT, usb_info.id); // TODO uvc has device_path, usb_info has id and unique_id
1983 
1984  _sensor = std::make_shared<tm2_sensor>(this);
1986 
1987  _sensor->register_option(rs2_option::RS2_OPTION_ASIC_TEMPERATURE, std::make_shared<asic_temperature_option>(*_sensor));
1988  _sensor->register_option(rs2_option::RS2_OPTION_MOTION_MODULE_TEMPERATURE, std::make_shared<motion_temperature_option>(*_sensor));
1989 
1990  _sensor->register_option(rs2_option::RS2_OPTION_EXPOSURE, std::make_shared<exposure_option>(*_sensor));
1991  _sensor->register_option(rs2_option::RS2_OPTION_GAIN, std::make_shared<gain_option>(*_sensor));
1992  _sensor->register_option(rs2_option::RS2_OPTION_ENABLE_AUTO_EXPOSURE, std::make_shared<exposure_mode_option>(*_sensor));
1993 
1994  _sensor->register_option(rs2_option::RS2_OPTION_ENABLE_MAPPING, std::make_shared<tracking_mode_option<SIXDOF_MODE_ENABLE_MAPPING, SIXDOF_MODE_NORMAL, false>>(*_sensor, "Use an on device map (recommended)"));
1995  _sensor->register_option(rs2_option::RS2_OPTION_ENABLE_RELOCALIZATION, std::make_shared<tracking_mode_option<SIXDOF_MODE_ENABLE_RELOCALIZATION, SIXDOF_MODE_ENABLE_MAPPING, false>>(*_sensor, "Use appearance based relocalization (depends on mapping)"));
1996  _sensor->register_option(rs2_option::RS2_OPTION_ENABLE_POSE_JUMPING, std::make_shared<tracking_mode_option<SIXDOF_MODE_DISABLE_JUMPING, SIXDOF_MODE_ENABLE_MAPPING, true>>(*_sensor, "Allow pose jumping (depends on mapping)"));
1998  _sensor->register_option(rs2_option::RS2_OPTION_ENABLE_MAP_PRESERVATION, std::make_shared<tracking_mode_option<SIXDOF_MODE_ENABLE_MAP_PRESERVATION, SIXDOF_MODE_ENABLE_MAPPING, false>>(*_sensor, "Preserve the map from the previous run as if it was loaded"));
1999 
2000  // Adding the extrinsic nodes to the default group
2001  auto tm2_profiles = _sensor->get_stream_profiles();
2002  for (auto && pf : tm2_profiles)
2004 
2005  //For manual testing: enable_loopback("C:\\dev\\recording\\tm2.bag");
2006  }
2007 
2009  {
2010  // Since the device claims the interface and opens it, it
2011  // should also dispose of it
2012  LOG_DEBUG("Stopping sensor");
2013  // Note this is the last chance the tm2_sensor gets to use USB
2014  _sensor->dispose();
2015  LOG_DEBUG("Destroying T265 device");
2016  }
2017 
2019  {
2020  LOG_INFO("Sending hardware reset");
2021  uint32_t transferred;
2022  usb_messenger->control_transfer(0x40, 0x10, 0, 0, nullptr, 0, transferred, USB_TIMEOUT);
2023  }
2024 
2025  template<typename Request, typename Response>
2026  platform::usb_status tm2_device::bulk_request_response(const Request &request, Response &response, size_t max_response_size, bool assert_success)
2027  {
2028  std::lock_guard<std::mutex> lock(bulk_mutex);
2029 
2030  // request
2031  uint32_t length = request.header.dwLength;
2032  uint16_t message_id = request.header.wMessageID;
2033  LOG_DEBUG("Sending message " << message_name(request.header) << " length " << length);
2034  uint32_t transferred = 0;
2036  e = usb_messenger->bulk_transfer(endpoint_msg_out, (uint8_t*)&request, length, transferred, USB_TIMEOUT);
2038  LOG_ERROR("Bulk request error " << platform::usb_status_to_string.at(e));
2039  return e;
2040  }
2041  if (transferred != length) {
2042  LOG_ERROR("error: sent " << transferred << " not " << length);
2044  }
2045 
2046  // response
2047  if(max_response_size == 0)
2048  max_response_size = sizeof(response);
2049  LOG_DEBUG("Receiving message with max_response_size " << max_response_size);
2050 
2051  transferred = 0;
2052  e = usb_messenger->bulk_transfer(endpoint_msg_in, (uint8_t*)&response, int(max_response_size), transferred, USB_TIMEOUT);
2054  LOG_ERROR("Bulk response error " << platform::usb_status_to_string.at(e));
2055  return e;
2056  }
2057  if (transferred != response.header.dwLength) {
2058  LOG_ERROR("Received " << transferred << " but header was " << response.header.dwLength << " bytes (max_response_size was " << max_response_size << ")");
2060  }
2061  if (assert_success && MESSAGE_STATUS(response.header.wStatus) != MESSAGE_STATUS::SUCCESS) {
2062  LOG_ERROR("Received " << message_name(response.header) << " with length " << response.header.dwLength << " but got non-zero status of " << status_name(response.header));
2063  }
2064  LOG_DEBUG("Received " << message_name(response.header) << " with length " << response.header.dwLength);
2065  return e;
2066  }
2067 
2068  // all messages must have dwLength and wMessageID as first two members
2070  {
2071  std::lock_guard<std::mutex> lock(stream_mutex);
2072 
2073  uint32_t length = request->dwLength;
2074  uint16_t message_id = request->wMessageID;
2075  LOG_DEBUG("Sending stream message " << message_name(*request) << " length " << length);
2076  uint32_t transferred = 0;
2078  e = usb_messenger->bulk_transfer(endpoint_bulk_out, (uint8_t *)request, length, transferred, USB_TIMEOUT);
2080  LOG_ERROR("Stream write error " << platform::usb_status_to_string.at(e));
2081  return e;
2082  }
2083  if (transferred != length) {
2084  LOG_ERROR("error: sent " << transferred << " not " << length);
2086  }
2087  return e;
2088  }
2089 
2090  platform::rs_usb_request tm2_device::stream_read_request(std::vector<uint8_t> & buffer, std::shared_ptr<platform::usb_request_callback> callback)
2091  {
2092  auto request = usb_messenger->create_request(endpoint_bulk_in);
2093  request->set_buffer(buffer);
2094  request->set_callback(callback);
2095  return request;
2096  }
2097 
2099  {
2100  auto e = usb_messenger->submit_request(request);
2102  throw std::runtime_error("failed to submit request, error: " + platform::usb_status_to_string.at(e));
2103  }
2104 
2106  {
2107  auto e = usb_messenger->cancel_request(request);
2109  return false;
2110  return true;
2111  }
2112 
2113  platform::rs_usb_request tm2_device::interrupt_read_request(std::vector<uint8_t> & buffer, std::shared_ptr<platform::usb_request_callback> callback)
2114  {
2115  auto request = usb_messenger->create_request(endpoint_int_in);
2116  request->set_buffer(buffer);
2117  request->set_callback(callback);
2118  return request;
2119  }
2120 
2124  void tm2_device::enable_loopback(const std::string& source_file)
2125  {
2126  auto ctx = get_context();
2127  std::shared_ptr<playback_device> raw_streams;
2128  try
2129  {
2130  raw_streams = std::make_shared<playback_device>(ctx, std::make_shared<ros_reader>(source_file, ctx));
2131  }
2132  catch (const std::exception& e)
2133  {
2134  LOG_ERROR("Failed to create playback device from given file. File = \"" << source_file << "\". Exception: " << e.what());
2135  throw librealsense::invalid_value_exception("Failed to enable loopback");
2136  }
2137  _sensor->enable_loopback(raw_streams);
2138  update_info(RS2_CAMERA_INFO_NAME, to_string() << tm2_device_name() << " (Loopback - " << source_file << ")");
2139  }
2140 
2142  {
2143  _sensor->disable_loopback();
2145  }
2146 
2148  {
2149  return _sensor->is_loopback_enabled();
2150  }
2151 
2153  {
2154  //T265 uses POSE sensor as reference sensor for extrinsics
2155  auto tm2_profiles = _sensor->get_stream_profiles();
2156  int ref_index = 0;
2157  for (int i = 0; i < tm2_profiles.size(); i++)
2158  if (tm2_profiles[i]->get_stream_type() == RS2_STREAM_POSE)
2159  {
2160  ref_index = i;
2161  break;
2162  }
2163 
2164  _extrinsics[stream.get_unique_id()] = std::make_pair(group_index, tm2_profiles[ref_index]);
2165  }
2166 
2167 }
MESSAGE_STATUS
Defines all bulk message return statuses.
int tm2_sensor_type(rs2_stream rtype)
Definition: tm-device.cpp:111
std::vector< t265::supported_raw_stream_libtm_message > _supported_raw_streams
Definition: tm-device.h:163
static const textual_icon lock
Definition: model-views.h:218
static uint64_t bytesSwap(uint64_t val)
Definition: tm-device.cpp:30
void receive_set_localization_data_complete(const t265::interrupt_message_set_localization_data_stream &message)
Definition: tm-device.cpp:1565
GLenum GLuint GLenum GLsizei const GLchar * message
Bulk Get Localization Data Message.
virtual rs2_stream get_stream_type() const =0
float3 mult(const float3x3 &a, const float3 &b)
Definition: test-pose.cpp:78
Bulk Get Pose Message.
frame_source _source
Definition: sensor.h:110
interrupt_message_gyro_stream_metadata metadata
platform::usb_status stream_write(const t265::bulk_message_request_header *request)
Definition: tm-device.cpp:2069
GLboolean GLboolean GLboolean b
Interrupt get pose message.
async_op_state perform_async_transfer(std::function< bool()> transfer_activator, std::function< void()> on_success, const std::string &op_description) const
Definition: tm-device.cpp:1613
interrupt_message_accelerometer_stream_metadata metadata
static rs_usb_device create_usb_device(const usb_device_info &info)
Interrupt raw accelerometer stream message.
platform::rs_usb_request _stream_request
Definition: tm-device.h:185
std::atomic< bool > _is_opened
Definition: sensor.h:104
Base class that establishes the interface for retrieving metadata attributes.
pose inv(pose const &p)
Definition: test-pose.cpp:178
void invoke_callback(frame_holder frame) const
Definition: source.cpp:113
Bulk SLAM override calibration Message.
std::shared_ptr< usb_request > rs_usb_request
Definition: usb-request.h:41
Bulk Log Control Message.
bool is_enabled() const override
Definition: tm-device.cpp:221
bool is_loopback_enabled() const
Definition: tm-device.cpp:1499
GLenum const void * addr
Definition: glext.h:8864
rs2_format rs2_format_from_tm2(const uint8_t format)
Definition: tm-device.cpp:106
exposure_option(tm2_sensor &ep)
Definition: tm-device.cpp:181
Bulk message request header struct.
GLdouble s
std::shared_ptr< platform::time_service > get_time_service()
void start(frame_callback_ptr callback) override
Definition: tm-device.cpp:807
virtual std::shared_ptr< notifications_processor > get_notifications_processor() const
Definition: sensor.cpp:116
void init(std::shared_ptr< metadata_parser_map > metadata_parsers)
Definition: source.cpp:50
void raise_error_notification(const std::string &msg)
Definition: tm-device.cpp:1558
log_level
Definition: tm-device.cpp:71
std::shared_ptr< rs2_frame_callback > frame_callback_ptr
Definition: src/types.h:1071
Interrupt Get Localization Data Stream message.
GLfloat GLfloat p
Definition: glext.h:12687
platform::rs_usb_request stream_read_request(std::vector< uint8_t > &buffer, std::shared_ptr< platform::usb_request_callback > callback)
Definition: tm-device.cpp:2090
void receive_pose_message(const t265::interrupt_message_get_pose &message)
Definition: tm-device.cpp:1084
coordinated_ts last_ts
Definition: tm-device.h:199
bulk_message_raw_stream_header rawStreamHeader
float translation[3]
Definition: rs_sensor.h:99
GLboolean invert
const char * get_description() const override
Definition: tm-device.cpp:242
#define LOG_WARNING(...)
Definition: src/types.h:241
tm2_device * _device
Definition: tm-device.h:166
std::atomic< bool > _log_poll_thread_stop
Definition: tm-device.h:180
stream_profiles get_stream_profiles(int tag=profile_tag::PROFILE_TAG_ANY) const override
Definition: sensor.cpp:196
#define GET_SENSOR_INDEX(_sensorID)
Definition: tm-device.cpp:49
std::mutex stream_mutex
Definition: tm-device.h:70
void set_manual_exposure(bool manual)
Definition: tm-device.cpp:1895
GLfloat value
stream_exposure stream[MAX_VIDEO_STREAMS]
bool import_relocalization_map(const std::vector< uint8_t > &lmap_buf) const override
Definition: tm-device.cpp:1679
void stop() override
Definition: tm-device.cpp:846
Bulk raw video stream message.
Bulk Set Exposure Control Message Enable/disable the auto-exposure management of the different video ...
bulk_message_video_stream_metadata metadata
GeneratorWrapper< std::vector< T > > chunk(size_t size, GeneratorWrapper< T > &&generator)
Definition: catch.hpp:4321
void register_stream_to_extrinsic_group(const stream_interface &stream, uint32_t group_index)
Definition: tm-device.cpp:2152
bulk_message_velocimeter_stream_metadata metadata
bulk_message_response_header header
GLenum GLenum dst
Definition: glext.h:1751
bool is_read_only() const override
Definition: tm-device.cpp:246
void register_same_extrinsics(const stream_interface &from, const stream_interface &to)
Definition: environment.cpp:23
Bulk write configuration Message.
#define GET_SENSOR_TYPE(_sensorID)
Definition: tm-device.cpp:50
unsigned short uint16_t
Definition: stdint.h:79
static const std::map< usb_spec, std::string > usb_spec_names
Definition: usb-types.h:124
float coeffs[5]
Definition: rs_types.h:67
virtual void register_metadata(rs2_frame_metadata_value metadata, std::shared_ptr< md_attribute_parser_base > metadata_parser) const
Definition: sensor.cpp:121
void enable_loopback(std::shared_ptr< playback_device > input)
Definition: tm-device.cpp:1485
void set_timestamp_domain(rs2_timestamp_domain timestamp_domain) override
Definition: archive.h:137
GLsizei const GLchar *const * string
float query() const override
Definition: tm-device.cpp:173
std_msgs::Header * header(M &m)
returns Header<M>::pointer(m);
bulk_message_request_header header
const char * get_description() const override
Definition: tm-device.cpp:259
Interrupt raw gyro stream message.
temperature_option(tm2_sensor &ep, temperature_type type)
Definition: tm-device.cpp:161
GLuint GLuint stream
Definition: glext.h:1790
GLenum src
Definition: glext.h:1751
static const int BUFFER_SIZE
Definition: tm-device.cpp:86
#define ENDPOINT_HOST_INT_IN
Definition: tm-device.cpp:68
unsigned char uint8_t
Definition: stdint.h:78
const char * get_description() const override
Definition: tm-device.cpp:270
platform::usb_status bulk_request_response(const Request &request, Response &response, size_t max_response_size=0, bool assert_success=true)
Definition: tm-device.cpp:2026
Bulk Get Static Node Message.
e
Definition: rmse.py:177
interrupt_message_raw_stream_header rawStreamHeader
rs2_extrinsics get_extrinsics(const stream_profile_interface &profile, int sensor_id) const
Definition: tm-device.cpp:924
GLenum GLfloat * buffer
std::thread _time_sync_thread
Definition: tm-device.h:177
Bulk Set Localization Data Stream Message.
std::shared_ptr< dispatcher > _data_dispatcher
Definition: tm-device.h:206
bool load_wheel_odometery_config(const std::vector< uint8_t > &odometry_config_buf) const override
Definition: tm-device.cpp:1799
platform::rs_usb_endpoint endpoint_int_in
Definition: tm-device.h:63
void set_exposure_and_gain(float exposure_ms, float gain)
Definition: tm-device.cpp:1852
float rotation[9]
Definition: rs_sensor.h:98
enum librealsense::platform::_usb_status usb_status
std::condition_variable _async_op
Definition: tm-device.h:159
rs2_intrinsics get_intrinsics(const stream_profile &profile) const override
Definition: tm-device.cpp:876
static std::map< usb_status, std::string > usb_status_to_string
Definition: usb-types.h:162
t265::sensor_temperature get_temperature(int sensor_id)
Definition: tm-device.cpp:1839
GLuint index
virtual void release()=0
GLdouble t
GLboolean GLboolean GLboolean GLboolean a
GLenum GLuint GLenum GLsizei const GLchar * buf
void set_max_publish_list_size(int qsize)
Definition: source.h:50
GLuint GLfloat * val
def info(name, value, persistent=False)
Definition: test.py:301
void set_active_streams(const stream_profiles &requests)
Definition: sensor.cpp:178
static std::string message_name(const T &header)
Definition: message-print.h:74
bool is_enabled() const override
Definition: tm-device.cpp:159
GLdouble f
platform::rs_usb_endpoint endpoint_int_out
Definition: tm-device.h:63
void register_extrinsics(const stream_interface &from, const stream_interface &to, std::weak_ptr< lazy< rs2_extrinsics >> extr)
Definition: environment.cpp:28
std::string hexify(const T &val)
Definition: src/types.h:185
rs2_motion_device_intrinsic get_motion_intrinsics(const motion_stream_profile_interface &profile) const
Definition: tm-device.cpp:905
void register_info(rs2_camera_info info, const std::string &val)
Definition: sensor.cpp:602
std::vector< hid_device_info > hid_devices
Definition: backend.h:527
const char * get_description() const override
Definition: tm-device.cpp:177
float query() const override
Definition: tm-device.cpp:209
#define ENDPOINT_HOST_IN
Definition: tm-device.cpp:64
void set_timestamp(double new_ts) override
Definition: archive.h:135
void print_logs(const std::unique_ptr< t265::bulk_message_response_get_and_clear_event_log > &log)
Definition: tm-device.cpp:1399
Bulk Get Temperature Message.
stream_profiles init_stream_profiles() override
Definition: tm-device.cpp:433
std::chrono::duration< double, std::milli > global_ts
Definition: tm-device.h:196
tracking_mode_option(tm2_sensor &sensor, const char *description_)
Definition: tm-device.cpp:248
std::atomic< bool > _time_sync_thread_stop
Definition: tm-device.h:179
platform::rs_usb_request_callback _interrupt_callback
Definition: tm-device.h:183
void set_extrinsics(const stream_profile_interface &from_profile, const stream_profile_interface &to_profile, const rs2_extrinsics &extr) override
Definition: tm-device.cpp:973
Bulk Set Exposure Message.
Stream Endpoint Protocol.
void disable_loopback() override
Definition: tm-device.cpp:2141
GLdouble GLdouble r
bulk_message_raw_stream_header rawStreamHeader
static const char * tm2_device_name()
Definition: tm-device.h:51
unsigned int uint32_t
Definition: stdint.h:80
Bulk reset configuration Message.
void raise_on_before_streaming_changes(bool streaming)
Definition: sensor.cpp:174
GLboolean GLuint group
Definition: glext.h:5688
uint32_t dwMapperConfidence
void set_stream(std::shared_ptr< stream_profile_interface > sp) override
Definition: archive.h:145
void close() override
Definition: tm-device.cpp:689
std::chrono::duration< double, std::milli > arrival_ts
Definition: tm-device.h:197
void set_sensor(const std::shared_ptr< sensor_interface > &s)
Definition: source.cpp:94
GLint GLsizei GLsizei height
bulk_message_request_header header
platform::rs_usb_endpoint endpoint_bulk_out
Definition: tm-device.h:62
Bulk Set Motion Module Intrinsics Message.
std::atomic< int64_t > device_to_host_ns
Definition: tm-device.h:192
void receive_gyro_message(const t265::interrupt_message_gyro_stream &message)
Definition: tm-device.cpp:1154
bool is_enabled() const override
Definition: tm-device.cpp:244
#define FREE_CONT
Definition: tm-device.cpp:82
GLint GLint GLsizei GLint GLenum format
gain_option(tm2_sensor &ep)
Definition: tm-device.cpp:223
std::map< int, std::pair< uint32_t, std::shared_ptr< const stream_interface > > > _extrinsics
Definition: device.h:93
std::shared_ptr< playback_device > _loopback
Definition: tm-device.h:158
virtual void set_timestamp(double new_ts)=0
bool supports(const frame &frm) const override
Definition: tm-device.cpp:335
void pass_frames_to_fw(frame_holder fref)
Definition: tm-device.cpp:711
int tm2_sensor_id(rs2_stream type, int stream_index)
Definition: tm-device.cpp:125
Bulk enable low power Message.
def finish()
Definition: test.py:373
def callback(frame)
Definition: t265_stereo.py:91
unsigned __int64 uint64_t
Definition: stdint.h:90
async_op_state _async_op_status
Definition: tm-device.h:160
bool remove_static_node(const std::string &guid) const override
Definition: tm-device.cpp:1783
float get_gain() const
Definition: tm-device.cpp:1890
std::chrono::duration< double, std::milli > device_ts
Definition: tm-device.h:195
float get_exposure() const
Definition: tm-device.cpp:1876
GLuint start
bool export_relocalization_map(std::vector< uint8_t > &lmap_buf) const override
Definition: tm-device.cpp:1640
GLdouble GLdouble GLint stride
void receive_accel_message(const t265::interrupt_message_accelerometer_stream &message)
Definition: tm-device.cpp:1141
std::shared_ptr< tm2_sensor > _sensor
Definition: tm-device.h:55
platform::rs_usb_endpoint endpoint_msg_in
Definition: tm-device.h:61
#define MAX_GUID_LENGTH
Definition: t265-messages.h:34
rs2_format
A stream&#39;s format identifies how binary data is encoded within a frame.
Definition: rs_sensor.h:59
#define ENDPOINT_HOST_MSGS_OUT
Definition: tm-device.cpp:67
Bulk message response header struct.
Supported Raw Stream libtm Message.
bool log_poll_once(std::unique_ptr< t265::bulk_message_response_get_and_clear_event_log > &log_buffer)
Definition: tm-device.cpp:1415
float query() const override
Definition: tm-device.cpp:234
#define ENDPOINT_HOST_MSGS_IN
Definition: tm-device.cpp:66
std::shared_ptr< tm2_sensor > get_tm2_sensor()
Definition: tm-device.h:45
#define LOG_ERROR(...)
Definition: src/types.h:242
Bulk Raw Streams Control Message.
const char * get_description() const override
Definition: tm-device.cpp:219
bool is_enabled() const override
Definition: tm-device.cpp:2147
void update_info(rs2_camera_info info, const std::string &val)
Definition: sensor.cpp:614
std::vector< std::shared_ptr< stream_profile_interface >> stream_profiles
Definition: streaming.h:165
void enable_loopback(const std::string &source_file) override
Definition: tm-device.cpp:2124
dictionary intrinsics
Definition: t265_stereo.py:142
rs2_stream
Streams are different types of data provided by RealSense devices.
Definition: rs_sensor.h:42
uint64_t llNanoseconds
Bulk Set Camera Intrinsics Message.
frame_interface * alloc_frame(rs2_extension type, size_t size, frame_additional_data additional_data, bool requires_memory) const
Definition: source.cpp:87
static environment & get_instance()
int add_sensor(const std::shared_ptr< sensor_interface > &sensor_base)
Definition: device.cpp:163
static const int MAX_TRANSFER_SIZE
Definition: tm-device.cpp:84
extrinsics_graph & get_extrinsics_graph()
const char * get_description() const override
Definition: tm-device.cpp:195
std::chrono::duration< uint64_t, std::nano > nanoseconds
void set_sensor(std::shared_ptr< sensor_interface > s) override
Definition: archive.cpp:24
static const int USB_TIMEOUT
Definition: tm-device.cpp:85
option_range get_range() const override
Definition: tm-device.cpp:157
::geometry_msgs::Pose_< std::allocator< void > > Pose
Definition: Pose.h:54
bulk_message_response_header header
struct _cl_event * event
Definition: glext.h:2991
Interrupt Endpoint Protocol.
Cross-stream extrinsics: encodes the topology describing how the different devices are oriented...
Definition: rs_sensor.h:96
platform::rs_usb_messenger usb_messenger
Definition: tm-device.h:59
bulk_message_response_header header
LOG_INFO("Log message using LOG_INFO()")
void receive_video_message(const t265::bulk_message_video_stream *message)
Definition: tm-device.cpp:1167
Interrupt SLAM error message.
void set_exposure(float value)
Definition: tm-device.cpp:1867
GLuint GLfloat GLfloat GLfloat x1
Definition: glext.h:9721
rs2_distortion model
Definition: rs_types.h:66
std::shared_ptr< context > get_context() const override
Definition: device.h:58
void set_motion_device_intrinsics(const stream_profile_interface &stream_profile, const rs2_motion_device_intrinsic &intr) override
Definition: tm-device.cpp:1034
frame_interface * frame
Definition: streaming.h:126
Bulk Get Device Info Message.
bool set_static_node(const std::string &guid, const float3 &pos, const float4 &orient_quat) const override
Definition: tm-device.cpp:1740
static std::string status_name(const T &header)
float query() const override
Definition: tm-device.cpp:191
Bulk Get Supported Raw Streams Message.
GLenum GLenum GLenum input
Definition: glext.h:10805
void open(const stream_profiles &requests) override
Definition: tm-device.cpp:568
void dispatch_threaded(frame_holder frame)
Definition: tm-device.cpp:1074
stream_profile to_profile(const stream_profile_interface *sp)
Definition: src/stream.h:185
long long rs2_metadata_type
Definition: rs_types.h:301
GLenum type
std::vector< usb_device_info > usb_devices
Definition: backend.h:526
void log(std::string message)
t265::SIXDOF_MODE _tm_mode
Definition: tm-device.h:149
int min(int a, int b)
Definition: lz4s.c:73
std::shared_ptr< metadata_parser_map > _metadata_parsers
Definition: sensor.h:107
rs2_extrinsics extr
Definition: test-pose.cpp:258
void set_gain(float value)
Definition: tm-device.cpp:1881
std::string async_op_to_string(tm2_sensor::async_op_state val)
Definition: tm-device.cpp:1601
void write_calibration() override
Definition: tm-device.cpp:1055
signed __int64 int64_t
Definition: stdint.h:89
bool is_enabled() const override
Definition: tm-device.cpp:197
GLint GLsizei count
virtual int get_stream_index() const =0
size_t copy_array(T(&dst)[size_tgt], const S(&src)[size_src])
Definition: src/types.h:133
typename::boost::move_detail::remove_reference< T >::type && move(T &&t) BOOST_NOEXCEPT
Video stream intrinsics.
Definition: rs_types.h:58
void set_callback(frame_callback_ptr callback)
Definition: source.cpp:102
interrupt_message_raw_stream_header rawStreamHeader
#define ENDPOINT_HOST_OUT
Definition: tm-device.cpp:65
float rs2_vector::* pos
md_tm2_parser(rs2_frame_metadata_value type)
Definition: tm-device.cpp:280
platform::usb_device_info usb_info
Definition: tm-device.h:57
platform::rs_usb_request_callback _stream_callback
Definition: tm-device.h:186
platform::rs_usb_request interrupt_read_request(std::vector< uint8_t > &buffer, std::shared_ptr< platform::usb_request_callback > callback)
Definition: tm-device.cpp:2113
Interrupt Set Localization Data Stream message.
Motion device intrinsics: scale, bias, and variances.
Definition: rs_types.h:103
void handle_imu_frame(unsigned long long tm_frame_ts, unsigned long long frame_number, rs2_stream stream_type, int index, float3 imu_data, float temperature)
Definition: tm-device.cpp:1504
uint32_t dwTrackerConfidence
coordinated_ts get_coordinated_timestamp(uint64_t device_nanoseconds)
Definition: tm-device.cpp:1246
void receive_localization_data_chunk(const t265::interrupt_message_get_localization_data_stream *chunk)
Definition: tm-device.cpp:1583
int i
#define offsetof(STRUCTURE, FIELD)
Definition: sqlite3.c:11372
GLenum GLuint GLenum GLsizei length
GLuint res
Definition: glext.h:8856
virtual void set_timestamp_domain(rs2_timestamp_domain timestamp_domain)=0
rs2_frame_metadata_value _type
Definition: tm-device.cpp:356
void set_extrinsics_to_ref(rs2_stream stream_type, int stream_index, const rs2_extrinsics &extr)
Definition: tm-device.cpp:1020
platform::rs_usb_endpoint endpoint_bulk_in
Definition: tm-device.h:62
#define MAX_SLAM_CALIBRATION_SIZE
Definition: t265-messages.h:36
platform::rs_usb_endpoint endpoint_msg_out
Definition: tm-device.h:61
std::vector< uint8_t > _async_op_res_buffer
Definition: tm-device.h:161
static const uint16_t ID_OEM_CAL
Definition: tm-device.h:141
#define LOG_DEBUG(...)
Definition: src/types.h:239
void hardware_reset() override
Definition: tm-device.cpp:2018
#define ENDPOINT_HOST_INT_OUT
Definition: tm-device.cpp:69
std::vector< uvc_device_info > uvc_devices
Definition: backend.h:525
const std::map< PixelFormat, rs2_format > tm2_formats_map
Definition: tm-device.cpp:88
Interrupt SLAM Relocalization Event message.
std::atomic< bool > _is_streaming
Definition: sensor.h:103
tm2_device(std::shared_ptr< context > ctx, const platform::backend_device_group &group, bool register_device_notifications)
Definition: tm-device.cpp:1916
std::vector< t265::supported_raw_stream_libtm_message > _active_raw_streams
Definition: tm-device.h:164
void set_intrinsics(const stream_profile_interface &stream_profile, const rs2_intrinsics &intr) override
Definition: tm-device.cpp:947
virtual int get_unique_id() const =0
GLuint64EXT * result
Definition: glext.h:10921
int get_image_bpp(rs2_format format)
Definition: image.cpp:21
Bulk Get and Clear Event Log Message.
bool send_wheel_odometry(uint8_t wo_sensor_id, uint32_t frame_num, const float3 &translational_velocity) const override
Definition: tm-device.cpp:1818
bool is_enabled() const override
Definition: tm-device.cpp:179
float query() const override
Definition: tm-device.cpp:155
auto device
Definition: pyrs_net.cpp:17
bool cancel_request(platform::rs_usb_request request)
Definition: tm-device.cpp:2105
Bulk raw velocimeter stream message.
Definition: parser.hpp:150
rs2_frame_metadata_value
Per-Frame-Metadata is the set of read-only properties that might be exposed for each individual frame...
Definition: rs_frame.h:29
bool get_static_node(const std::string &guid, float3 &pos, float4 &orient_quat) const override
Definition: tm-device.cpp:1763
GLint GLsizei width
#define SET_SENSOR_ID(_type, _index)
Definition: tm-device.cpp:48
void reset_to_factory_calibration() override
Definition: tm-device.cpp:1066
void submit_request(platform::rs_usb_request request)
Definition: tm-device.cpp:2098
Interrupt raw stream header.
std::vector< byte > data
Definition: archive.h:100
void raise_relocalization_event(const std::string &msg, double timestamp)
Definition: tm-device.cpp:1551
platform::rs_usb_request _interrupt_request
Definition: tm-device.h:182
std::thread _log_poll_thread
Definition: tm-device.h:178
virtual void set_stream(std::shared_ptr< stream_profile_interface > sp)=0
std::string to_string(T value)


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