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

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 Reilly and Mikhail 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
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();
miu 2016/10/27 20:01:02 1. How precise a measurement do you need? When sam
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();
miu 2016/10/27 20:01:01 1. Semantically, it seems the parentheses are in t
171
172 return platform_sensor_reader_->SensorReadingChanged(*report, reading);
173 }
174
175 private:
176 PlatformSensorReaderWin* platform_sensor_reader_;
177
178 DISALLOW_COPY_AND_ASSIGN(EventListener);
179 };
180
181 // static
182 std::unique_ptr<PlatformSensorReaderWin> PlatformSensorReaderWin::Create(
183 mojom::SensorType type,
184 base::win::ScopedComPtr<ISensorManager> sensor_manager) {
185 DCHECK(sensor_manager);
186
187 auto params = CreateReaderInitParamsForSensor(type);
188 if (!params)
189 return nullptr;
190
191 auto sensor = GetSensorForType(params->sensor_type_id, sensor_manager);
192 if (!sensor)
193 return nullptr;
194
195 PROPVARIANT variant = {};
196 if (SUCCEEDED(
197 sensor->GetProperty(SENSOR_PROPERTY_MIN_REPORT_INTERVAL, &variant))) {
198 if (variant.vt == VT_UI4)
199 params->min_reporting_interval_ms = variant.ulVal;
200 }
201
202 GUID interests[] = {SENSOR_EVENT_STATE_CHANGED, SENSOR_EVENT_DATA_UPDATED};
203 HRESULT hr = sensor->SetEventInterest(interests, arraysize(interests));
204 if (FAILED(hr))
205 return nullptr;
206
207 return base::WrapUnique(
208 new PlatformSensorReaderWin(sensor, std::move(params)));
209 }
210
211 // static
212 base::win::ScopedComPtr<ISensor> PlatformSensorReaderWin::GetSensorForType(
213 REFSENSOR_TYPE_ID sensor_type,
214 base::win::ScopedComPtr<ISensorManager> sensor_manager) {
215 base::win::ScopedComPtr<ISensor> sensor;
216 base::win::ScopedComPtr<ISensorCollection> sensor_collection;
217 HRESULT hr = sensor_manager->GetSensorsByType(sensor_type,
218 sensor_collection.Receive());
219 if (FAILED(hr) || !sensor_collection)
220 return sensor;
221
222 ULONG count = 0;
223 hr = sensor_collection->GetCount(&count);
224 if (FAILED(hr) || count == 0)
225 return sensor;
226
227 sensor_collection->GetAt(0, sensor.Receive());
228 return sensor;
229 }
230
231 PlatformSensorReaderWin::PlatformSensorReaderWin(
232 base::win::ScopedComPtr<ISensor> sensor,
233 std::unique_ptr<ReaderInitParams> params)
234 : init_params_(std::move(params)),
235 task_runner_(base::ThreadTaskRunnerHandle::Get()),
236 sensor_active_(false),
237 client_(nullptr),
238 sensor_(sensor),
239 event_listener_(new EventListener(this)) {
240 DCHECK(init_params_);
241 DCHECK(!init_params_->reader_func.is_null());
242 DCHECK(sensor_);
243 }
244
245 void PlatformSensorReaderWin::SetClient(Client* client) {
246 base::AutoLock autolock(lock_);
247 // Can be null.
248 client_ = client;
249 }
250
251 void PlatformSensorReaderWin::StopSensor() {
252 base::AutoLock autolock(lock_);
253 if (sensor_active_) {
254 sensor_->SetEventSink(nullptr);
255 sensor_active_ = false;
256 }
257 }
258
259 PlatformSensorReaderWin::~PlatformSensorReaderWin() {
260 DCHECK(task_runner_->BelongsToCurrentThread());
261 }
262
263 bool PlatformSensorReaderWin::StartSensor(
264 const PlatformSensorConfiguration& configuration) {
265 base::AutoLock autolock(lock_);
266
267 if (!SetReportingInterval(configuration))
268 return false;
269
270 // Set event listener.
271 if (!sensor_active_) {
272 base::win::ScopedComPtr<ISensorEvents> sensor_events;
273 HRESULT hr = event_listener_->QueryInterface(__uuidof(ISensorEvents),
274 sensor_events.ReceiveVoid());
275
276 if (FAILED(hr) || !sensor_events)
277 return false;
278
279 if (FAILED(sensor_->SetEventSink(sensor_events.get())))
280 return false;
281
282 sensor_active_ = true;
283 }
284
285 return true;
286 }
287
288 bool PlatformSensorReaderWin::SetReportingInterval(
289 const PlatformSensorConfiguration& configuration) {
290 base::win::ScopedComPtr<IPortableDeviceValues> props;
291 if (SUCCEEDED(props.CreateInstance(CLSID_PortableDeviceValues))) {
292 unsigned interval =
293 (1 / configuration.frequency()) * base::Time::kMillisecondsPerSecond;
294 if (SUCCEEDED(props->SetUnsignedIntegerValue(
295 SENSOR_PROPERTY_CURRENT_REPORT_INTERVAL, interval))) {
296 base::win::ScopedComPtr<IPortableDeviceValues> return_props;
297 sensor_->SetProperties(props.get(), return_props.Receive());
298 return true;
299 }
300 }
301 return false;
302 }
303
304 HRESULT PlatformSensorReaderWin::SensorReadingChanged(
305 ISensorDataReport& report,
306 SensorReading& reading) const {
307 if (!client_)
308 return E_FAIL;
309
310 HRESULT hr = init_params_->reader_func.Run(report, reading);
311 if (SUCCEEDED(hr))
312 client_->OnReadingUpdated(reading);
313 return hr;
314 }
315
316 void PlatformSensorReaderWin::SensorError() {
317 if (client_)
318 client_->OnSensorError();
319 }
320
321 unsigned long PlatformSensorReaderWin::GetMinimalReportingIntervalMs() const {
322 return init_params_->min_reporting_interval_ms;
323 }
324
325 mojom::ReportingMode PlatformSensorReaderWin::GetReportingMode() const {
326 return init_params_->reporting_mode;
327 }
328
329 } // 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