mf-hid.cpp
Go to the documentation of this file.
1 // License: Apache 2.0. See LICENSE file in root directory.
2 // Copyright(c) 2015 Intel Corporation. All Rights Reserved.
3 
4 #if (_MSC_FULL_VER < 180031101)
5 #error At least Visual Studio 2013 Update 4 is required to compile this backend
6 #endif
7 
8 #ifndef NOMINMAX
9 #define NOMINMAX
10 #endif
11 
12 #include "../types.h"
13 #include "mf-hid.h"
14 #include "win/win-helpers.h"
15 #include "metadata.h"
16 
17 #include <PortableDeviceTypes.h>
18 //#include <PortableDeviceClassExtension.h>
19 #include <PortableDevice.h>
20 #include <Windows.h>
21 #include <Sensorsapi.h>
22 #include <sensors.h>
23 #include <SensAPI.h>
24 #include <initguid.h>
25 #include <propkeydef.h>
26 #include <comutil.h>
27 #include <string>
28 
29 #pragma comment(lib, "Sensorsapi.lib")
30 #pragma comment(lib, "PortableDeviceGuids.lib")
31 
32 // Windows Filetime is represented in 64 - bit number of 100 - nanosecond intervals since midnight Jan 1, 1601
33 // To convert to the Unix epoch, subtract 116444736000000000LL to reach Jan 1, 1970.
34 constexpr uint64_t WIN_FILETIME_2_UNIX_SYSTIME = 116444736000000000LL;
35 
36 namespace librealsense
37 {
38  namespace platform
39  {
40  class sensor_events : public ISensorEvents
41  {
42  public:
43  virtual ~sensor_events() = default;
44 
45  explicit sensor_events(hid_callback callback) : m_cRef(0), _callback(callback) {}
46 
47  STDMETHODIMP QueryInterface(REFIID iid, void** ppv)
48  {
49  if (ppv == NULL)
50  {
51  return E_POINTER;
52  }
53  if (iid == __uuidof(IUnknown))
54  {
55  *ppv = static_cast<IUnknown*>(this);
56  }
57  else if (iid == __uuidof(ISensorEvents))
58  {
59  *ppv = static_cast<ISensorEvents*>(this);
60  }
61  else
62  {
63  *ppv = NULL;
64  return E_NOINTERFACE;
65  }
66  AddRef();
67  return S_OK;
68  }
69 
70  STDMETHODIMP_(ULONG) AddRef()
71  {
72  return InterlockedIncrement(&m_cRef);
73  }
74 
75  STDMETHODIMP_(ULONG) Release()
76  {
77  ULONG count = InterlockedDecrement(&m_cRef);
78  if (count == 0)
79  {
80  delete this;
81  return 0;
82  }
83  return count;
84  }
85 
86  //
87  // ISensorEvents methods.
88  //
89 
90  STDMETHODIMP OnEvent(
91  ISensor *pSensor,
92  REFGUID eventID,
93  IPortableDeviceValues *pEventData)
94  {
95  HRESULT hr = S_OK;
96 
97  // Handle custom events here.
98 
99  return hr;
100  }
101 
102  STDMETHODIMP OnDataUpdated(ISensor *pSensor, ISensorDataReport *report)
103  {
104  if (NULL == report ||
105  NULL == pSensor)
106  {
107  return E_INVALIDARG;
108  }
109 
110  BSTR fName{};
111  SYSTEMTIME sys_time;
112  FILETIME file_time;
113  report->GetTimestamp(&sys_time);
114 
115  PROPVARIANT var = {};
116  // Custom timestamp low
117  auto hr = (report->GetSensorValue(SENSOR_DATA_TYPE_CUSTOM_VALUE1, &var));
118  if (FAILED(hr)) return S_OK;
119  auto customTimestampLow = var.ulVal;
120 
121  // Custom timestamp high
122  CHECK_HR(report->GetSensorValue(SENSOR_DATA_TYPE_CUSTOM_VALUE2, &var));
123  auto customTimestampHigh = var.ulVal;
124 
125  // Parse additional custom fields
126  CHECK_HR(report->GetSensorValue(SENSOR_DATA_TYPE_CUSTOM_VALUE6, &var));
127  uint8_t imu_count = var.bVal;
128  CHECK_HR(report->GetSensorValue(SENSOR_DATA_TYPE_CUSTOM_VALUE7, &var));
129  uint8_t usb_count = var.bVal;
130 
131  /* Retrieve sensor type - Sensor types are more specific groupings than sensor categories. Sensor type IDs are GUIDs that are defined in Sensors.h */
132 
133  SENSOR_TYPE_ID type{};
134 
135  CHECK_HR(pSensor->GetType(&type));
136 
137  double rawX, rawY, rawZ;
138 
139 
140  if (type == SENSOR_TYPE_ACCELEROMETER_3D)
141  {
142  CHECK_HR(report->GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_X_G, &var));
143  rawX = var.dblVal;
144 
145  CHECK_HR(report->GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_Y_G, &var));
146  rawY = var.dblVal;
147 
148  CHECK_HR(report->GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_Z_G, &var));
149  rawZ = var.dblVal;
150 
151  static constexpr double accelerator_transform_factor = 1000.0;
152 
153  rawX *= accelerator_transform_factor;
154  rawY *= accelerator_transform_factor;
155  rawZ *= accelerator_transform_factor;
156  }
157  else if (type == SENSOR_TYPE_GYROMETER_3D)
158  {
159  // Raw X
160  CHECK_HR(report->GetSensorValue(SENSOR_DATA_TYPE_ANGULAR_VELOCITY_X_DEGREES_PER_SECOND, &var));
161  rawX = var.dblVal;
162 
163  // Raw Y
164  CHECK_HR(report->GetSensorValue(SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Y_DEGREES_PER_SECOND, &var));
165  rawY = var.dblVal;
166 
167  // Raw Z
168  CHECK_HR(report->GetSensorValue(SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Z_DEGREES_PER_SECOND, &var));
169  rawZ = var.dblVal;
170 
171  static constexpr double gyro_transform_factor = 10.0;
172 
173  rawX *= gyro_transform_factor;
174  rawY *= gyro_transform_factor;
175  rawZ *= gyro_transform_factor;
176  }
177  else
178  {
179  /* Unsupported sensor */
180  return S_FALSE;
181  }
182 
183  PropVariantClear(&var);
184 
185  sensor_data d{};
187  // Populate HID IMU data - Header
188  metadata_hid_raw meta_data{};
190  meta_data.header.length = hid_header_size + metadata_imu_report_size;
191  meta_data.header.timestamp = customTimestampLow | (customTimestampHigh < 32);
192  // Payload:
193  meta_data.report_type.imu_report.header.md_type_id = md_type::META_DATA_HID_IMU_REPORT_ID;
194  meta_data.report_type.imu_report.header.md_size = metadata_imu_report_size;
195  meta_data.report_type.imu_report.flags = static_cast<uint8_t>( md_hid_imu_attributes::custom_timestamp_attirbute |
198  meta_data.report_type.imu_report.custom_timestamp = customTimestampLow | (customTimestampHigh < 32);
199  meta_data.report_type.imu_report.imu_counter = imu_count;
200  meta_data.report_type.imu_report.usb_counter = usb_count;
201 
202  data.x = static_cast<int16_t>(rawX);
203  data.y = static_cast<int16_t>(rawY);
204  data.z = static_cast<int16_t>(rawZ);
205  data.ts_low = customTimestampLow;
206  data.ts_high = customTimestampHigh;
207 
208  pSensor->GetFriendlyName(&fName);
209  d.sensor.name = CW2A(fName);
210  SysFreeString(fName); // free string after it was copied to sensor data
211 
212  d.fo.pixels = &data;
213  d.fo.metadata = &meta_data;
214  d.fo.metadata_size = metadata_hid_raw_size;
215  d.fo.frame_size = sizeof(data);
216  d.fo.backend_time = 0;
217  if (SystemTimeToFileTime(&sys_time, &file_time))
218  {
219  auto ll_now = (LONGLONG)file_time.dwLowDateTime + ((LONGLONG)(file_time.dwHighDateTime) << 32LL) - WIN_FILETIME_2_UNIX_SYSTIME;
220  d.fo.backend_time = ll_now * 0.0001; //100 nano-sec to millisec
221  }
222 
223  _callback(d);
224 
225  return S_OK;
226  }
227 
228  STDMETHODIMP OnLeave(
229  REFSENSOR_ID sensorID)
230  {
231  HRESULT hr = S_OK;
232 
233  // Perform any housekeeping tasks for the sensor that is leaving.
234  // For example, if you have maintained a reference to the sensor,
235  // release it now and set the pointer to NULL.
236 
237  return hr;
238  }
239 
240  STDMETHODIMP OnStateChanged(
241  ISensor* pSensor,
242  SensorState state)
243  {
244  HRESULT hr = S_OK;
245 
246  if (NULL == pSensor)
247  {
248  return E_INVALIDARG;
249  }
250 
251 
252  if (state == SENSOR_STATE_READY)
253  {
254  wprintf_s(L"\nTime sensor is now ready.");
255  }
256  else if (state == SENSOR_STATE_ACCESS_DENIED)
257  {
258  wprintf_s(L"\nNo permission for the time sensor.\n");
259  wprintf_s(L"Enable the sensor in the control panel.\n");
260  }
261 
262 
263  return hr;
264  }
265 
266  private:
267  long m_cRef;
269  };
270 
271  void wmf_hid_device::open(const std::vector<hid_profile>&iio_profiles)
272  {
273  try
274  {
275  for (auto& profile_to_open : iio_profiles)
276  {
277  for (auto& connected_sensor : _connected_sensors)
278  {
279  if (profile_to_open.sensor_name == connected_sensor->get_sensor_name())
280  {
281  /* Set SENSOR_PROPERTY_CURRENT_REPORT_INTERVAL sensor property to profile */
282  HRESULT hr = S_OK;
283  IPortableDeviceValues* pPropsToSet = NULL; // Input
284  IPortableDeviceValues* pPropsReturn = NULL; // Output
285 
286  /* Create the input object */
287  CHECK_HR(CoCreateInstance(__uuidof(PortableDeviceValues), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pPropsToSet)));
288 
289  /* Add the current report interval property */
290  hr = pPropsToSet->SetUnsignedIntegerValue(SENSOR_PROPERTY_CURRENT_REPORT_INTERVAL, profile_to_open.frequency);
291  if (SUCCEEDED(hr))
292  {
293  // Setting a single property
294  hr = connected_sensor->get_sensor()->SetProperties(pPropsToSet, &pPropsReturn);
295  if (SUCCEEDED(hr))
296  {
297  _opened_sensors.push_back(connected_sensor);
298  pPropsReturn->Release();
299  }
300  }
301 
302  pPropsToSet->Release();
303  }
304  }
305  }
306  }
307  catch (...)
308  {
309  for (auto& connected_sensor : _connected_sensors)
310  {
311  connected_sensor.reset();
312  }
313  _connected_sensors.clear();
314  LOG_ERROR("Hid device is busy!");
315  throw;
316  }
317  }
318 
320  {
321  for (auto& open_sensor : _opened_sensors)
322  {
323  open_sensor.reset();
324  }
325  _opened_sensors.clear();
326  }
327 
329  {
330  // Hack, start default profile
331  _cb = new sensor_events(callback);
332  ISensorEvents* sensorEvents = nullptr;
333  CHECK_HR(_cb->QueryInterface(IID_PPV_ARGS(&sensorEvents)));
334 
335  for (auto& sensor : _opened_sensors)
336  {
337  CHECK_HR(sensor->start_capture(sensorEvents));
338  }
339  }
340 
342  {
343  for (auto& sensor : _opened_sensors)
344  {
345  sensor->stop_capture();
346  }
347  _cb = nullptr;
348  }
349 
350  std::vector<hid_sensor> wmf_hid_device::get_sensors()
351  {
352  std::vector<hid_sensor> sensors;
353 
354  for (auto& sensor : _hid_profiles)
355  sensors.push_back({ sensor.sensor_name });
356 
357  return sensors;
358  }
359 
360  std::vector<uint8_t> wmf_hid_device::get_custom_report_data(const std::string & custom_sensor_name, const std::string & report_name, custom_sensor_report_field report_field)
361  {
362  return std::vector<uint8_t>();
363  }
364 
365  void wmf_hid_device::foreach_hid_device(std::function<void(hid_device_info, CComPtr<ISensor>)> action)
366  {
367  /* Enumerate all HID devices and run action function on each device */
368  try
369  {
370  CComPtr<ISensorManager> pSensorManager = nullptr;
371  CComPtr<ISensorCollection> pSensorCollection = nullptr;
372  CComPtr<ISensor> pSensor = nullptr;
373  ULONG sensorCount = 0;
374  HRESULT res{};
375 
376  CHECK_HR(CoCreateInstance(CLSID_SensorManager, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pSensorManager)));
377 
378  /* Retrieves a collection containing all sensors associated with category SENSOR_CATEGORY_ALL */
379  LOG_HR(res=pSensorManager->GetSensorsByCategory(SENSOR_CATEGORY_ALL, &pSensorCollection));
380  if (SUCCEEDED(res))
381  {
382  /* Retrieves the count of sensors in the collection */
383  CHECK_HR(pSensorCollection->GetCount(&sensorCount));
384 
385  for (ULONG i = 0; i < sensorCount; i++)
386  {
387  /* Retrieves the sensor at the specified index in the collection */
388  if (SUCCEEDED(pSensorCollection->GetAt(i, &pSensor.p)))
389  {
390  /* Retrieve SENSOR_PROPERTY_FRIENDLY_NAME which is the sensor name that is intended to be seen by the user */
391  BSTR fName{};
392  LOG_HR(res = pSensor->GetFriendlyName(&fName));
393  if (FAILED(res))
394  fName= L"Unidentified HID sensor";
395 
396  /* Retrieve SENSOR_PROPERTY_PERSISTENT_UNIQUE_ID which is a GUID that uniquely identifies the sensor on the current computer */
397  SENSOR_ID id{};
398  CHECK_HR(pSensor->GetID(&id));
399 
400  /* Retrieve sensor type - Sensor types are more specific groupings than sensor categories. Sensor type IDs are GUIDs that are defined in Sensors.h */
401  SENSOR_TYPE_ID type{};
402  CHECK_HR(pSensor->GetType(&type));
403 
404  CComPtr<IPortableDeviceValues> pValues = nullptr; // Output
406 
407  /* Retrieves multiple sensor properties */
408  auto hr = pSensor->GetProperties(nullptr, &pValues);
409  if (SUCCEEDED(hr))
410  {
411  /* Get the number of property returned */
412  DWORD propertyCount = 0;
413  hr = pValues->GetCount(&propertyCount);
414  if (SUCCEEDED(hr))
415  {
416  PROPERTYKEY propertyKey;
417  PROPVARIANT propertyValue = {};
418 
419  /* Loop through the properties */
420  for (DWORD properyIndex = 0; properyIndex < propertyCount; properyIndex++)
421  {
422  // Get the value at the current index.
423  hr = pValues->GetAt(properyIndex, &propertyKey, &propertyValue);
424  if (SUCCEEDED(hr))
425  {
426  if (IsEqualPropertyKey(propertyKey, SENSOR_PROPERTY_DEVICE_PATH))
427  {
428  info.device_path = win_to_utf( propertyValue.pwszVal );
429  info.id = win_to_utf( fName );
430 
431  uint16_t vid, pid, mi;
433  if (parse_usb_path_multiple_interface(vid, pid, mi, uid, info.device_path, guid))
434  {
435  auto node = cm_node::from_device_path( propertyValue.pwszVal );
436  if( node.valid() )
437  {
438  // We take the "unique id" (really, the composite ID used to associate all the devices belonging to
439  // a single composite device) of the PARENT of the HID device:
440  // 17 USB\VID_8086&PID_0B4D\012345678901 "USB Composite Device"
441  // 18 USB\VID_8086&PID_0B4D&MI_00\6&CB1C340&0&0000 "Intel(R) RealSense(TM) Depth Camera 465 Depth"
442  // 19 USB\VID_8086&PID_0B4D&MI_03\6&CB1C340&0&0003 "Intel(R) RealSense(TM) Depth Camera 465 RGB"
443  // 20 USB\VID_8086&PID_0B4D&MI_05\6&CB1C340&0&0005 "USB Input Device"
444  // 21 HID\VID_8086&PID_0B4D&MI_05\7&24FD3503&0&0000 "HID Sensor Collection V2"
445  // 22 USB\VID_8086&PID_0B4D&MI_06\6&CB1C340&0&0006 "Intel(R) RealSense(TM) Depth Camera 465 "
446  // (the first number is the CM DEVINST handle for each node)
447  // Note that all the USB devices have the same "CB1C340" ID, while the HID device is "24FD3503".
448  // Because the HID devices are "inside" a USB device parent in the OS's CM tree, we can try to get the
449  // parent UID:
450  info.unique_id = node.get_parent().get_uid();
451  }
452  else
453  {
454  LOG_WARNING( "Parent for HID device not available: " << info.device_path );
455  // Leave it empty: it won't be matched against anything
456  }
457 
458  info.pid = to_string() << std::hex << pid;
459  info.vid = to_string() << std::hex << vid;
460  }
461  }
462  if (IsEqualPropertyKey(propertyKey, SENSOR_PROPERTY_SERIAL_NUMBER))
463  {
464  auto str = win_to_utf( propertyValue.pwszVal );
465  std::transform(begin(str), end(str), begin(str), ::tolower);
466  info.serial_number = str;
467  }
468  }
469 
470  PropVariantClear(&propertyValue);
471  }
472  }
473  }
474 
475  action(info, pSensor);
476 
477  SysFreeString(fName);
478  }
479  }
480  }
481  }
482  catch (...)
483  {
484  LOG_INFO("Could not enumerate HID devices!");
485  }
486  }
487  }
488 }
STDMETHODIMP QueryInterface(REFIID iid, void **ppv)
Definition: mf-hid.cpp:47
GLuint GLuint end
constexpr uint8_t metadata_hid_raw_size
Definition: src/metadata.h:742
metadata_hid_raw - HID metadata structure layout populated by backend
Definition: src/metadata.h:736
std::vector< uint8_t > get_custom_report_data(const std::string &custom_sensor_name, const std::string &report_name, custom_sensor_report_field report_field) override
Definition: mf-hid.cpp:360
#define LOG_WARNING(...)
Definition: src/types.h:241
std::string win_to_utf(const WCHAR *s)
Definition: win-helpers.cpp:94
unsigned short uint16_t
Definition: stdint.h:79
#define CHECK_HR(x)
Definition: win-helpers.h:23
GLsizei const GLchar *const * string
d
Definition: rmse.py:171
sensor_events(hid_callback callback)
Definition: mf-hid.cpp:45
unsigned char uint8_t
Definition: stdint.h:78
STDMETHODIMP OnLeave(REFSENSOR_ID sensorID)
Definition: mf-hid.cpp:228
#define LOG_HR(x)
Definition: win-helpers.h:24
static cm_node from_device_path(LPCWSTR device_path)
Definition: win-helpers.h:53
def info(name, value, persistent=False)
Definition: test.py:301
not_this_one begin(...)
constexpr uint8_t metadata_imu_report_size
Definition: src/metadata.h:712
STDMETHODIMP OnDataUpdated(ISensor *pSensor, ISensorDataReport *report)
Definition: mf-hid.cpp:102
std::vector< hid_sensor > get_sensors() override
Definition: mf-hid.cpp:350
signed short int16_t
Definition: stdint.h:76
def callback(frame)
Definition: t265_stereo.py:91
unsigned __int64 uint64_t
Definition: stdint.h:90
void start_capture(hid_callback callback) override
Definition: mf-hid.cpp:328
#define LOG_ERROR(...)
Definition: src/types.h:242
bool parse_usb_path_multiple_interface(uint16_t &vid, uint16_t &pid, uint16_t &mi, std::string &unique_id, const std::string &path, std::string &device_guid)
action
Definition: enums.py:62
constexpr uint64_t WIN_FILETIME_2_UNIX_SYSTIME
Definition: mf-hid.cpp:34
LOG_INFO("Log message using LOG_INFO()")
GLenum type
STDMETHODIMP OnStateChanged(ISensor *pSensor, SensorState state)
Definition: mf-hid.cpp:240
GLint GLsizei count
void open(const std::vector< hid_profile > &iio_profiles) override
Definition: mf-hid.cpp:271
platform::hid_header header
Definition: src/metadata.h:738
#define NULL
Definition: tinycthread.c:47
int i
GLuint res
Definition: glext.h:8856
static void foreach_hid_device(std::function< void(hid_device_info, CComPtr< ISensor >)> action)
Definition: mf-hid.cpp:365
GLuint GLenum GLenum transform
Definition: glext.h:11553
std::function< void(const sensor_data &)> hid_callback
Definition: backend.h:327
STDMETHODIMP OnEvent(ISensor *pSensor, REFGUID eventID, IPortableDeviceValues *pEventData)
Definition: mf-hid.cpp:90
GLboolean * data
constexpr uint8_t hid_header_size
Definition: backend.h:166
Definition: parser.hpp:150
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:47:21