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

Unified 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 side-by-side diff with in-line comments
Download patch
« 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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: device/generic_sensor/platform_sensor_reader_win.cc
diff --git a/device/generic_sensor/platform_sensor_reader_win.cc b/device/generic_sensor/platform_sensor_reader_win.cc
new file mode 100644
index 0000000000000000000000000000000000000000..7f292b1fb2a197de00216dad2075d5a865c44c2b
--- /dev/null
+++ b/device/generic_sensor/platform_sensor_reader_win.cc
@@ -0,0 +1,338 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/generic_sensor/platform_sensor_reader_win.h"
+
+#include <Sensors.h>
+
+#include "base/callback.h"
+#include "base/time/time.h"
+#include "base/win/iunknown_impl.h"
+#include "device/generic_sensor/public/cpp/platform_sensor_configuration.h"
+#include "device/generic_sensor/public/cpp/sensor_reading.h"
+
+namespace device {
+
+// Init params for the PlatformSensorReaderWin.
+struct ReaderInitParams {
+ // ISensorDataReport::GetSensorValue is not const, therefore, report
+ // cannot be passed as const ref.
+ // ISensorDataReport& report - report that contains new sensor data.
+ // SensorReading& reading - out parameter that must be populated.
+ // Returns HRESULT - S_OK on success, otherwise error code.
+ using ReaderFunctor = base::Callback<HRESULT(ISensorDataReport& report,
+ SensorReading& reading)>;
+ SENSOR_TYPE_ID sensor_type_id;
+ mojom::ReportingMode reporting_mode;
+ ReaderFunctor reader_func;
+ unsigned long min_reporting_interval_ms = 0;
+};
+
+namespace {
+
+// Gets value from the report for provided key.
+bool GetReadingValueForProperty(REFPROPERTYKEY key,
+ ISensorDataReport& report,
+ double* value) {
+ DCHECK(value);
+ PROPVARIANT variant_value = {};
+ if (SUCCEEDED(report.GetSensorValue(key, &variant_value))) {
+ if (variant_value.vt == VT_R8)
+ *value = variant_value.dblVal;
+ else if (variant_value.vt == VT_R4)
+ *value = variant_value.fltVal;
+ else
+ return false;
+ return true;
+ }
+
+ *value = 0;
+ return false;
+}
+
+// Creates ReaderInitParams params structure. To implement support for new
+// sensor types, new switch case should be added and appropriate fields must
+// be set:
+// sensor_type_id - GUID of the sensor supported by Windows.
+// reporting_mode - mode of reporting (ON_CHANGE | CONTINUOUS).
+// reader_func - Functor that is responsible to populate SensorReading from
+// ISensorDataReport data.
+std::unique_ptr<ReaderInitParams> CreateReaderInitParamsForSensor(
+ mojom::SensorType type) {
+ auto params = std::make_unique<ReaderInitParams>();
+ switch (type) {
+ case mojom::SensorType::AMBIENT_LIGHT: {
+ params->sensor_type_id = SENSOR_TYPE_AMBIENT_LIGHT;
+ params->reporting_mode = mojom::ReportingMode::ON_CHANGE;
+ params->reader_func =
+ base::Bind([](ISensorDataReport& report, SensorReading& reading) {
+ double lux = 0.0;
+ if (!GetReadingValueForProperty(SENSOR_DATA_TYPE_LIGHT_LEVEL_LUX,
+ report, &lux)) {
+ return E_FAIL;
+ }
+ reading.values[0] = lux;
+ return S_OK;
+ });
+ return params;
+ }
+ default:
+ NOTIMPLEMENTED();
+ return nullptr;
+ }
+}
+
+} // namespace
+
+// Class that implements ISensorEvents and IUnknown interfaces and used
+// by ISensor interface to dispatch state and data change events.
+class EventListener : public ISensorEvents, public base::win::IUnknownImpl {
+ public:
+ explicit EventListener(PlatformSensorReaderWin* platform_sensor_reader)
+ : platform_sensor_reader_(platform_sensor_reader) {
+ DCHECK(platform_sensor_reader_);
+ }
+
+ // IUnknown interface
+ ULONG STDMETHODCALLTYPE AddRef() override { return IUnknownImpl::AddRef(); }
+ ULONG STDMETHODCALLTYPE Release() override { return IUnknownImpl::Release(); }
+
+ STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override {
+ if (riid == __uuidof(ISensorEvents)) {
+ *ppv = static_cast<ISensorEvents*>(this);
+ AddRef();
+ return S_OK;
+ }
+ return IUnknownImpl::QueryInterface(riid, ppv);
+ }
+
+ protected:
+ ~EventListener() override = default;
+
+ // ISensorEvents interface
+ STDMETHODIMP OnEvent(ISensor*, REFGUID, IPortableDeviceValues*) override {
+ return S_OK;
+ }
+
+ STDMETHODIMP OnLeave(REFSENSOR_ID sensor_id) override {
+ // If event listener is active and sensor is disconnected, notify client
+ // about the error.
+ platform_sensor_reader_->SensorError();
+ platform_sensor_reader_->StopSensor();
+ return S_OK;
+ }
+
+ STDMETHODIMP OnStateChanged(ISensor* sensor, SensorState state) override {
+ if (sensor == nullptr)
+ return E_INVALIDARG;
+
+ if (state != SensorState::SENSOR_STATE_READY &&
+ state != SensorState::SENSOR_STATE_INITIALIZING) {
+ platform_sensor_reader_->SensorError();
+ platform_sensor_reader_->StopSensor();
+ }
+ return S_OK;
+ }
+
+ STDMETHODIMP OnDataUpdated(ISensor* sensor,
+ ISensorDataReport* report) override {
+ if (sensor == nullptr || report == nullptr)
+ return E_INVALIDARG;
+
+ // To get precise timestamp, we need to get delta between timestamp
+ // provided in the report and current system time. Then the delta in
+ // milliseconds is substracted from current high resolution timestamp.
+ SYSTEMTIME report_time;
+ HRESULT hr = report->GetTimestamp(&report_time);
+ if (FAILED(hr))
+ return hr;
+
+ base::TimeTicks ticks_now = base::TimeTicks::Now();
+ base::Time time_now = base::Time::NowFromSystemTime();
+
+ base::Time::Exploded exploded;
+ exploded.year = report_time.wYear;
+ exploded.month = report_time.wMonth;
+ exploded.day_of_week = report_time.wDayOfWeek;
+ exploded.day_of_month = report_time.wDay;
+ exploded.hour = report_time.wHour;
+ exploded.minute = report_time.wMinute;
+ exploded.second = report_time.wSecond;
+ exploded.millisecond = report_time.wMilliseconds;
+
+ base::Time timestamp;
+ if (!base::Time::FromUTCExploded(exploded, &timestamp))
+ return E_FAIL;
+
+ base::TimeDelta delta = time_now - timestamp;
+
+ SensorReading reading;
+ reading.timestamp = ((ticks_now - delta) - base::TimeTicks()).InSecondsF();
+
+ // Discard update events that have non-monotonically increasing timestamp.
+ if (last_sensor_reading_.timestamp > reading.timestamp)
+ return E_FAIL;
+
+ hr = platform_sensor_reader_->SensorReadingChanged(*report, reading);
+ if (SUCCEEDED(hr))
+ last_sensor_reading_ = reading;
+ return hr;
+ }
+
+ private:
+ PlatformSensorReaderWin* const platform_sensor_reader_;
+ SensorReading last_sensor_reading_;
+
+ DISALLOW_COPY_AND_ASSIGN(EventListener);
+};
+
+// static
+std::unique_ptr<PlatformSensorReaderWin> PlatformSensorReaderWin::Create(
+ mojom::SensorType type,
+ base::win::ScopedComPtr<ISensorManager> sensor_manager) {
+ DCHECK(sensor_manager);
+
+ auto params = CreateReaderInitParamsForSensor(type);
+ if (!params)
+ return nullptr;
+
+ auto sensor = GetSensorForType(params->sensor_type_id, sensor_manager);
+ if (!sensor)
+ return nullptr;
+
+ PROPVARIANT variant = {};
+ HRESULT hr =
+ sensor->GetProperty(SENSOR_PROPERTY_MIN_REPORT_INTERVAL, &variant);
+ if (SUCCEEDED(hr) && variant.vt == VT_UI4)
+ params->min_reporting_interval_ms = variant.ulVal;
+
+ GUID interests[] = {SENSOR_EVENT_STATE_CHANGED, SENSOR_EVENT_DATA_UPDATED};
+ hr = sensor->SetEventInterest(interests, arraysize(interests));
+ if (FAILED(hr))
+ return nullptr;
+
+ return base::WrapUnique(
+ new PlatformSensorReaderWin(sensor, std::move(params)));
+}
+
+// static
+base::win::ScopedComPtr<ISensor> PlatformSensorReaderWin::GetSensorForType(
+ REFSENSOR_TYPE_ID sensor_type,
+ base::win::ScopedComPtr<ISensorManager> sensor_manager) {
+ base::win::ScopedComPtr<ISensor> sensor;
+ base::win::ScopedComPtr<ISensorCollection> sensor_collection;
+ HRESULT hr = sensor_manager->GetSensorsByType(sensor_type,
+ sensor_collection.Receive());
+ if (FAILED(hr) || !sensor_collection)
+ return sensor;
+
+ ULONG count = 0;
+ hr = sensor_collection->GetCount(&count);
+ if (SUCCEEDED(hr) && count > 0)
+ sensor_collection->GetAt(0, sensor.Receive());
+ return sensor;
+}
+
+PlatformSensorReaderWin::PlatformSensorReaderWin(
+ base::win::ScopedComPtr<ISensor> sensor,
+ std::unique_ptr<ReaderInitParams> params)
+ : init_params_(std::move(params)),
+ task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ sensor_active_(false),
+ client_(nullptr),
+ sensor_(sensor),
+ event_listener_(new EventListener(this)) {
+ DCHECK(init_params_);
+ DCHECK(!init_params_->reader_func.is_null());
+ DCHECK(sensor_);
+}
+
+void PlatformSensorReaderWin::SetClient(Client* client) {
+ base::AutoLock autolock(lock_);
+ // Can be null.
+ client_ = client;
+}
+
+void PlatformSensorReaderWin::StopSensor() {
+ base::AutoLock autolock(lock_);
+ if (sensor_active_) {
+ sensor_->SetEventSink(nullptr);
+ sensor_active_ = false;
+ }
+}
+
+PlatformSensorReaderWin::~PlatformSensorReaderWin() {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+}
+
+bool PlatformSensorReaderWin::StartSensor(
+ const PlatformSensorConfiguration& configuration) {
+ base::AutoLock autolock(lock_);
+
+ if (!SetReportingInterval(configuration))
+ return false;
+
+ // Set event listener.
+ if (!sensor_active_) {
+ base::win::ScopedComPtr<ISensorEvents> sensor_events;
+ HRESULT hr = event_listener_->QueryInterface(__uuidof(ISensorEvents),
+ sensor_events.ReceiveVoid());
+
+ if (FAILED(hr) || !sensor_events)
+ return false;
+
+ if (FAILED(sensor_->SetEventSink(sensor_events.get())))
+ return false;
+
+ sensor_active_ = true;
+ }
+
+ return true;
+}
+
+bool PlatformSensorReaderWin::SetReportingInterval(
+ const PlatformSensorConfiguration& configuration) {
+ base::win::ScopedComPtr<IPortableDeviceValues> props;
+ if (SUCCEEDED(props.CreateInstance(CLSID_PortableDeviceValues))) {
+ unsigned interval =
+ (1 / configuration.frequency()) * base::Time::kMillisecondsPerSecond;
+
+ HRESULT hr = props->SetUnsignedIntegerValue(
+ SENSOR_PROPERTY_CURRENT_REPORT_INTERVAL, interval);
+
+ if (SUCCEEDED(hr)) {
+ base::win::ScopedComPtr<IPortableDeviceValues> return_props;
+ hr = sensor_->SetProperties(props.get(), return_props.Receive());
+ return SUCCEEDED(hr);
+ }
+ }
+ return false;
+}
+
+HRESULT PlatformSensorReaderWin::SensorReadingChanged(
+ ISensorDataReport& report,
+ SensorReading& reading) const {
+ if (!client_)
+ return E_FAIL;
+
+ HRESULT hr = init_params_->reader_func.Run(report, reading);
+ if (SUCCEEDED(hr))
+ client_->OnReadingUpdated(reading);
+ return hr;
+}
+
+void PlatformSensorReaderWin::SensorError() {
+ if (client_)
+ client_->OnSensorError();
+}
+
+unsigned long PlatformSensorReaderWin::GetMinimalReportingIntervalMs() const {
+ return init_params_->min_reporting_interval_ms;
+}
+
+mojom::ReportingMode PlatformSensorReaderWin::GetReportingMode() const {
+ return init_params_->reporting_mode;
+}
+
+} // namespace device
« 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