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

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: Modify timestamp calculation as proposed by miu@ 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 } // namespace
Lei Zhang 2016/10/29 05:10:42 nit: blank line before
shalamov 2016/10/31 13:12:58 Done.
86
87 // Class that implements ISensorEvents and IUnknown interfaces and used
88 // by ISensor interface to dispatch state and data change events.
89 class EventListener : public ISensorEvents, public base::win::IUnknownImpl {
90 public:
91 explicit EventListener(PlatformSensorReaderWin* platform_sensor_reader)
92 : platform_sensor_reader_(platform_sensor_reader) {
93 DCHECK(platform_sensor_reader_);
94 }
95
96 // IUnknown interface
97 ULONG STDMETHODCALLTYPE AddRef() override { return IUnknownImpl::AddRef(); }
98 ULONG STDMETHODCALLTYPE Release() override { return IUnknownImpl::Release(); }
99
100 STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override {
101 if (riid == __uuidof(ISensorEvents)) {
102 *ppv = static_cast<ISensorEvents*>(this);
103 AddRef();
104 return S_OK;
105 }
106 return IUnknownImpl::QueryInterface(riid, ppv);
107 }
108
109 protected:
110 ~EventListener() override = default;
111
112 // ISensorEvents interface
113 STDMETHODIMP OnEvent(ISensor*, REFGUID, IPortableDeviceValues*) override {
114 return S_OK;
115 }
116
117 STDMETHODIMP OnLeave(REFSENSOR_ID sensor_id) override {
118 // If event listener is active and sensor is disconnected, notify client
119 // about the error.
120 platform_sensor_reader_->SensorError();
121 platform_sensor_reader_->StopSensor();
122 return S_OK;
123 }
124
125 STDMETHODIMP OnStateChanged(ISensor* sensor, SensorState state) override {
126 if (sensor == nullptr)
127 return E_INVALIDARG;
128
129 if (state != SensorState::SENSOR_STATE_READY &&
130 state != SensorState::SENSOR_STATE_INITIALIZING) {
131 platform_sensor_reader_->SensorError();
132 platform_sensor_reader_->StopSensor();
133 }
134 return S_OK;
135 }
136
137 STDMETHODIMP OnDataUpdated(ISensor* sensor,
138 ISensorDataReport* report) override {
139 if (sensor == nullptr || report == nullptr)
140 return E_INVALIDARG;
141
142 // To get precise timestamp, we need to get delta between timestamp
143 // provided in the report and current system time. Then the delta in
144 // milliseconds is substracted from current high resolution timestamp.
145 SYSTEMTIME report_time;
146 HRESULT hr = report->GetTimestamp(&report_time);
147 if (FAILED(hr))
148 return hr;
149
150 base::TimeTicks ticks_now = base::TimeTicks::Now();
151 base::Time time_now = base::Time::NowFromSystemTime();
152
153 base::Time::Exploded exploded;
154 exploded.year = report_time.wYear;
155 exploded.month = report_time.wMonth;
156 exploded.day_of_week = report_time.wDayOfWeek;
157 exploded.day_of_month = report_time.wDay;
158 exploded.hour = report_time.wHour;
159 exploded.minute = report_time.wMinute;
160 exploded.second = report_time.wSecond;
161 exploded.millisecond = report_time.wMilliseconds;
162
163 base::Time timestamp;
164 if (!base::Time::FromUTCExploded(exploded, &timestamp))
165 return E_FAIL;
166
167 base::TimeDelta delta = time_now - timestamp;
168
169 SensorReading reading;
170 reading.timestamp = ((ticks_now - delta) - base::TimeTicks()).InSecondsF();
171
172 // Discard update events that have non-monotonically increasing timestamp.
173 if (last_sensor_reading_.timestamp > reading.timestamp)
174 return E_FAIL;
175
176 hr = platform_sensor_reader_->SensorReadingChanged(*report, reading);
177 if (SUCCEEDED(hr))
178 last_sensor_reading_ = reading;
179 return hr;
180 }
181
182 private:
183 PlatformSensorReaderWin* platform_sensor_reader_;
Lei Zhang 2016/10/29 05:10:42 You can do: PlatformSensorReaderWin* const platfor
shalamov 2016/10/31 13:12:58 Done.
184 SensorReading last_sensor_reading_;
185
186 DISALLOW_COPY_AND_ASSIGN(EventListener);
187 };
188
189 // static
190 std::unique_ptr<PlatformSensorReaderWin> PlatformSensorReaderWin::Create(
191 mojom::SensorType type,
192 base::win::ScopedComPtr<ISensorManager> sensor_manager) {
193 DCHECK(sensor_manager);
194
195 auto params = CreateReaderInitParamsForSensor(type);
196 if (!params)
197 return nullptr;
198
199 auto sensor = GetSensorForType(params->sensor_type_id, sensor_manager);
200 if (!sensor)
201 return nullptr;
202
203 PROPVARIANT variant = {};
204 if (SUCCEEDED(
205 sensor->GetProperty(SENSOR_PROPERTY_MIN_REPORT_INTERVAL, &variant))) {
206 if (variant.vt == VT_UI4)
207 params->min_reporting_interval_ms = variant.ulVal;
208 }
209
210 GUID interests[] = {SENSOR_EVENT_STATE_CHANGED, SENSOR_EVENT_DATA_UPDATED};
211 HRESULT hr = sensor->SetEventInterest(interests, arraysize(interests));
212 if (FAILED(hr))
213 return nullptr;
214
215 return base::WrapUnique(
Lei Zhang 2016/10/29 05:10:42 Can this be base::MakeUnique()?
shalamov 2016/10/31 13:12:58 Constructor is private, can't use base::MakeUnique
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 (FAILED(hr) || count == 0)
Lei Zhang 2016/10/29 05:10:42 Since you return |sensor| either way here: if (SU
shalamov 2016/10/31 13:12:57 Done.
233 return sensor;
234
235 sensor_collection->GetAt(0, sensor.Receive());
236 return sensor;
237 }
238
239 PlatformSensorReaderWin::PlatformSensorReaderWin(
240 base::win::ScopedComPtr<ISensor> sensor,
241 std::unique_ptr<ReaderInitParams> params)
242 : init_params_(std::move(params)),
243 task_runner_(base::ThreadTaskRunnerHandle::Get()),
244 sensor_active_(false),
245 client_(nullptr),
246 sensor_(sensor),
247 event_listener_(new EventListener(this)) {
248 DCHECK(init_params_);
249 DCHECK(!init_params_->reader_func.is_null());
250 DCHECK(sensor_);
251 }
252
253 void PlatformSensorReaderWin::SetClient(Client* client) {
254 base::AutoLock autolock(lock_);
255 // Can be null.
256 client_ = client;
257 }
258
259 void PlatformSensorReaderWin::StopSensor() {
260 base::AutoLock autolock(lock_);
261 if (sensor_active_) {
262 sensor_->SetEventSink(nullptr);
263 sensor_active_ = false;
264 }
265 }
266
267 PlatformSensorReaderWin::~PlatformSensorReaderWin() {
268 DCHECK(task_runner_->BelongsToCurrentThread());
269 }
270
271 bool PlatformSensorReaderWin::StartSensor(
272 const PlatformSensorConfiguration& configuration) {
273 base::AutoLock autolock(lock_);
274
275 if (!SetReportingInterval(configuration))
276 return false;
277
278 // Set event listener.
279 if (!sensor_active_) {
280 base::win::ScopedComPtr<ISensorEvents> sensor_events;
281 HRESULT hr = event_listener_->QueryInterface(__uuidof(ISensorEvents),
282 sensor_events.ReceiveVoid());
283
284 if (FAILED(hr) || !sensor_events)
285 return false;
286
287 if (FAILED(sensor_->SetEventSink(sensor_events.get())))
288 return false;
289
290 sensor_active_ = true;
291 }
292
293 return true;
294 }
295
296 bool PlatformSensorReaderWin::SetReportingInterval(
297 const PlatformSensorConfiguration& configuration) {
298 base::win::ScopedComPtr<IPortableDeviceValues> props;
299 if (SUCCEEDED(props.CreateInstance(CLSID_PortableDeviceValues))) {
300 unsigned interval =
301 (1 / configuration.frequency()) * base::Time::kMillisecondsPerSecond;
302 if (SUCCEEDED(props->SetUnsignedIntegerValue(
303 SENSOR_PROPERTY_CURRENT_REPORT_INTERVAL, interval))) {
304 base::win::ScopedComPtr<IPortableDeviceValues> return_props;
305 sensor_->SetProperties(props.get(), return_props.Receive());
306 return true;
307 }
308 }
309 return false;
310 }
311
312 HRESULT PlatformSensorReaderWin::SensorReadingChanged(
313 ISensorDataReport& report,
314 SensorReading& reading) const {
315 if (!client_)
316 return E_FAIL;
317
318 HRESULT hr = init_params_->reader_func.Run(report, reading);
319 if (SUCCEEDED(hr))
320 client_->OnReadingUpdated(reading);
321 return hr;
322 }
323
324 void PlatformSensorReaderWin::SensorError() {
325 if (client_)
326 client_->OnSensorError();
327 }
328
329 unsigned long PlatformSensorReaderWin::GetMinimalReportingIntervalMs() const {
330 return init_params_->min_reporting_interval_ms;
331 }
332
333 mojom::ReportingMode PlatformSensorReaderWin::GetReportingMode() const {
334 return init_params_->reporting_mode;
335 }
336
337 } // namespace device
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698