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

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

Issue 2447973003: [sensors] [win] Implement ambient light sensor for Windows platform (Closed)
Patch Set: Fixes for comments from Lei Zhang Created 4 years, 1 month 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
9 #include "base/callback.h"
10 #include "base/time/time.h"
11 #include "base/win/iunknown_impl.h"
12 #include "device/generic_sensor/public/cpp/platform_sensor_configuration.h"
13 #include "device/generic_sensor/public/cpp/sensor_reading.h"
14
15 namespace device {
16
17 // Init params for the PlatformSensorReaderWin.
18 struct ReaderInitParams {
19 // ISensorDataReport::GetSensorValue is not const, therefore, report
20 // cannot be passed as const ref.
21 // ISensorDataReport& report - report that contains new sensor data.
22 // SensorReading& reading - out parameter that must be populated.
23 // Returns HRESULT - S_OK on success, otherwise error code.
24 using ReaderFunctor = base::Callback<HRESULT(ISensorDataReport& report,
25 SensorReading& reading)>;
26 SENSOR_TYPE_ID sensor_type_id;
27 mojom::ReportingMode reporting_mode;
28 ReaderFunctor reader_func;
29 unsigned long min_reporting_interval_ms = 0;
30 };
31
32 namespace {
33
34 // Gets value from the report for provided key.
35 bool GetReadingValueForProperty(REFPROPERTYKEY key,
36 ISensorDataReport& report,
37 double* value) {
38 DCHECK(value);
39 PROPVARIANT variant_value = {};
40 if (SUCCEEDED(report.GetSensorValue(key, &variant_value))) {
41 if (variant_value.vt == VT_R8)
42 *value = variant_value.dblVal;
43 else if (variant_value.vt == VT_R4)
44 *value = variant_value.fltVal;
45 else
46 return false;
47 return true;
48 }
49
50 *value = 0;
51 return false;
52 }
53
54 // Creates ReaderInitParams params structure. To implement support for new
55 // sensor types, new switch case should be added and appropriate fields must
56 // be set:
57 // sensor_type_id - GUID of the sensor supported by Windows.
58 // reporting_mode - mode of reporting (ON_CHANGE | CONTINUOUS).
59 // reader_func - Functor that is responsible to populate SensorReading from
60 // ISensorDataReport data.
61 std::unique_ptr<ReaderInitParams> CreateReaderInitParamsForSensor(
62 mojom::SensorType type) {
63 auto params = std::make_unique<ReaderInitParams>();
64 switch (type) {
65 case mojom::SensorType::AMBIENT_LIGHT: {
66 params->sensor_type_id = SENSOR_TYPE_AMBIENT_LIGHT;
67 params->reporting_mode = mojom::ReportingMode::ON_CHANGE;
68 params->reader_func =
69 base::Bind([](ISensorDataReport& report, SensorReading& reading) {
70 double lux = 0.0;
71 if (!GetReadingValueForProperty(SENSOR_DATA_TYPE_LIGHT_LEVEL_LUX,
72 report, &lux)) {
73 return E_FAIL;
74 }
75 reading.values[0] = lux;
76 return S_OK;
77 });
78 return params;
79 }
80 default:
81 NOTIMPLEMENTED();
82 return nullptr;
83 }
84 }
85
86 } // namespace
87
88 // Class that implements ISensorEvents and IUnknown interfaces and used
89 // by ISensor interface to dispatch state and data change events.
90 class EventListener : public ISensorEvents, public base::win::IUnknownImpl {
91 public:
92 explicit EventListener(PlatformSensorReaderWin* platform_sensor_reader)
93 : platform_sensor_reader_(platform_sensor_reader) {
94 DCHECK(platform_sensor_reader_);
95 }
96
97 // IUnknown interface
98 ULONG STDMETHODCALLTYPE AddRef() override { return IUnknownImpl::AddRef(); }
99 ULONG STDMETHODCALLTYPE Release() override { return IUnknownImpl::Release(); }
100
101 STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override {
102 if (riid == __uuidof(ISensorEvents)) {
103 *ppv = static_cast<ISensorEvents*>(this);
104 AddRef();
105 return S_OK;
106 }
107 return IUnknownImpl::QueryInterface(riid, ppv);
108 }
109
110 protected:
111 ~EventListener() override = default;
112
113 // ISensorEvents interface
114 STDMETHODIMP OnEvent(ISensor*, REFGUID, IPortableDeviceValues*) override {
115 return S_OK;
116 }
117
118 STDMETHODIMP OnLeave(REFSENSOR_ID sensor_id) override {
119 // If event listener is active and sensor is disconnected, notify client
120 // about the error.
121 platform_sensor_reader_->SensorError();
122 platform_sensor_reader_->StopSensor();
123 return S_OK;
124 }
125
126 STDMETHODIMP OnStateChanged(ISensor* sensor, SensorState state) override {
127 if (sensor == nullptr)
128 return E_INVALIDARG;
129
130 if (state != SensorState::SENSOR_STATE_READY &&
131 state != SensorState::SENSOR_STATE_INITIALIZING) {
132 platform_sensor_reader_->SensorError();
133 platform_sensor_reader_->StopSensor();
134 }
135 return S_OK;
136 }
137
138 STDMETHODIMP OnDataUpdated(ISensor* sensor,
139 ISensorDataReport* report) override {
140 if (sensor == nullptr || report == nullptr)
141 return E_INVALIDARG;
142
143 // To get precise timestamp, we need to get delta between timestamp
144 // provided in the report and current system time. Then the delta in
145 // milliseconds is substracted from current high resolution timestamp.
146 SYSTEMTIME report_time;
147 HRESULT hr = report->GetTimestamp(&report_time);
148 if (FAILED(hr))
149 return hr;
150
151 base::TimeTicks ticks_now = base::TimeTicks::Now();
152 base::Time time_now = base::Time::NowFromSystemTime();
153
154 base::Time::Exploded exploded;
155 exploded.year = report_time.wYear;
156 exploded.month = report_time.wMonth;
157 exploded.day_of_week = report_time.wDayOfWeek;
158 exploded.day_of_month = report_time.wDay;
159 exploded.hour = report_time.wHour;
160 exploded.minute = report_time.wMinute;
161 exploded.second = report_time.wSecond;
162 exploded.millisecond = report_time.wMilliseconds;
163
164 base::Time timestamp;
165 if (!base::Time::FromUTCExploded(exploded, &timestamp))
166 return E_FAIL;
167
168 base::TimeDelta delta = time_now - timestamp;
169
170 SensorReading reading;
171 reading.timestamp = ((ticks_now - delta) - base::TimeTicks()).InSecondsF();
172
173 // Discard update events that have non-monotonically increasing timestamp.
174 if (last_sensor_reading_.timestamp > reading.timestamp)
175 return E_FAIL;
176
177 hr = platform_sensor_reader_->SensorReadingChanged(*report, reading);
178 if (SUCCEEDED(hr))
179 last_sensor_reading_ = reading;
180 return hr;
181 }
182
183 private:
184 PlatformSensorReaderWin* const platform_sensor_reader_;
185 SensorReading last_sensor_reading_;
186
187 DISALLOW_COPY_AND_ASSIGN(EventListener);
188 };
189
190 // static
191 std::unique_ptr<PlatformSensorReaderWin> PlatformSensorReaderWin::Create(
192 mojom::SensorType type,
193 base::win::ScopedComPtr<ISensorManager> sensor_manager) {
194 DCHECK(sensor_manager);
195
196 auto params = CreateReaderInitParamsForSensor(type);
197 if (!params)
198 return nullptr;
199
200 auto sensor = GetSensorForType(params->sensor_type_id, sensor_manager);
201 if (!sensor)
202 return nullptr;
203
204 PROPVARIANT variant = {};
205 if (SUCCEEDED(
206 sensor->GetProperty(SENSOR_PROPERTY_MIN_REPORT_INTERVAL, &variant))) {
Reilly Grant (use Gerrit) 2016/10/31 21:49:43 nit: since this had to get split across two lines
shalamov 2016/11/01 11:00:02 Done.
207 if (variant.vt == VT_UI4)
208 params->min_reporting_interval_ms = variant.ulVal;
209 }
210
211 GUID interests[] = {SENSOR_EVENT_STATE_CHANGED, SENSOR_EVENT_DATA_UPDATED};
212 HRESULT hr = sensor->SetEventInterest(interests, arraysize(interests));
213 if (FAILED(hr))
214 return nullptr;
215
216 return base::WrapUnique(
217 new PlatformSensorReaderWin(sensor, std::move(params)));
218 }
219
220 // static
221 base::win::ScopedComPtr<ISensor> PlatformSensorReaderWin::GetSensorForType(
222 REFSENSOR_TYPE_ID sensor_type,
223 base::win::ScopedComPtr<ISensorManager> sensor_manager) {
224 base::win::ScopedComPtr<ISensor> sensor;
225 base::win::ScopedComPtr<ISensorCollection> sensor_collection;
226 HRESULT hr = sensor_manager->GetSensorsByType(sensor_type,
227 sensor_collection.Receive());
228 if (FAILED(hr) || !sensor_collection)
229 return sensor;
230
231 ULONG count = 0;
232 hr = sensor_collection->GetCount(&count);
233 if (SUCCEEDED(hr) && count > 0)
234 sensor_collection->GetAt(0, sensor.Receive());
235 return sensor;
236 }
237
238 PlatformSensorReaderWin::PlatformSensorReaderWin(
239 base::win::ScopedComPtr<ISensor> sensor,
240 std::unique_ptr<ReaderInitParams> params)
241 : init_params_(std::move(params)),
242 task_runner_(base::ThreadTaskRunnerHandle::Get()),
243 sensor_active_(false),
244 client_(nullptr),
245 sensor_(sensor),
246 event_listener_(new EventListener(this)) {
247 DCHECK(init_params_);
248 DCHECK(!init_params_->reader_func.is_null());
249 DCHECK(sensor_);
250 }
251
252 void PlatformSensorReaderWin::SetClient(Client* client) {
253 base::AutoLock autolock(lock_);
254 // Can be null.
255 client_ = client;
256 }
257
258 void PlatformSensorReaderWin::StopSensor() {
259 base::AutoLock autolock(lock_);
260 if (sensor_active_) {
261 sensor_->SetEventSink(nullptr);
262 sensor_active_ = false;
263 }
264 }
265
266 PlatformSensorReaderWin::~PlatformSensorReaderWin() {
267 DCHECK(task_runner_->BelongsToCurrentThread());
268 }
269
270 bool PlatformSensorReaderWin::StartSensor(
271 const PlatformSensorConfiguration& configuration) {
272 base::AutoLock autolock(lock_);
273
274 if (!SetReportingInterval(configuration))
275 return false;
276
277 // Set event listener.
278 if (!sensor_active_) {
279 base::win::ScopedComPtr<ISensorEvents> sensor_events;
280 HRESULT hr = event_listener_->QueryInterface(__uuidof(ISensorEvents),
281 sensor_events.ReceiveVoid());
282
283 if (FAILED(hr) || !sensor_events)
284 return false;
285
286 if (FAILED(sensor_->SetEventSink(sensor_events.get())))
287 return false;
288
289 sensor_active_ = true;
290 }
291
292 return true;
293 }
294
295 bool PlatformSensorReaderWin::SetReportingInterval(
296 const PlatformSensorConfiguration& configuration) {
297 base::win::ScopedComPtr<IPortableDeviceValues> props;
298 if (SUCCEEDED(props.CreateInstance(CLSID_PortableDeviceValues))) {
299 unsigned interval =
300 (1 / configuration.frequency()) * base::Time::kMillisecondsPerSecond;
301 if (SUCCEEDED(props->SetUnsignedIntegerValue(
Reilly Grant (use Gerrit) 2016/10/31 21:49:43 Same here.
shalamov 2016/11/01 11:00:02 Done.
302 SENSOR_PROPERTY_CURRENT_REPORT_INTERVAL, interval))) {
303 base::win::ScopedComPtr<IPortableDeviceValues> return_props;
304 sensor_->SetProperties(props.get(), return_props.Receive());
305 return true;
306 }
307 }
308 return false;
309 }
310
311 HRESULT PlatformSensorReaderWin::SensorReadingChanged(
312 ISensorDataReport& report,
313 SensorReading& reading) const {
314 if (!client_)
315 return E_FAIL;
316
317 HRESULT hr = init_params_->reader_func.Run(report, reading);
318 if (SUCCEEDED(hr))
319 client_->OnReadingUpdated(reading);
320 return hr;
321 }
322
323 void PlatformSensorReaderWin::SensorError() {
324 if (client_)
325 client_->OnSensorError();
326 }
327
328 unsigned long PlatformSensorReaderWin::GetMinimalReportingIntervalMs() const {
329 return init_params_->min_reporting_interval_ms;
330 }
331
332 mojom::ReportingMode PlatformSensorReaderWin::GetReportingMode() const {
333 return init_params_->reporting_mode;
334 }
335
336 } // namespace device
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698