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

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: Rebased to master 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 HRESULT hr =
206 sensor->GetProperty(SENSOR_PROPERTY_MIN_REPORT_INTERVAL, &variant);
207 if (SUCCEEDED(hr) && variant.vt == VT_UI4)
208 params->min_reporting_interval_ms = variant.ulVal;
209
210 GUID interests[] = {SENSOR_EVENT_STATE_CHANGED, SENSOR_EVENT_DATA_UPDATED};
211 hr = sensor->SetEventInterest(interests, arraysize(interests));
212 if (FAILED(hr))
213 return nullptr;
214
215 return base::WrapUnique(
216 new PlatformSensorReaderWin(sensor, std::move(params)));
217 }
218
219 // static
220 base::win::ScopedComPtr<ISensor> PlatformSensorReaderWin::GetSensorForType(
221 REFSENSOR_TYPE_ID sensor_type,
222 base::win::ScopedComPtr<ISensorManager> sensor_manager) {
223 base::win::ScopedComPtr<ISensor> sensor;
224 base::win::ScopedComPtr<ISensorCollection> sensor_collection;
225 HRESULT hr = sensor_manager->GetSensorsByType(sensor_type,
226 sensor_collection.Receive());
227 if (FAILED(hr) || !sensor_collection)
228 return sensor;
229
230 ULONG count = 0;
231 hr = sensor_collection->GetCount(&count);
232 if (SUCCEEDED(hr) && count > 0)
233 sensor_collection->GetAt(0, sensor.Receive());
234 return sensor;
235 }
236
237 PlatformSensorReaderWin::PlatformSensorReaderWin(
238 base::win::ScopedComPtr<ISensor> sensor,
239 std::unique_ptr<ReaderInitParams> params)
240 : init_params_(std::move(params)),
241 task_runner_(base::ThreadTaskRunnerHandle::Get()),
242 sensor_active_(false),
243 client_(nullptr),
244 sensor_(sensor),
245 event_listener_(new EventListener(this)) {
246 DCHECK(init_params_);
247 DCHECK(!init_params_->reader_func.is_null());
248 DCHECK(sensor_);
249 }
250
251 void PlatformSensorReaderWin::SetClient(Client* client) {
252 base::AutoLock autolock(lock_);
253 // Can be null.
254 client_ = client;
255 }
256
257 void PlatformSensorReaderWin::StopSensor() {
258 base::AutoLock autolock(lock_);
259 if (sensor_active_) {
260 sensor_->SetEventSink(nullptr);
261 sensor_active_ = false;
262 }
263 }
264
265 PlatformSensorReaderWin::~PlatformSensorReaderWin() {
266 DCHECK(task_runner_->BelongsToCurrentThread());
267 }
268
269 bool PlatformSensorReaderWin::StartSensor(
270 const PlatformSensorConfiguration& configuration) {
271 base::AutoLock autolock(lock_);
272
273 if (!SetReportingInterval(configuration))
274 return false;
275
276 // Set event listener.
277 if (!sensor_active_) {
278 base::win::ScopedComPtr<ISensorEvents> sensor_events;
279 HRESULT hr = event_listener_->QueryInterface(__uuidof(ISensorEvents),
280 sensor_events.ReceiveVoid());
281
282 if (FAILED(hr) || !sensor_events)
283 return false;
284
285 if (FAILED(sensor_->SetEventSink(sensor_events.get())))
286 return false;
287
288 sensor_active_ = true;
289 }
290
291 return true;
292 }
293
294 bool PlatformSensorReaderWin::SetReportingInterval(
295 const PlatformSensorConfiguration& configuration) {
296 base::win::ScopedComPtr<IPortableDeviceValues> props;
297 if (SUCCEEDED(props.CreateInstance(CLSID_PortableDeviceValues))) {
298 unsigned interval =
299 (1 / configuration.frequency()) * base::Time::kMillisecondsPerSecond;
300
301 HRESULT hr = props->SetUnsignedIntegerValue(
302 SENSOR_PROPERTY_CURRENT_REPORT_INTERVAL, interval);
303
304 if (SUCCEEDED(hr)) {
305 base::win::ScopedComPtr<IPortableDeviceValues> return_props;
306 hr = sensor_->SetProperties(props.get(), return_props.Receive());
307 return SUCCEEDED(hr);
308 }
309 }
310 return false;
311 }
312
313 HRESULT PlatformSensorReaderWin::SensorReadingChanged(
314 ISensorDataReport& report,
315 SensorReading& reading) const {
316 if (!client_)
317 return E_FAIL;
318
319 HRESULT hr = init_params_->reader_func.Run(report, reading);
320 if (SUCCEEDED(hr))
321 client_->OnReadingUpdated(reading);
322 return hr;
323 }
324
325 void PlatformSensorReaderWin::SensorError() {
326 if (client_)
327 client_->OnSensorError();
328 }
329
330 unsigned long PlatformSensorReaderWin::GetMinimalReportingIntervalMs() const {
331 return init_params_->min_reporting_interval_ms;
332 }
333
334 mojom::ReportingMode PlatformSensorReaderWin::GetReportingMode() const {
335 return init_params_->reporting_mode;
336 }
337
338 } // 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