Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1406)

Side by Side Diff: device/generic_sensor/platform_sensor_reader_win.cc

Issue 2865263002: Move //device/generic_sensor to be part of the internal implementation of the Device Service. (Closed)
Patch Set: code rebase Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "device/generic_sensor/platform_sensor_reader_win.h"
6
7 #include <Sensors.h>
8 #include <objbase.h>
9
10 #include "base/callback.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/threading/thread_task_runner_handle.h"
13 #include "base/time/time.h"
14 #include "base/win/iunknown_impl.h"
15 #include "base/win/scoped_propvariant.h"
16 #include "device/generic_sensor/generic_sensor_consts.h"
17 #include "device/generic_sensor/public/cpp/platform_sensor_configuration.h"
18 #include "device/generic_sensor/public/cpp/sensor_reading.h"
19
20 namespace device {
21
22 // Init params for the PlatformSensorReaderWin.
23 struct ReaderInitParams {
24 // ISensorDataReport::GetSensorValue is not const, therefore, report
25 // cannot be passed as const ref.
26 // ISensorDataReport* report - report that contains new sensor data.
27 // SensorReading* reading - out parameter that must be populated.
28 // Returns HRESULT - S_OK on success, otherwise error code.
29 using ReaderFunctor = base::Callback<HRESULT(ISensorDataReport* report,
30 SensorReading* reading)>;
31 SENSOR_TYPE_ID sensor_type_id;
32 ReaderFunctor reader_func;
33 unsigned long min_reporting_interval_ms = 0;
34 };
35
36 namespace {
37
38 // Gets value from the report for provided key.
39 bool GetReadingValueForProperty(REFPROPERTYKEY key,
40 ISensorDataReport* report,
41 double* value) {
42 DCHECK(value);
43 base::win::ScopedPropVariant variant_value;
44 if (SUCCEEDED(report->GetSensorValue(key, variant_value.Receive()))) {
45 if (variant_value.get().vt == VT_R8)
46 *value = variant_value.get().dblVal;
47 else if (variant_value.get().vt == VT_R4)
48 *value = variant_value.get().fltVal;
49 else
50 return false;
51 return true;
52 }
53
54 *value = 0;
55 return false;
56 }
57
58 // Ambient light sensor reader initialization parameters.
59 std::unique_ptr<ReaderInitParams> CreateAmbientLightReaderInitParams() {
60 auto params = base::MakeUnique<ReaderInitParams>();
61 params->sensor_type_id = SENSOR_TYPE_AMBIENT_LIGHT;
62 params->reader_func =
63 base::Bind([](ISensorDataReport* report, SensorReading* reading) {
64 double lux = 0.0;
65 if (!GetReadingValueForProperty(SENSOR_DATA_TYPE_LIGHT_LEVEL_LUX,
66 report, &lux)) {
67 return E_FAIL;
68 }
69 reading->values[0] = lux;
70 return S_OK;
71 });
72 return params;
73 }
74
75 // Accelerometer sensor reader initialization parameters.
76 std::unique_ptr<ReaderInitParams> CreateAccelerometerReaderInitParams() {
77 auto params = base::MakeUnique<ReaderInitParams>();
78 params->sensor_type_id = SENSOR_TYPE_ACCELEROMETER_3D;
79 params->reader_func =
80 base::Bind([](ISensorDataReport* report, SensorReading* reading) {
81 double x = 0.0;
82 double y = 0.0;
83 double z = 0.0;
84 if (!GetReadingValueForProperty(SENSOR_DATA_TYPE_ACCELERATION_X_G,
85 report, &x) ||
86 !GetReadingValueForProperty(SENSOR_DATA_TYPE_ACCELERATION_Y_G,
87 report, &y) ||
88 !GetReadingValueForProperty(SENSOR_DATA_TYPE_ACCELERATION_Z_G,
89 report, &z)) {
90 return E_FAIL;
91 }
92
93 // Windows uses coordinate system where Z axis points down from device
94 // screen, therefore, using right hand notation, we have to reverse
95 // sign for each axis. Values are converted from G/s^2 to m/s^2.
96 reading->values[0] = -x * kMeanGravity;
97 reading->values[1] = -y * kMeanGravity;
98 reading->values[2] = -z * kMeanGravity;
99 return S_OK;
100 });
101 return params;
102 }
103
104 // Gyroscope sensor reader initialization parameters.
105 std::unique_ptr<ReaderInitParams> CreateGyroscopeReaderInitParams() {
106 auto params = base::MakeUnique<ReaderInitParams>();
107 params->sensor_type_id = SENSOR_TYPE_GYROMETER_3D;
108 params->reader_func = base::Bind([](ISensorDataReport* report,
109 SensorReading* reading) {
110 double x = 0.0;
111 double y = 0.0;
112 double z = 0.0;
113 if (!GetReadingValueForProperty(
114 SENSOR_DATA_TYPE_ANGULAR_VELOCITY_X_DEGREES_PER_SECOND, report,
115 &x) ||
116 !GetReadingValueForProperty(
117 SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Y_DEGREES_PER_SECOND, report,
118 &y) ||
119 !GetReadingValueForProperty(
120 SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Z_DEGREES_PER_SECOND, report,
121 &z)) {
122 return E_FAIL;
123 }
124
125 // Windows uses coordinate system where Z axis points down from device
126 // screen, therefore, using right hand notation, we have to reverse
127 // sign for each axis. Values are converted from deg to rad.
128 reading->values[0] = -x * kRadiansInDegrees;
129 reading->values[1] = -y * kRadiansInDegrees;
130 reading->values[2] = -z * kRadiansInDegrees;
131 return S_OK;
132 });
133 return params;
134 }
135
136 // Magnetometer sensor reader initialization parameters.
137 std::unique_ptr<ReaderInitParams> CreateMagnetometerReaderInitParams() {
138 auto params = base::MakeUnique<ReaderInitParams>();
139 params->sensor_type_id = SENSOR_TYPE_COMPASS_3D;
140 params->reader_func =
141 base::Bind([](ISensorDataReport* report, SensorReading* reading) {
142 double x = 0.0;
143 double y = 0.0;
144 double z = 0.0;
145 if (!GetReadingValueForProperty(
146 SENSOR_DATA_TYPE_MAGNETIC_FIELD_STRENGTH_X_MILLIGAUSS, report,
147 &x) ||
148 !GetReadingValueForProperty(
149 SENSOR_DATA_TYPE_MAGNETIC_FIELD_STRENGTH_Y_MILLIGAUSS, report,
150 &y) ||
151 !GetReadingValueForProperty(
152 SENSOR_DATA_TYPE_MAGNETIC_FIELD_STRENGTH_Z_MILLIGAUSS, report,
153 &z)) {
154 return E_FAIL;
155 }
156
157 // Windows uses coordinate system where Z axis points down from device
158 // screen, therefore, using right hand notation, we have to reverse
159 // sign for each axis. Values are converted from Milligaus to
160 // Microtesla.
161 reading->values[0] = -x * kMicroteslaInMilligauss;
162 reading->values[1] = -y * kMicroteslaInMilligauss;
163 reading->values[2] = -z * kMicroteslaInMilligauss;
164 return S_OK;
165 });
166 return params;
167 }
168
169 // AbsoluteOrientation sensor reader initialization parameters.
170 std::unique_ptr<ReaderInitParams> CreateAbsoluteOrientationReaderInitParams() {
171 auto params = base::MakeUnique<ReaderInitParams>();
172 params->sensor_type_id = SENSOR_TYPE_AGGREGATED_DEVICE_ORIENTATION;
173 params->reader_func =
174 base::Bind([](ISensorDataReport* report, SensorReading* reading) {
175 base::win::ScopedPropVariant quat_variant;
176 HRESULT hr = report->GetSensorValue(SENSOR_DATA_TYPE_QUATERNION,
177 quat_variant.Receive());
178 if (FAILED(hr) || quat_variant.get().vt != (VT_VECTOR | VT_UI1) ||
179 quat_variant.get().caub.cElems < 16) {
180 return E_FAIL;
181 }
182
183 float* quat = reinterpret_cast<float*>(quat_variant.get().caub.pElems);
184
185 // Windows uses coordinate system where Z axis points down from device
186 // screen, therefore, using right hand notation, we have to reverse
187 // sign for each quaternion component.
188 reading->values[0] = -quat[0]; // x*sin(Theta/2)
189 reading->values[1] = -quat[1]; // y*sin(Theta/2)
190 reading->values[2] = -quat[2]; // z*sin(Theta/2)
191 reading->values[3] = quat[3]; // cos(Theta/2)
192 return S_OK;
193 });
194 return params;
195 }
196
197 // Creates ReaderInitParams params structure. To implement support for new
198 // sensor types, new switch case should be added and appropriate fields must
199 // be set:
200 // sensor_type_id - GUID of the sensor supported by Windows.
201 // reader_func - Functor that is responsible to populate SensorReading from
202 // ISensorDataReport data.
203 std::unique_ptr<ReaderInitParams> CreateReaderInitParamsForSensor(
204 mojom::SensorType type) {
205 switch (type) {
206 case mojom::SensorType::AMBIENT_LIGHT:
207 return CreateAmbientLightReaderInitParams();
208 case mojom::SensorType::ACCELEROMETER:
209 return CreateAccelerometerReaderInitParams();
210 case mojom::SensorType::GYROSCOPE:
211 return CreateGyroscopeReaderInitParams();
212 case mojom::SensorType::MAGNETOMETER:
213 return CreateMagnetometerReaderInitParams();
214 case mojom::SensorType::ABSOLUTE_ORIENTATION:
215 return CreateAbsoluteOrientationReaderInitParams();
216 default:
217 NOTIMPLEMENTED();
218 return nullptr;
219 }
220 }
221
222 } // namespace
223
224 // Class that implements ISensorEvents and IUnknown interfaces and used
225 // by ISensor interface to dispatch state and data change events.
226 class EventListener : public ISensorEvents, public base::win::IUnknownImpl {
227 public:
228 explicit EventListener(PlatformSensorReaderWin* platform_sensor_reader)
229 : platform_sensor_reader_(platform_sensor_reader) {
230 DCHECK(platform_sensor_reader_);
231 }
232
233 // IUnknown interface
234 ULONG STDMETHODCALLTYPE AddRef() override { return IUnknownImpl::AddRef(); }
235 ULONG STDMETHODCALLTYPE Release() override { return IUnknownImpl::Release(); }
236
237 STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override {
238 if (riid == __uuidof(ISensorEvents)) {
239 *ppv = static_cast<ISensorEvents*>(this);
240 AddRef();
241 return S_OK;
242 }
243 return IUnknownImpl::QueryInterface(riid, ppv);
244 }
245
246 protected:
247 ~EventListener() override = default;
248
249 // ISensorEvents interface
250 STDMETHODIMP OnEvent(ISensor*, REFGUID, IPortableDeviceValues*) override {
251 return S_OK;
252 }
253
254 STDMETHODIMP OnLeave(REFSENSOR_ID sensor_id) override {
255 // If event listener is active and sensor is disconnected, notify client
256 // about the error.
257 platform_sensor_reader_->SensorError();
258 platform_sensor_reader_->StopSensor();
259 return S_OK;
260 }
261
262 STDMETHODIMP OnStateChanged(ISensor* sensor, SensorState state) override {
263 if (sensor == nullptr)
264 return E_INVALIDARG;
265
266 if (state != SensorState::SENSOR_STATE_READY &&
267 state != SensorState::SENSOR_STATE_INITIALIZING) {
268 platform_sensor_reader_->SensorError();
269 platform_sensor_reader_->StopSensor();
270 }
271 return S_OK;
272 }
273
274 STDMETHODIMP OnDataUpdated(ISensor* sensor,
275 ISensorDataReport* report) override {
276 if (sensor == nullptr || report == nullptr)
277 return E_INVALIDARG;
278
279 // To get precise timestamp, we need to get delta between timestamp
280 // provided in the report and current system time. Then the delta in
281 // milliseconds is substracted from current high resolution timestamp.
282 SYSTEMTIME report_time;
283 HRESULT hr = report->GetTimestamp(&report_time);
284 if (FAILED(hr))
285 return hr;
286
287 base::TimeTicks ticks_now = base::TimeTicks::Now();
288 base::Time time_now = base::Time::NowFromSystemTime();
289
290 base::Time::Exploded exploded;
291 exploded.year = report_time.wYear;
292 exploded.month = report_time.wMonth;
293 exploded.day_of_week = report_time.wDayOfWeek;
294 exploded.day_of_month = report_time.wDay;
295 exploded.hour = report_time.wHour;
296 exploded.minute = report_time.wMinute;
297 exploded.second = report_time.wSecond;
298 exploded.millisecond = report_time.wMilliseconds;
299
300 base::Time timestamp;
301 if (!base::Time::FromUTCExploded(exploded, &timestamp))
302 return E_FAIL;
303
304 base::TimeDelta delta = time_now - timestamp;
305
306 SensorReading reading;
307 reading.timestamp = ((ticks_now - delta) - base::TimeTicks()).InSecondsF();
308
309 // Discard update events that have non-monotonically increasing timestamp.
310 if (last_sensor_reading_.timestamp > reading.timestamp)
311 return E_FAIL;
312
313 hr = platform_sensor_reader_->SensorReadingChanged(report, &reading);
314 if (SUCCEEDED(hr))
315 last_sensor_reading_ = reading;
316 return hr;
317 }
318
319 private:
320 PlatformSensorReaderWin* const platform_sensor_reader_;
321 SensorReading last_sensor_reading_;
322
323 DISALLOW_COPY_AND_ASSIGN(EventListener);
324 };
325
326 // static
327 std::unique_ptr<PlatformSensorReaderWin> PlatformSensorReaderWin::Create(
328 mojom::SensorType type,
329 base::win::ScopedComPtr<ISensorManager> sensor_manager) {
330 DCHECK(sensor_manager);
331
332 auto params = CreateReaderInitParamsForSensor(type);
333 if (!params)
334 return nullptr;
335
336 auto sensor = GetSensorForType(params->sensor_type_id, sensor_manager);
337 if (!sensor)
338 return nullptr;
339
340 base::win::ScopedPropVariant min_interval;
341 HRESULT hr = sensor->GetProperty(SENSOR_PROPERTY_MIN_REPORT_INTERVAL,
342 min_interval.Receive());
343 if (SUCCEEDED(hr) && min_interval.get().vt == VT_UI4)
344 params->min_reporting_interval_ms = min_interval.get().ulVal;
345
346 GUID interests[] = {SENSOR_EVENT_STATE_CHANGED, SENSOR_EVENT_DATA_UPDATED};
347 hr = sensor->SetEventInterest(interests, arraysize(interests));
348 if (FAILED(hr))
349 return nullptr;
350
351 return base::WrapUnique(
352 new PlatformSensorReaderWin(sensor, std::move(params)));
353 }
354
355 // static
356 base::win::ScopedComPtr<ISensor> PlatformSensorReaderWin::GetSensorForType(
357 REFSENSOR_TYPE_ID sensor_type,
358 base::win::ScopedComPtr<ISensorManager> sensor_manager) {
359 base::win::ScopedComPtr<ISensor> sensor;
360 base::win::ScopedComPtr<ISensorCollection> sensor_collection;
361 HRESULT hr = sensor_manager->GetSensorsByType(
362 sensor_type, sensor_collection.GetAddressOf());
363 if (FAILED(hr) || !sensor_collection)
364 return sensor;
365
366 ULONG count = 0;
367 hr = sensor_collection->GetCount(&count);
368 if (SUCCEEDED(hr) && count > 0)
369 sensor_collection->GetAt(0, sensor.GetAddressOf());
370 return sensor;
371 }
372
373 PlatformSensorReaderWin::PlatformSensorReaderWin(
374 base::win::ScopedComPtr<ISensor> sensor,
375 std::unique_ptr<ReaderInitParams> params)
376 : init_params_(std::move(params)),
377 task_runner_(base::ThreadTaskRunnerHandle::Get()),
378 sensor_active_(false),
379 client_(nullptr),
380 sensor_(sensor),
381 event_listener_(new EventListener(this)),
382 weak_factory_(this) {
383 DCHECK(init_params_);
384 DCHECK(!init_params_->reader_func.is_null());
385 DCHECK(sensor_);
386 }
387
388 void PlatformSensorReaderWin::SetClient(Client* client) {
389 base::AutoLock autolock(lock_);
390 // Can be null.
391 client_ = client;
392 }
393
394 void PlatformSensorReaderWin::StopSensor() {
395 base::AutoLock autolock(lock_);
396 if (sensor_active_) {
397 sensor_->SetEventSink(nullptr);
398 sensor_active_ = false;
399 }
400 }
401
402 PlatformSensorReaderWin::~PlatformSensorReaderWin() {
403 DCHECK(task_runner_->BelongsToCurrentThread());
404 }
405
406 bool PlatformSensorReaderWin::StartSensor(
407 const PlatformSensorConfiguration& configuration) {
408 base::AutoLock autolock(lock_);
409
410 if (!SetReportingInterval(configuration))
411 return false;
412
413 if (!sensor_active_) {
414 task_runner_->PostTask(
415 FROM_HERE, base::Bind(&PlatformSensorReaderWin::ListenSensorEvent,
416 weak_factory_.GetWeakPtr()));
417 sensor_active_ = true;
418 }
419
420 return true;
421 }
422
423 void PlatformSensorReaderWin::ListenSensorEvent() {
424 // Set event listener.
425 if (FAILED(sensor_->SetEventSink(event_listener_.get()))) {
426 SensorError();
427 StopSensor();
428 }
429 }
430
431 bool PlatformSensorReaderWin::SetReportingInterval(
432 const PlatformSensorConfiguration& configuration) {
433 base::win::ScopedComPtr<IPortableDeviceValues> props;
434 if (SUCCEEDED(::CoCreateInstance(CLSID_PortableDeviceValues, nullptr,
435 CLSCTX_ALL, IID_PPV_ARGS(&props)))) {
436 unsigned interval =
437 (1 / configuration.frequency()) * base::Time::kMillisecondsPerSecond;
438
439 HRESULT hr = props->SetUnsignedIntegerValue(
440 SENSOR_PROPERTY_CURRENT_REPORT_INTERVAL, interval);
441
442 if (SUCCEEDED(hr)) {
443 base::win::ScopedComPtr<IPortableDeviceValues> return_props;
444 hr = sensor_->SetProperties(props.Get(), return_props.GetAddressOf());
445 return SUCCEEDED(hr);
446 }
447 }
448 return false;
449 }
450
451 HRESULT PlatformSensorReaderWin::SensorReadingChanged(
452 ISensorDataReport* report,
453 SensorReading* reading) const {
454 if (!client_)
455 return E_FAIL;
456
457 HRESULT hr = init_params_->reader_func.Run(report, reading);
458 if (SUCCEEDED(hr))
459 client_->OnReadingUpdated(*reading);
460 return hr;
461 }
462
463 void PlatformSensorReaderWin::SensorError() {
464 if (client_)
465 client_->OnSensorError();
466 }
467
468 unsigned long PlatformSensorReaderWin::GetMinimalReportingIntervalMs() const {
469 return init_params_->min_reporting_interval_ms;
470 }
471
472 } // namespace device
OLDNEW
« no previous file with comments | « device/generic_sensor/platform_sensor_reader_win.h ('k') | device/generic_sensor/platform_sensor_win.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698