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

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

Powered by Google App Engine
This is Rietveld 408576698