Commit 061d113d authored by maksim.sisov's avatar maksim.sisov Committed by Commit bot

[sensors](CrOS/Linux) Implement Sensor device manager for sensors

This cl introduces a SensorDeviceManager for Linux and ChromeOS platforms.

Manager:
1) PlatformSensorProviderLinux owns a SensorDeviceManager that uses
DeviceMonitorLinux to enumerate iio devices and get removed/add udev
events. Once device is enumerated, added or removed, it is identified
and all the necessary information is put to SensorInfoLinux structure
and passed to the provider. If there is no such a device, it is added
to cache. In case of removal, manager checks if there was such a device
and updates it's cache accordingly + notifies the provider about a
removed device, which update own cache.
2) Requests: when a request for a sensor comes, it can be processed
immediately or asynchronously once service is up and running.

Reader:
1) There will be two strategies for a reader. At the moment
only polling read is supported.
2) The reader doesn't search for sensor files any more, those are passed
to it in SensorInfoLinux structure.

Unittests:
1) In order to make it possible to test the whole path, I've made
SensorDeviceManager's methods virtual, which allowed me to
mock and override them.
2) Unittests implement own udev methods that just read values from
files. If read is successful, the manager adds this type of sensor
associated with the files that have been read to it's cache and notifies
the provider.

BUG=606766

Review-Url: https://codereview.chromium.org/2533793002
Cr-Commit-Position: refs/heads/master@{#437550}
parent b0246be6
......@@ -108,8 +108,9 @@ test("device_unittests") {
deps += [ "//dbus:test_support" ]
}
if (is_linux) {
sources += [ "generic_sensor/linux/sensor_reader_unittest.cc" ]
if (!is_linux_without_udev) {
sources +=
[ "generic_sensor/platform_sensor_and_provider_unittest_linux.cc" ]
}
# HID and Serial:
......
......@@ -12,8 +12,6 @@ component("generic_sensor") {
output_name = "generic_sensor"
sources = [
"generic_sensor_consts.h",
"linux/platform_sensor_utils_linux.cc",
"linux/platform_sensor_utils_linux.h",
"linux/sensor_data_linux.cc",
"linux/sensor_data_linux.h",
"platform_sensor.cc",
......@@ -30,12 +28,12 @@ component("generic_sensor") {
"platform_sensor_provider_android.h",
"platform_sensor_provider_base.cc",
"platform_sensor_provider_base.h",
"platform_sensor_provider_linux.cc",
"platform_sensor_provider_linux.h",
"platform_sensor_provider_mac.cc",
"platform_sensor_provider_mac.h",
"platform_sensor_provider_win.cc",
"platform_sensor_provider_win.h",
"platform_sensor_reader_linux.cc",
"platform_sensor_reader_linux.h",
"platform_sensor_reader_win.cc",
"platform_sensor_reader_win.h",
"platform_sensor_win.cc",
......@@ -67,12 +65,23 @@ component("generic_sensor") {
deps += [ ":jni_headers" ]
}
if (is_mac || is_linux) {
if (is_mac) {
deps += [ "//device/sensors/public/cpp" ]
libs = [ "IOKit.framework" ]
}
if (is_mac) {
libs = [ "IOKit.framework" ]
if (use_udev) {
deps += [
"//device/base",
"//device/udev_linux",
]
sources += [
"linux/platform_sensor_manager.cc",
"linux/platform_sensor_manager.h",
"platform_sensor_provider_linux.cc",
"platform_sensor_provider_linux.h",
]
}
if (is_win) {
......
// 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/linux/platform_sensor_manager.h"
#include "base/strings/string_number_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "device/generic_sensor/linux/sensor_data_linux.h"
namespace device {
namespace {
std::string StringOrEmptyIfNull(const char* value) {
return value ? value : std::string();
}
} // namespace
SensorDeviceManager::SensorDeviceManager()
: observer_(this),
delegate_(nullptr),
task_runner_(base::ThreadTaskRunnerHandle::Get()) {
thread_checker_.DetachFromThread();
}
SensorDeviceManager::~SensorDeviceManager() {
DCHECK(thread_checker_.CalledOnValidThread());
}
void SensorDeviceManager::Start(Delegate* delegate) {
DCHECK(thread_checker_.CalledOnValidThread());
base::ThreadRestrictions::AssertIOAllowed();
DCHECK(!delegate_);
delegate_ = delegate;
DeviceMonitorLinux* monitor = DeviceMonitorLinux::GetInstance();
observer_.Add(monitor);
monitor->Enumerate(
base::Bind(&SensorDeviceManager::OnDeviceAdded, base::Unretained(this)));
task_runner_->PostTask(
FROM_HERE,
base::Bind(&SensorDeviceManager::Delegate::OnSensorNodesEnumerated,
base::Unretained(delegate_)));
}
std::string SensorDeviceManager::GetUdevDeviceGetSubsystem(udev_device* dev) {
return StringOrEmptyIfNull(udev_device_get_subsystem(dev));
}
std::string SensorDeviceManager::GetUdevDeviceGetSyspath(udev_device* dev) {
return StringOrEmptyIfNull(udev_device_get_syspath(dev));
}
std::string SensorDeviceManager::GetUdevDeviceGetSysattrValue(
udev_device* dev,
const std::string& attribute) {
return StringOrEmptyIfNull(
udev_device_get_sysattr_value(dev, attribute.c_str()));
}
std::string SensorDeviceManager::GetUdevDeviceGetDevnode(udev_device* dev) {
return StringOrEmptyIfNull(udev_device_get_devnode(dev));
}
void SensorDeviceManager::OnDeviceAdded(udev_device* dev) {
const std::string subsystem = GetUdevDeviceGetSubsystem(dev);
if (subsystem.empty() || subsystem.compare("iio") != 0)
return;
const std::string sysfs_path = GetUdevDeviceGetSyspath(dev);
if (sysfs_path.empty())
return;
const std::string device_node = GetUdevDeviceGetDevnode(dev);
if (device_node.empty())
return;
const uint32_t first = static_cast<uint32_t>(mojom::SensorType::FIRST);
const uint32_t last = static_cast<uint32_t>(mojom::SensorType::LAST);
for (uint32_t i = first; i < last; ++i) {
SensorPathsLinux data;
mojom::SensorType type = static_cast<mojom::SensorType>(i);
if (!InitSensorData(type, &data))
continue;
std::vector<base::FilePath> sensor_file_names;
for (const std::vector<std::string>& names : data.sensor_file_names) {
for (const auto& name : names) {
const std::string value =
GetUdevDeviceGetSysattrValue(dev, name.c_str());
if (value.empty())
continue;
base::FilePath full_path = base::FilePath(sysfs_path).Append(name);
sensor_file_names.push_back(full_path);
break;
}
}
if (sensor_file_names.empty())
continue;
const std::string scaling_value =
GetUdevDeviceGetSysattrValue(dev, data.sensor_scale_name.c_str());
// If scaling value is not found, treat it as 1.
double sensor_scaling_value = 1;
if (!scaling_value.empty())
base::StringToDouble(scaling_value, &sensor_scaling_value);
const std::string offset_vallue =
GetUdevDeviceGetSysattrValue(dev, data.sensor_offset_file_name.c_str());
// If offset value is not found, treat it as 0.
double sensor_offset_value = 0;
if (!offset_vallue.empty())
base::StringToDouble(offset_vallue, &sensor_offset_value);
const std::string frequency_value = GetUdevDeviceGetSysattrValue(
dev, data.sensor_frequency_file_name.c_str());
// If frequency is not found, use default one from SensorPathsLinux struct.
double sensor_frequency_value = data.default_configuration.frequency();
// By default, |reporting_mode| is ON_CHANGE. But if platform provides
// sampling frequency, the reporting mode is CONTINUOUS.
mojom::ReportingMode reporting_mode = mojom::ReportingMode::ON_CHANGE;
if (!frequency_value.empty()) {
base::StringToDouble(frequency_value, &sensor_frequency_value);
reporting_mode = mojom::ReportingMode::CONTINUOUS;
}
// Update own cache of known sensor devices.
if (!base::ContainsKey(sensors_by_node_, device_node))
sensors_by_node_[device_node] = data.type;
std::unique_ptr<SensorInfoLinux> device(new SensorInfoLinux(
device_node, sensor_frequency_value, sensor_scaling_value,
sensor_offset_value, reporting_mode, data.apply_scaling_func,
std::move(sensor_file_names)));
task_runner_->PostTask(
FROM_HERE, base::Bind(&SensorDeviceManager::Delegate::OnDeviceAdded,
base::Unretained(delegate_), data.type,
base::Passed(&device)));
// One |dev| can represent more than one sensor.
// For example, there is an accelerometer and gyroscope represented by one
// |dev| in Chrome OS, kernel < 3.18. Thus, iterate through all possible
// types of sensors.
}
}
void SensorDeviceManager::OnDeviceRemoved(udev_device* dev) {
const std::string subsystem = GetUdevDeviceGetSubsystem(dev);
if (subsystem.empty() || subsystem.compare("iio") != 0)
return;
const std::string device_node = GetUdevDeviceGetDevnode(dev);
if (device_node.empty())
return;
auto sensor = sensors_by_node_.find(device_node);
if (sensor == sensors_by_node_.end())
return;
mojom::SensorType type = sensor->second;
sensors_by_node_.erase(sensor);
task_runner_->PostTask(
FROM_HERE, base::Bind(&SensorDeviceManager::Delegate::OnDeviceRemoved,
base::Unretained(delegate_), type, device_node));
}
} // namespace device
// 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.
#ifndef DEVICE_GENERIC_SENSOR_LINUX_PLATFORM_SENSOR_MANAGER_H_
#define DEVICE_GENERIC_SENSOR_LINUX_PLATFORM_SENSOR_MANAGER_H_
#include "base/scoped_observer.h"
#include "device/base/device_monitor_linux.h"
#include "device/generic_sensor/public/interfaces/sensor.mojom.h"
namespace device {
struct SensorInfoLinux;
// This SensorDeviceManager uses LinuxDeviceMonitor to enumerate devices
// and listen to "add/removed" events to notify |provider_| about
// added or removed iio devices. It has own cache to speed up an identification
// process of removed devices.
class DEVICE_GENERIC_SENSOR_EXPORT SensorDeviceManager
: public DeviceMonitorLinux::Observer {
public:
class Delegate {
public:
// Called when SensorDeviceManager has enumerated through all possible
// iio udev devices.
virtual void OnSensorNodesEnumerated() = 0;
// Called after SensorDeviceManager has identified a udev device, which
// belongs to "iio" subsystem.
virtual void OnDeviceAdded(mojom::SensorType type,
std::unique_ptr<SensorInfoLinux> sensor) = 0;
// Called after "removed" event is received from LinuxDeviceMonitor and
// sensor is identified as known.
virtual void OnDeviceRemoved(mojom::SensorType type,
const std::string& device_node) = 0;
protected:
virtual ~Delegate() {}
};
SensorDeviceManager();
~SensorDeviceManager() override;
// Starts this service.
virtual void Start(Delegate* delegate);
protected:
using SensorDeviceMap = std::unordered_map<std::string, mojom::SensorType>;
// Wrappers around udev system methods that can be implemented differently
// by tests.
virtual std::string GetUdevDeviceGetSubsystem(udev_device* dev);
virtual std::string GetUdevDeviceGetSyspath(udev_device* dev);
virtual std::string GetUdevDeviceGetSysattrValue(
udev_device* dev,
const std::string& attribute);
virtual std::string GetUdevDeviceGetDevnode(udev_device* dev);
// DeviceMonitorLinux::Observer:
void OnDeviceAdded(udev_device* udev_device) override;
void OnDeviceRemoved(udev_device* device) override;
// Represents a map of sensors that are already known to this manager after
// initial enumeration.
SensorDeviceMap sensors_by_node_;
base::ThreadChecker thread_checker_;
ScopedObserver<DeviceMonitorLinux, DeviceMonitorLinux::Observer> observer_;
Delegate* delegate_;
// A task runner, which |delegate_| lives on.
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
DISALLOW_COPY_AND_ASSIGN(SensorDeviceManager);
};
} // namespace device
#endif // DEVICE_GENERIC_SENSOR_LINUX_PLATFORM_SENSOR_MANAGER_H_
// 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/linux/platform_sensor_utils_linux.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_restrictions.h"
#include "device/generic_sensor/public/cpp/sensor_reading.h"
namespace device {
namespace {
bool InitSensorPaths(const std::vector<std::string>& input_names,
const char* base_path,
std::vector<base::FilePath>* sensor_paths) {
// Search the iio/devices directory for a subdirectory (eg "device0" or
// "iio:device0") that contains the specified input_name file (eg
// "in_illuminance_input" or "in_illuminance0_input").
base::FileEnumerator dir_enumerator(base::FilePath(base_path), false,
base::FileEnumerator::DIRECTORIES);
for (base::FilePath check_path = dir_enumerator.Next(); !check_path.empty();
check_path = dir_enumerator.Next()) {
for (auto const& file_name : input_names) {
base::FilePath full_path = check_path.Append(file_name);
if (base::PathExists(full_path)) {
sensor_paths->push_back(full_path);
return true;
}
}
}
return false;
}
bool GetSensorFilePaths(const SensorDataLinux& data,
std::vector<base::FilePath>* sensor_paths) {
DCHECK(sensor_paths->empty());
// Depending on a sensor, there can be up to three sets of files that need
// to be checked. If one of three files is not found, a sensor is
// treated as a non-existing one.
for (auto const& file_names : data.sensor_file_names) {
// Supply InitSensorPaths() with a set of files.
// Only one file from each set should be found.
if (!InitSensorPaths(file_names, data.base_path_sensor_linux, sensor_paths))
return false;
}
return true;
}
// Returns -1 if unable to read a scaling value.
// Otherwise, returns a scaling value read from a file.
double ReadSensorScalingValue(const base::FilePath& scale_file_path) {
std::string value;
if (!base::ReadFileToString(scale_file_path, &value))
return -1;
double scaling_value;
base::TrimWhitespaceASCII(value, base::TRIM_ALL, &value);
if (!base::StringToDouble(value, &scaling_value))
return -1;
return scaling_value;
}
} // namespace
// static
std::unique_ptr<SensorReader> SensorReader::Create(
const SensorDataLinux& data) {
base::ThreadRestrictions::AssertIOAllowed();
std::vector<base::FilePath> sensor_paths;
if (!GetSensorFilePaths(data, &sensor_paths))
return nullptr;
DCHECK(!sensor_paths.empty());
// Scaling value is 1 if scaling file is not specified is |data| or scaling
// file is not found.
double scaling_value = 1;
if (!data.sensor_scale_name.empty()) {
const base::FilePath scale_file_path =
sensor_paths.back().DirName().Append(data.sensor_scale_name);
if (base::PathExists(scale_file_path))
scaling_value = ReadSensorScalingValue(scale_file_path);
}
// A file with a scaling value is found, but couldn't be read.
if (scaling_value == -1)
return nullptr;
return base::WrapUnique(new SensorReader(
std::move(sensor_paths), scaling_value, data.apply_scaling_func));
}
SensorReader::SensorReader(
std::vector<base::FilePath> sensor_paths,
double scaling_value,
const SensorDataLinux::ReaderFunctor& apply_scaling_func)
: sensor_paths_(std::move(sensor_paths)),
scaling_value_(scaling_value),
apply_scaling_func_(apply_scaling_func) {
DCHECK(!sensor_paths_.empty());
}
SensorReader::~SensorReader() = default;
bool SensorReader::ReadSensorReading(SensorReading* reading) {
base::ThreadRestrictions::AssertIOAllowed();
SensorReading readings;
DCHECK_LE(sensor_paths_.size(), arraysize(readings.values));
int i = 0;
for (const auto& path : sensor_paths_) {
std::string new_read_value;
if (!base::ReadFileToString(path, &new_read_value))
return false;
double new_value = 0;
base::TrimWhitespaceASCII(new_read_value, base::TRIM_ALL, &new_read_value);
if (!base::StringToDouble(new_read_value, &new_value))
return false;
readings.values[i++] = new_value;
}
if (!apply_scaling_func_.is_null())
apply_scaling_func_.Run(scaling_value_, readings);
*reading = readings;
return true;
}
} // namespace device
// 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.
#ifndef DEVICE_GENERIC_SENSOR_LINUX_PLATFORM_SENSOR_UTILS_LINUX_H_
#define DEVICE_GENERIC_SENSOR_LINUX_PLATFORM_SENSOR_UTILS_LINUX_H_
#include "base/files/file_path.h"
#include "base/memory/ptr_util.h"
#include "device/generic_sensor/generic_sensor_export.h"
#include "device/generic_sensor/linux/sensor_data_linux.h"
namespace device {
struct SensorDataLinux;
struct SensorReading;
// Generic reader class that reads sensors data from
// sensors files located in the base iio folder.
class DEVICE_GENERIC_SENSOR_EXPORT SensorReader {
public:
~SensorReader();
// Creates a new instance of SensorReader if sensor read files
// has been found and |sensor_paths_| are set.
static std::unique_ptr<SensorReader> Create(const SensorDataLinux& data);
// Reads sensor values into |*reading| from sensor files
// specified in |sensor_paths_|.
bool ReadSensorReading(SensorReading* reading);
private:
SensorReader(std::vector<base::FilePath> sensor_paths,
double scaling_value,
const SensorDataLinux::ReaderFunctor& apply_scaling_func);
// Contains paths to sensor files that are set when
// Create() is called.
const std::vector<base::FilePath> sensor_paths_;
// Scaling values that are applied to raw data from sensors.
const double scaling_value_;
// Used to apply scalings and invert signs if needed.
const SensorDataLinux::ReaderFunctor apply_scaling_func_;
DISALLOW_COPY_AND_ASSIGN(SensorReader);
};
} // namespace device
#endif // DEVICE_GENERIC_SENSOR_LINUX_PLATFORM_SENSOR_UTILS_LINUX_H_
......@@ -23,12 +23,11 @@ const char kChangedAxisKernelVersion[] = "3.18.0";
const base::FilePath::CharType* kSensorsBasePath =
FILE_PATH_LITERAL("/sys/bus/iio/devices");
void InitAmbientLightSensorData(SensorDataLinux* data) {
void InitAmbientLightSensorData(SensorPathsLinux* data) {
std::vector<std::string> file_names{
"in_illuminance0_input", "in_illuminance_input", "in_illuminance0_raw",
"in_illuminance_raw"};
data->sensor_file_names.push_back(std::move(file_names));
data->reporting_mode = mojom::ReportingMode::ON_CHANGE;
data->default_configuration =
PlatformSensorConfiguration(kDefaultAmbientLightFrequencyHz);
}
......@@ -41,7 +40,7 @@ void MaybeCheckKernelVersionAndAssignFileNames(
const std::vector<std::string>& file_names_x,
const std::vector<std::string>& file_names_y,
const std::vector<std::string>& file_names_z,
SensorDataLinux* data) {
SensorPathsLinux* data) {
#if defined(OS_CHROMEOS)
const base::Version checked_kernel_version(kChangedAxisKernelVersion);
DCHECK(checked_kernel_version.IsValid());
......@@ -62,7 +61,7 @@ void MaybeCheckKernelVersionAndAssignFileNames(
}
// TODO(maksims): add support for lid accelerometer on chromeos.
void InitAccelerometerSensorData(SensorDataLinux* data) {
void InitAccelerometerSensorData(SensorPathsLinux* data) {
std::vector<std::string> file_names_x{"in_accel_x_base_raw",
"in_accel_x_raw"};
std::vector<std::string> file_names_y{"in_accel_y_base_raw",
......@@ -72,32 +71,35 @@ void InitAccelerometerSensorData(SensorDataLinux* data) {
#if defined(OS_CHROMEOS)
data->sensor_scale_name = "in_accel_base_scale";
data->apply_scaling_func =
base::Bind([](double scaling_value, SensorReading& reading) {
double scaling = kMeanGravity / scaling_value;
data->sensor_frequency_file_name = "in_accel_base_sampling_frequency";
data->apply_scaling_func = base::Bind(
[](double scaling_value, double offset, SensorReading& reading) {
double scaling = (kMeanGravity / scaling_value) + offset;
reading.values[0] = scaling * reading.values[0];
reading.values[1] = scaling * reading.values[1];
reading.values[2] = scaling * reading.values[2];
});
#else
data->sensor_scale_name = "in_accel_scale";
data->apply_scaling_func =
base::Bind([](double scaling_value, SensorReading& reading) {
data->sensor_offset_file_name = "in_accel_offset";
data->sensor_frequency_file_name = "in_accel_sampling_frequency";
data->apply_scaling_func = base::Bind(
[](double scaling_value, double offset, SensorReading& reading) {
double scaling = scaling_value + offset;
// Adapt Linux reading values to generic sensor api specs.
reading.values[0] = -scaling_value * reading.values[0];
reading.values[1] = -scaling_value * reading.values[1];
reading.values[2] = -scaling_value * reading.values[2];
reading.values[0] = -scaling * reading.values[0];
reading.values[1] = -scaling * reading.values[1];
reading.values[2] = -scaling * reading.values[2];
});
#endif
MaybeCheckKernelVersionAndAssignFileNames(file_names_x, file_names_y,
file_names_z, data);
data->reporting_mode = mojom::ReportingMode::CONTINUOUS;
data->default_configuration =
PlatformSensorConfiguration(kDefaultAccelerometerFrequencyHz);
}
void InitGyroscopeSensorData(SensorDataLinux* data) {
void InitGyroscopeSensorData(SensorPathsLinux* data) {
std::vector<std::string> file_names_x{"in_anglvel_x_base_raw",
"in_anglvel_x_raw"};
std::vector<std::string> file_names_y{"in_anglvel_y_base_raw",
......@@ -106,10 +108,11 @@ void InitGyroscopeSensorData(SensorDataLinux* data) {
"in_anglvel_z_raw"};
#if defined(OS_CHROMEOS)
data->sensor_scale_name = "in_anglvel_base_scale";
data->apply_scaling_func =
base::Bind([](double scaling_value, SensorReading& reading) {
data->sensor_frequency_file_name = "in_anglvel_base_frequency";
data->apply_scaling_func = base::Bind(
[](double scaling_value, double offset, SensorReading& reading) {
double scaling =
kMeanGravity * kRadiansInDegreesPerSecond / scaling_value;
kMeanGravity * kRadiansInDegreesPerSecond / scaling_value + offset;
// Adapt CrOS reading values to generic sensor api specs.
reading.values[0] = -scaling * reading.values[0];
reading.values[1] = -scaling * reading.values[1];
......@@ -117,54 +120,60 @@ void InitGyroscopeSensorData(SensorDataLinux* data) {
});
#else
data->sensor_scale_name = "in_anglvel_scale";
data->apply_scaling_func =
base::Bind([](double scaling_value, SensorReading& reading) {
reading.values[0] = scaling_value * reading.values[0];
reading.values[1] = scaling_value * reading.values[1];
reading.values[2] = scaling_value * reading.values[2];
data->sensor_offset_file_name = "in_anglvel_offset";
data->sensor_frequency_file_name = "in_anglvel_sampling_frequency";
data->apply_scaling_func = base::Bind(
[](double scaling_value, double offset, SensorReading& reading) {
double scaling = scaling_value + offset;
reading.values[0] = scaling * reading.values[0];
reading.values[1] = scaling * reading.values[1];
reading.values[2] = scaling * reading.values[2];
});
#endif
MaybeCheckKernelVersionAndAssignFileNames(file_names_x, file_names_y,
file_names_z, data);
data->reporting_mode = mojom::ReportingMode::CONTINUOUS;
data->default_configuration =
PlatformSensorConfiguration(kDefaultGyroscopeFrequencyHz);
}
// TODO(maksims): Verify magnitometer works correctly on a chromebook when
// I get one with that sensor onboard.
void InitMagnitometerSensorData(SensorDataLinux* data) {
void InitMagnitometerSensorData(SensorPathsLinux* data) {
std::vector<std::string> file_names_x{"in_magn_x_raw"};
std::vector<std::string> file_names_y{"in_magn_y_raw"};
std::vector<std::string> file_names_z{"in_magn_z_raw"};
data->sensor_scale_name = "in_magn_scale";
data->apply_scaling_func = base::Bind([](double scaling_value,
SensorReading& reading) {
reading.values[0] = scaling_value * kMicroteslaInGauss * reading.values[0];
reading.values[1] = scaling_value * kMicroteslaInGauss * reading.values[1];
reading.values[2] = scaling_value * kMicroteslaInGauss * reading.values[2];
});
data->sensor_offset_file_name = "in_magn_offset";
data->sensor_frequency_file_name = "in_magn_sampling_frequency";
data->apply_scaling_func = base::Bind(
[](double scaling_value, double offset, SensorReading& reading) {
double scaling = scaling_value + offset;
reading.values[0] = scaling * kMicroteslaInGauss * reading.values[0];
reading.values[1] = scaling * kMicroteslaInGauss * reading.values[1];
reading.values[2] = scaling * kMicroteslaInGauss * reading.values[2];
});
MaybeCheckKernelVersionAndAssignFileNames(file_names_x, file_names_y,
file_names_z, data);
data->reporting_mode = mojom::ReportingMode::CONTINUOUS;
data->default_configuration =
PlatformSensorConfiguration(kDefaultMagnetometerFrequencyHz);
}
} // namespace
SensorDataLinux::SensorDataLinux() : base_path_sensor_linux(kSensorsBasePath) {}
SensorPathsLinux::SensorPathsLinux()
: base_path_sensor_linux(kSensorsBasePath) {}
SensorDataLinux::~SensorDataLinux() = default;
SensorPathsLinux::~SensorPathsLinux() = default;
SensorDataLinux::SensorDataLinux(const SensorDataLinux& other) = default;
SensorPathsLinux::SensorPathsLinux(const SensorPathsLinux& other) = default;
bool InitSensorData(SensorType type, SensorDataLinux* data) {
bool InitSensorData(SensorType type, SensorPathsLinux* data) {
DCHECK(data);
data->type = type;
switch (type) {
case SensorType::AMBIENT_LIGHT:
InitAmbientLightSensorData(data);
......@@ -179,11 +188,28 @@ bool InitSensorData(SensorType type, SensorDataLinux* data) {
InitMagnitometerSensorData(data);
break;
default:
NOTIMPLEMENTED();
return false;
}
return true;
}
SensorInfoLinux::SensorInfoLinux(
const std::string& sensor_device_node,
double sensor_device_frequency,
double sensor_device_scaling_value,
double sensor_device_offset_value,
mojom::ReportingMode mode,
SensorPathsLinux::ReaderFunctor scaling_func,
std::vector<base::FilePath> device_reading_files)
: device_node(sensor_device_node),
device_frequency(sensor_device_frequency),
device_scaling_value(sensor_device_scaling_value),
device_offset_value(sensor_device_offset_value),
reporting_mode(mode),
apply_scaling_func(scaling_func),
device_reading_files(std::move(device_reading_files)) {}
SensorInfoLinux::~SensorInfoLinux() = default;
} // namespace device
......@@ -10,19 +10,21 @@
namespace device {
class PlatformSensorConfiguration;
struct SensorReading;
// This structure represents a context that is used to
// create a type specific SensorReader and a concrete
// sensor that uses the SensorReader to read sensor
// data from files specified in the |sensor_file_names|.
struct DEVICE_GENERIC_SENSOR_EXPORT SensorDataLinux {
using ReaderFunctor =
base::Callback<void(double scaling, SensorReading& reading)>;
SensorDataLinux();
~SensorDataLinux();
SensorDataLinux(const SensorDataLinux& other);
// This structure represents a context that is used to identify a udev device
// and create a type specific SensorInfoLinux. For example, when a
// SensorDeviceManager receives a udev device, it uses this structure to
// identify what type of sensor that is and creates a SensorInfoLinux structure
// that holds all the necessary information to create a PlatformSensorLinux.
struct DEVICE_GENERIC_SENSOR_EXPORT SensorPathsLinux {
using ReaderFunctor = base::Callback<
void(double scaling, double offset, SensorReading& reading)>;
SensorPathsLinux();
~SensorPathsLinux();
SensorPathsLinux(const SensorPathsLinux& other);
// Provides a base path to all sensors.
const base::FilePath::CharType* base_path_sensor_linux;
// Provides an array of sensor file names to be searched for.
......@@ -31,16 +33,51 @@ struct DEVICE_GENERIC_SENSOR_EXPORT SensorDataLinux {
std::vector<std::vector<std::string>> sensor_file_names;
// Scaling file to be found.
std::string sensor_scale_name;
// Frequency file to be found.
std::string sensor_frequency_file_name;
// Offset file to be found.
std::string sensor_offset_file_name;
// Used to apply scalings to raw sensor data.
ReaderFunctor apply_scaling_func;
// Reporting mode of a sensor.
mojom::ReportingMode reporting_mode;
// Sensor type
mojom::SensorType type;
// Default configuration of a sensor.
PlatformSensorConfiguration default_configuration;
};
// Initializes a sensor type specific data.
bool InitSensorData(mojom::SensorType type, SensorDataLinux* data);
// Initializes sensor data according to |type|.
bool DEVICE_GENERIC_SENSOR_EXPORT InitSensorData(mojom::SensorType type,
SensorPathsLinux* data);
// This structure represents an iio device, which info is taken
// from udev service. If a client requests a sensor from a provider,
// the provider takes this initialized and stored structure and uses it to
// create a requested PlatformSensorLinux of a certain type.
struct SensorInfoLinux {
// Represents current sensor device node.
const std::string device_node;
// Represents frequency of a sensor.
const double device_frequency;
// Represents scaling value to be applied on raw data.
const double device_scaling_value;
// Represents offset value that must be applied on raw data.
const double device_offset_value;
// Reporting mode of a sensor taken from SensorDataLinux.
const mojom::ReportingMode reporting_mode;
// Functor that is used to convert raw data.
const SensorPathsLinux::ReaderFunctor apply_scaling_func;
// Sensor files in sysfs. Used to poll data.
const std::vector<base::FilePath> device_reading_files;
SensorInfoLinux(const std::string& sensor_device_node,
double sensor_device_frequency,
double sensor_device_scaling_value,
double sensor_device_offset_value,
mojom::ReportingMode mode,
SensorPathsLinux::ReaderFunctor scaling_func,
std::vector<base::FilePath> iio_device_reading_files);
~SensorInfoLinux();
};
} // namespace device
......
This diff is collapsed.
......@@ -4,10 +4,8 @@
#include "device/generic_sensor/platform_sensor_linux.h"
#include "base/threading/thread.h"
#include "base/timer/timer.h"
#include "device/generic_sensor/linux/platform_sensor_utils_linux.h"
#include "device/generic_sensor/linux/sensor_data_linux.h"
#include "device/generic_sensor/platform_sensor_reader_linux.h"
namespace device {
......@@ -25,48 +23,61 @@ PlatformSensorLinux::PlatformSensorLinux(
mojom::SensorType type,
mojo::ScopedSharedBufferMapping mapping,
PlatformSensorProvider* provider,
const SensorDataLinux& data,
std::unique_ptr<SensorReader> sensor_reader,
scoped_refptr<base::SingleThreadTaskRunner> polling_thread_task_runner_)
const SensorInfoLinux* sensor_device,
scoped_refptr<base::SingleThreadTaskRunner> polling_thread_task_runner)
: PlatformSensor(type, std::move(mapping), provider),
timer_(new base::RepeatingTimer()),
default_configuration_(data.default_configuration),
reporting_mode_(data.reporting_mode),
sensor_reader_(std::move(sensor_reader)),
polling_thread_task_runner_(polling_thread_task_runner_),
weak_factory_(this) {}
PlatformSensorLinux::~PlatformSensorLinux() {
polling_thread_task_runner_->DeleteSoon(FROM_HERE, timer_);
default_configuration_(
PlatformSensorConfiguration(sensor_device->device_frequency)),
reporting_mode_(sensor_device->reporting_mode),
weak_factory_(this) {
sensor_reader_ =
SensorReader::Create(sensor_device, this, polling_thread_task_runner);
}
PlatformSensorLinux::~PlatformSensorLinux() = default;
mojom::ReportingMode PlatformSensorLinux::GetReportingMode() {
DCHECK(task_runner_->BelongsToCurrentThread());
return reporting_mode_;
}
void PlatformSensorLinux::UpdatePlatformSensorReading(SensorReading reading) {
DCHECK(task_runner_->BelongsToCurrentThread());
bool notifyNeeded = false;
if (GetReportingMode() == mojom::ReportingMode::ON_CHANGE) {
if (!HaveValuesChanged(reading, old_values_))
return;
notifyNeeded = true;
}
old_values_ = reading;
reading.timestamp = (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF();
UpdateSensorReading(reading, notifyNeeded);
}
void PlatformSensorLinux::NotifyPlatformSensorError() {
DCHECK(task_runner_->BelongsToCurrentThread());
NotifySensorError();
}
bool PlatformSensorLinux::StartSensor(
const PlatformSensorConfiguration& configuration) {
DCHECK(task_runner_->BelongsToCurrentThread());
return polling_thread_task_runner_->PostTask(
FROM_HERE, base::Bind(&PlatformSensorLinux::BeginPoll,
weak_factory_.GetWeakPtr(), configuration));
if (!sensor_reader_)
return false;
return sensor_reader_->StartFetchingData(configuration);
}
void PlatformSensorLinux::StopSensor() {
DCHECK(task_runner_->BelongsToCurrentThread());
polling_thread_task_runner_->PostTask(
FROM_HERE, base::Bind(&PlatformSensorLinux::StopPoll, this));
DCHECK(sensor_reader_);
sensor_reader_->StopFetchingData();
}
bool PlatformSensorLinux::CheckSensorConfiguration(
const PlatformSensorConfiguration& configuration) {
DCHECK(task_runner_->BelongsToCurrentThread());
// TODO(maksims): make this sensor dependent.
// For example, in case of accelerometer, check current polling frequency
// exposed by iio driver.
return configuration.frequency() > 0 &&
configuration.frequency() <=
mojom::SensorConfiguration::kMaxAllowedFrequency;
configuration.frequency() <= default_configuration_.frequency();
}
PlatformSensorConfiguration PlatformSensorLinux::GetDefaultConfiguration() {
......@@ -74,41 +85,4 @@ PlatformSensorConfiguration PlatformSensorLinux::GetDefaultConfiguration() {
return default_configuration_;
}
void PlatformSensorLinux::BeginPoll(
const PlatformSensorConfiguration& configuration) {
DCHECK(polling_thread_task_runner_->BelongsToCurrentThread());
timer_->Start(FROM_HERE, base::TimeDelta::FromMicroseconds(
base::Time::kMicrosecondsPerSecond /
configuration.frequency()),
this, &PlatformSensorLinux::PollForReadingData);
}
void PlatformSensorLinux::StopPoll() {
DCHECK(polling_thread_task_runner_->BelongsToCurrentThread());
timer_->Stop();
}
void PlatformSensorLinux::PollForReadingData() {
DCHECK(polling_thread_task_runner_->BelongsToCurrentThread());
SensorReading reading;
if (!sensor_reader_->ReadSensorReading(&reading)) {
task_runner_->PostTask(
FROM_HERE, base::Bind(&PlatformSensorLinux::NotifySensorError, this));
StopPoll();
return;
}
bool notifyNeeded = false;
if (GetReportingMode() == mojom::ReportingMode::ON_CHANGE) {
if (!HaveValuesChanged(reading, old_values_))
return;
notifyNeeded = true;
}
old_values_ = reading;
reading.timestamp = (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF();
UpdateSensorReading(reading, notifyNeeded);
}
} // namespace device
......@@ -8,15 +8,13 @@
#include "device/generic_sensor/platform_sensor.h"
namespace base {
class RepeatingTimer;
class SingleThreadTaskRunner;
class Thread;
}
namespace device {
class SensorReader;
struct SensorDataLinux;
struct SensorInfoLinux;
class PlatformSensorLinux : public PlatformSensor {
public:
......@@ -24,13 +22,17 @@ class PlatformSensorLinux : public PlatformSensor {
mojom::SensorType type,
mojo::ScopedSharedBufferMapping mapping,
PlatformSensorProvider* provider,
const SensorDataLinux& data,
std::unique_ptr<SensorReader> sensor_reader,
const SensorInfoLinux* sensor_device,
scoped_refptr<base::SingleThreadTaskRunner> polling_thread_task_runner);
// Thread safe.
mojom::ReportingMode GetReportingMode() override;
// Called by a sensor reader. Takes new readings.
void UpdatePlatformSensorReading(SensorReading reading);
// Called by a sensor reader if an error occurs.
void NotifyPlatformSensorError();
protected:
~PlatformSensorLinux() override;
bool StartSensor(const PlatformSensorConfiguration& configuration) override;
......@@ -40,16 +42,6 @@ class PlatformSensorLinux : public PlatformSensor {
PlatformSensorConfiguration GetDefaultConfiguration() override;
private:
void BeginPoll(const PlatformSensorConfiguration& configuration);
void StopPoll();
// Triggers |sensor_reader_| to read new sensor data.
// If new data is read, UpdateSensorReading() is called.
void PollForReadingData();
// Owned timer to be deleted on a polling thread.
base::RepeatingTimer* timer_;
const PlatformSensorConfiguration default_configuration_;
const mojom::ReportingMode reporting_mode_;
......@@ -57,9 +49,6 @@ class PlatformSensorLinux : public PlatformSensor {
// and stores them to a SensorReading structure.
std::unique_ptr<SensorReader> sensor_reader_;
// A task runner that is used to poll sensor data.
scoped_refptr<base::SingleThreadTaskRunner> polling_thread_task_runner_;
// Stores previously read values that are used to
// determine whether the recent values are changed
// and IPC can be notified that updates are available.
......
......@@ -10,7 +10,7 @@
#include "device/generic_sensor/platform_sensor_provider_android.h"
#elif defined(OS_WIN)
#include "device/generic_sensor/platform_sensor_provider_win.h"
#elif defined(OS_LINUX)
#elif defined(OS_LINUX) && defined(USE_UDEV)
#include "device/generic_sensor/platform_sensor_provider_linux.h"
#endif
......@@ -38,8 +38,10 @@ PlatformSensorProvider* PlatformSensorProvider::GetInstance() {
return PlatformSensorProviderAndroid::GetInstance();
#elif defined(OS_WIN)
return PlatformSensorProviderWin::GetInstance();
#elif defined(OS_LINUX)
#elif defined(OS_LINUX) && defined(USE_UDEV)
return PlatformSensorProviderLinux::GetInstance();
#else
return nullptr;
#endif
}
......
......@@ -32,8 +32,7 @@ void PlatformSensorProviderBase::CreateSensor(
return;
}
mojo::ScopedSharedBufferMapping mapping = shared_buffer_handle_->MapAtOffset(
kReadingBufferSize, SensorReadingSharedBuffer::GetOffset(type));
mojo::ScopedSharedBufferMapping mapping = MapSharedBufferForType(type);
if (!mapping) {
callback.Run(nullptr);
return;
......@@ -43,8 +42,6 @@ void PlatformSensorProviderBase::CreateSensor(
if (it != requests_map_.end()) {
it->second.push_back(callback);
} else { // This is the first CreateSensor call.
memset(mapping.get(), 0, kReadingBufferSize);
requests_map_[type] = CallbackQueue({callback});
CreateSensorInternal(
......@@ -117,4 +114,20 @@ void PlatformSensorProviderBase::NotifySensorCreated(
requests_map_.erase(type);
}
std::vector<mojom::SensorType>
PlatformSensorProviderBase::GetPendingRequestTypes() {
std::vector<mojom::SensorType> request_types;
for (auto const& entry : requests_map_)
request_types.push_back(entry.first);
return request_types;
}
mojo::ScopedSharedBufferMapping
PlatformSensorProviderBase::MapSharedBufferForType(mojom::SensorType type) {
mojo::ScopedSharedBufferMapping mapping = shared_buffer_handle_->MapAtOffset(
kReadingBufferSize, SensorReadingSharedBuffer::GetOffset(type));
memset(mapping.get(), 0, kReadingBufferSize);
return mapping;
}
} // namespace device
......@@ -53,13 +53,19 @@ class DEVICE_GENERIC_SENSOR_EXPORT PlatformSensorProviderBase
// are no sensors left.
virtual void AllSensorsRemoved() {}
void NotifySensorCreated(mojom::SensorType type,
scoped_refptr<PlatformSensor> sensor);
std::vector<mojom::SensorType> GetPendingRequestTypes();
mojo::ScopedSharedBufferMapping MapSharedBufferForType(
mojom::SensorType type);
private:
friend class PlatformSensor; // To call RemoveSensor();
bool CreateSharedBufferIfNeeded();
void RemoveSensor(mojom::SensorType type);
void NotifySensorCreated(mojom::SensorType type,
scoped_refptr<PlatformSensor> sensor);
private:
using CallbackQueue = std::vector<CreateSensorCallback>;
......
......@@ -5,9 +5,7 @@
#include "device/generic_sensor/platform_sensor_provider_linux.h"
#include "base/memory/singleton.h"
#include "base/task_runner_util.h"
#include "base/threading/thread.h"
#include "device/generic_sensor/linux/platform_sensor_utils_linux.h"
#include "device/generic_sensor/linux/sensor_data_linux.h"
#include "device/generic_sensor/platform_sensor_linux.h"
......@@ -20,59 +18,59 @@ PlatformSensorProviderLinux* PlatformSensorProviderLinux::GetInstance() {
base::LeakySingletonTraits<PlatformSensorProviderLinux>>::get();
}
PlatformSensorProviderLinux::PlatformSensorProviderLinux() = default;
PlatformSensorProviderLinux::PlatformSensorProviderLinux()
: sensor_nodes_enumerated_(false),
sensor_nodes_enumeration_started_(false),
sensor_device_manager_(nullptr) {}
PlatformSensorProviderLinux::~PlatformSensorProviderLinux() = default;
PlatformSensorProviderLinux::~PlatformSensorProviderLinux() {
DCHECK(!sensor_device_manager_);
}
void PlatformSensorProviderLinux::CreateSensorInternal(
mojom::SensorType type,
mojo::ScopedSharedBufferMapping mapping,
const CreateSensorCallback& callback) {
SensorDataLinux data;
if (!InitSensorData(type, &data)) {
callback.Run(nullptr);
if (!sensor_device_manager_)
sensor_device_manager_.reset(new SensorDeviceManager());
if (!sensor_nodes_enumerated_) {
if (!sensor_nodes_enumeration_started_) {
sensor_nodes_enumeration_started_ = file_task_runner_->PostTask(
FROM_HERE,
base::Bind(&SensorDeviceManager::Start,
base::Unretained(sensor_device_manager_.get()), this));
}
return;
}
if (!polling_thread_)
polling_thread_.reset(new base::Thread("Sensor polling thread"));
if (!polling_thread_->IsRunning()) {
if (!polling_thread_->StartWithOptions(
base::Thread::Options(base::MessageLoop::TYPE_IO, 0))) {
callback.Run(nullptr);
return;
}
polling_thread_task_runner_ = polling_thread_->task_runner();
SensorInfoLinux* sensor_device = GetSensorDevice(type);
if (!sensor_device) {
// If there are no sensors, stop polling thread.
if (!HasSensors())
AllSensorsRemoved();
callback.Run(nullptr);
return;
}
base::PostTaskAndReplyWithResult(
polling_thread_task_runner_.get(), FROM_HERE,
base::Bind(SensorReader::Create, data),
base::Bind(&PlatformSensorProviderLinux::SensorReaderFound,
base::Unretained(this), type, base::Passed(&mapping), callback,
data));
SensorDeviceFound(type, std::move(mapping), callback, sensor_device);
}
void PlatformSensorProviderLinux::SensorReaderFound(
void PlatformSensorProviderLinux::SensorDeviceFound(
mojom::SensorType type,
mojo::ScopedSharedBufferMapping mapping,
const PlatformSensorProviderBase::CreateSensorCallback& callback,
const SensorDataLinux& data,
std::unique_ptr<SensorReader> sensor_reader) {
SensorInfoLinux* sensor_device) {
DCHECK(CalledOnValidThread());
if (!sensor_reader) {
// If there are no sensors, stop polling thread.
if (!HasSensors())
AllSensorsRemoved();
if (!StartPollingThread()) {
callback.Run(nullptr);
return;
}
callback.Run(new PlatformSensorLinux(type, std::move(mapping), this, data,
std::move(sensor_reader),
polling_thread_task_runner_));
scoped_refptr<PlatformSensorLinux> sensor =
new PlatformSensorLinux(type, std::move(mapping), this, sensor_device,
polling_thread_->task_runner());
callback.Run(sensor);
}
void PlatformSensorProviderLinux::SetFileTaskRunner(
......@@ -85,18 +83,128 @@ void PlatformSensorProviderLinux::SetFileTaskRunner(
void PlatformSensorProviderLinux::AllSensorsRemoved() {
DCHECK(CalledOnValidThread());
DCHECK(file_task_runner_);
Shutdown();
// When there are no sensors left, the polling thread must be stopped.
// Stop() can only be called on a different thread that allows io.
// Stop() can only be called on a different thread that allows I/O.
// Thus, browser's file thread is used for this purpose.
file_task_runner_->PostTask(
FROM_HERE, base::Bind(&PlatformSensorProviderLinux::StopPollingThread,
base::Unretained(this)));
}
bool PlatformSensorProviderLinux::StartPollingThread() {
if (!polling_thread_)
polling_thread_.reset(new base::Thread("Sensor polling thread"));
if (!polling_thread_->IsRunning()) {
return polling_thread_->StartWithOptions(
base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
}
return true;
}
void PlatformSensorProviderLinux::StopPollingThread() {
DCHECK(file_task_runner_);
DCHECK(file_task_runner_->BelongsToCurrentThread());
polling_thread_->Stop();
if (polling_thread_ && polling_thread_->IsRunning())
polling_thread_->Stop();
}
void PlatformSensorProviderLinux::Shutdown() {
DCHECK(CalledOnValidThread());
const bool did_post_task = file_task_runner_->DeleteSoon(
FROM_HERE, sensor_device_manager_.release());
DCHECK(did_post_task);
sensor_nodes_enumerated_ = false;
sensor_nodes_enumeration_started_ = false;
sensor_devices_by_type_.clear();
}
SensorInfoLinux* PlatformSensorProviderLinux::GetSensorDevice(
mojom::SensorType type) {
DCHECK(CalledOnValidThread());
auto sensor = sensor_devices_by_type_.find(type);
if (sensor == sensor_devices_by_type_.end())
return nullptr;
return sensor->second.get();
}
void PlatformSensorProviderLinux::GetAllSensorDevices() {
DCHECK(CalledOnValidThread());
// TODO(maksims): implement this method once we have discovery API.
NOTIMPLEMENTED();
}
void PlatformSensorProviderLinux::SetSensorDeviceManagerForTesting(
std::unique_ptr<SensorDeviceManager> sensor_device_manager) {
DCHECK(CalledOnValidThread());
Shutdown();
sensor_device_manager_ = std::move(sensor_device_manager);
}
void PlatformSensorProviderLinux::SetFileTaskRunnerForTesting(
scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
DCHECK(CalledOnValidThread());
file_task_runner_ = std::move(task_runner);
}
void PlatformSensorProviderLinux::ProcessStoredRequests() {
DCHECK(CalledOnValidThread());
std::vector<mojom::SensorType> request_types = GetPendingRequestTypes();
if (request_types.empty())
return;
for (auto const& type : request_types) {
SensorInfoLinux* device = nullptr;
auto device_entry = sensor_devices_by_type_.find(type);
if (device_entry != sensor_devices_by_type_.end())
device = device_entry->second.get();
CreateSensorAndNotify(type, device);
}
}
void PlatformSensorProviderLinux::CreateSensorAndNotify(
mojom::SensorType type,
SensorInfoLinux* sensor_device) {
DCHECK(CalledOnValidThread());
scoped_refptr<PlatformSensorLinux> sensor;
mojo::ScopedSharedBufferMapping mapping = MapSharedBufferForType(type);
if (sensor_device && mapping && StartPollingThread()) {
sensor =
new PlatformSensorLinux(type, std::move(mapping), this, sensor_device,
polling_thread_->task_runner());
}
NotifySensorCreated(type, sensor);
}
void PlatformSensorProviderLinux::OnSensorNodesEnumerated() {
DCHECK(CalledOnValidThread());
DCHECK(!sensor_nodes_enumerated_);
sensor_nodes_enumerated_ = true;
ProcessStoredRequests();
}
void PlatformSensorProviderLinux::OnDeviceAdded(
mojom::SensorType type,
std::unique_ptr<SensorInfoLinux> sensor_device) {
DCHECK(CalledOnValidThread());
// At the moment, we support only one device per type.
if (base::ContainsKey(sensor_devices_by_type_, type)) {
DVLOG(1) << "Sensor ignored. Type " << type
<< ". Node: " << sensor_device->device_node;
return;
}
sensor_devices_by_type_[type] = std::move(sensor_device);
}
void PlatformSensorProviderLinux::OnDeviceRemoved(
mojom::SensorType type,
const std::string& device_node) {
DCHECK(CalledOnValidThread());
auto it = sensor_devices_by_type_.find(type);
if (it == sensor_devices_by_type_.end() &&
it->second->device_node == device_node)
sensor_devices_by_type_.erase(it);
}
} // namespace device
......@@ -7,23 +7,35 @@
#include "device/generic_sensor/platform_sensor_provider.h"
#include "device/generic_sensor/linux/platform_sensor_manager.h"
namespace base {
template <typename T>
struct DefaultSingletonTraits;
class Thread;
}
namespace device {
struct SensorDataLinux;
class SensorReader;
struct SensorInfoLinux;
class PlatformSensorProviderLinux : public PlatformSensorProvider {
class DEVICE_GENERIC_SENSOR_EXPORT PlatformSensorProviderLinux
: public PlatformSensorProvider,
public SensorDeviceManager::Delegate {
public:
PlatformSensorProviderLinux();
~PlatformSensorProviderLinux() override;
static PlatformSensorProviderLinux* GetInstance();
// Sets another service provided by tests.
void SetSensorDeviceManagerForTesting(
std::unique_ptr<SensorDeviceManager> sensor_device_manager);
// Sets task runner for tests.
void SetFileTaskRunnerForTesting(
scoped_refptr<base::SingleThreadTaskRunner> task_runner);
protected:
~PlatformSensorProviderLinux() override;
void CreateSensorInternal(mojom::SensorType type,
mojo::ScopedSharedBufferMapping mapping,
const CreateSensorCallback& callback) override;
......@@ -34,37 +46,70 @@ class PlatformSensorProviderLinux : public PlatformSensorProvider {
scoped_refptr<base::SingleThreadTaskRunner> file_task_runner) override;
private:
void SensorReaderFound(
friend struct base::DefaultSingletonTraits<PlatformSensorProviderLinux>;
using SensorDeviceMap =
std::unordered_map<mojom::SensorType, std::unique_ptr<SensorInfoLinux>>;
PlatformSensorProviderLinux();
void SensorDeviceFound(
mojom::SensorType type,
mojo::ScopedSharedBufferMapping mapping,
const PlatformSensorProviderBase::CreateSensorCallback& callback,
const SensorDataLinux& data,
std::unique_ptr<SensorReader> sensor_reader);
SensorInfoLinux* sensor_device);
bool StartPollingThread();
// Stops a polling thread if there are no sensors left. Must be called on
// a different that polling thread that allows io.
// a different than the polling thread which allows I/O.
void StopPollingThread();
// TODO(maksims): make a separate class Manager that will
// create provide sensors with a polling task runner, check sensors existence
// and notify provider if a new sensor has appeared and it can be created if a
// request comes again for the same sensor.
// A use case example: a request for a sensor X comes, manager checks if the
// sensor exists on a platform and notifies a provider it is not found.
// The provider stores this information into its cache and doesn't try to
// create this specific sensor if a request comes. But when, for example,
// the sensor X is plugged into a usb port, the manager notices that and
// notifies the provider, which updates its cache and starts handling requests
// for the sensor X.
//
// Right now, this thread is used to find sensors files and poll data.
// Shuts down a service that tracks events from iio subsystem.
void Shutdown();
// Returns SensorInfoLinux structure of a requested type.
// If a request cannot be processed immediately, returns nullptr and
// all the requests stored in |requests_map_| are processed after
// enumeration is ready.
SensorInfoLinux* GetSensorDevice(mojom::SensorType type);
// Returns all found iio devices. Currently not implemented.
void GetAllSensorDevices();
// Processed stored requests in |request_map_|.
void ProcessStoredRequests();
// Called when sensors are created asynchronously after enumeration is done.
void CreateSensorAndNotify(mojom::SensorType type,
SensorInfoLinux* sensor_device);
// SensorDeviceManager::Delegate implements:
void OnSensorNodesEnumerated() override;
void OnDeviceAdded(mojom::SensorType type,
std::unique_ptr<SensorInfoLinux> sensor_device) override;
void OnDeviceRemoved(mojom::SensorType type,
const std::string& device_node) override;
// Set to true when enumeration is ready.
bool sensor_nodes_enumerated_;
// Set to true when |sensor_device_manager_| has already started enumeration.
bool sensor_nodes_enumeration_started_;
// Stores all available sensor devices by type.
SensorDeviceMap sensor_devices_by_type_;
// A thread that is used by sensor readers in case of polling strategy.
std::unique_ptr<base::Thread> polling_thread_;
// A task runner that is passed to polling sensors to poll data.
scoped_refptr<base::SingleThreadTaskRunner> polling_thread_task_runner_;
// This manager is being used to get |SensorInfoLinux|, which represents
// all the information of a concrete sensor provided by OS.
std::unique_ptr<SensorDeviceManager> sensor_device_manager_;
// Browser's file thread task runner passed from renderer. Used to
// stop a polling thread.
// Browser's file thread task runner passed from renderer. Used by this
// provider to stop a polling thread and passed to a manager that
// runs a linux device monitor service on this task runner.
scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
DISALLOW_COPY_AND_ASSIGN(PlatformSensorProviderLinux);
......
// 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_linux.h"
#include "base/files/file_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_restrictions.h"
#include "base/timer/timer.h"
#include "device/generic_sensor/linux/sensor_data_linux.h"
#include "device/generic_sensor/platform_sensor_linux.h"
#include "device/generic_sensor/public/cpp/sensor_reading.h"
namespace device {
class PollingSensorReader : public SensorReader {
public:
PollingSensorReader(
const SensorInfoLinux* sensor_device,
PlatformSensorLinux* sensor,
scoped_refptr<base::SingleThreadTaskRunner> polling_task_runner);
~PollingSensorReader() override;
// SensorReader implements:
bool StartFetchingData(
const PlatformSensorConfiguration& configuration) override;
void StopFetchingData() override;
private:
// Initializes a read timer.
void InitializeTimer(const PlatformSensorConfiguration& configuration);
// Polls data and sends it to a |sensor_|.
void PollForData();
// Paths to sensor read files.
const std::vector<base::FilePath> sensor_file_paths_;
// Scaling value that are applied to raw data from sensors.
const double scaling_value_;
// Offset value.
const double offset_value_;
// Used to apply scalings and invert signs if needed.
const SensorPathsLinux::ReaderFunctor apply_scaling_func_;
// Owned pointer to a timer. Will be deleted on a polling thread once
// destructor is called.
base::RepeatingTimer* timer_;
base::WeakPtrFactory<PollingSensorReader> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(PollingSensorReader);
};
PollingSensorReader::PollingSensorReader(
const SensorInfoLinux* sensor_device,
PlatformSensorLinux* sensor,
scoped_refptr<base::SingleThreadTaskRunner> polling_task_runner)
: SensorReader(sensor, polling_task_runner),
sensor_file_paths_(sensor_device->device_reading_files),
scaling_value_(sensor_device->device_scaling_value),
offset_value_(sensor_device->device_offset_value),
apply_scaling_func_(sensor_device->apply_scaling_func),
timer_(new base::RepeatingTimer()),
weak_factory_(this) {}
PollingSensorReader::~PollingSensorReader() {
polling_task_runner_->DeleteSoon(FROM_HERE, timer_);
}
bool PollingSensorReader::StartFetchingData(
const PlatformSensorConfiguration& configuration) {
if (is_reading_active_)
StopFetchingData();
return polling_task_runner_->PostTask(
FROM_HERE, base::Bind(&PollingSensorReader::InitializeTimer,
weak_factory_.GetWeakPtr(), configuration));
}
void PollingSensorReader::StopFetchingData() {
is_reading_active_ = false;
timer_->Stop();
}
void PollingSensorReader::InitializeTimer(
const PlatformSensorConfiguration& configuration) {
DCHECK(polling_task_runner_->BelongsToCurrentThread());
timer_->Start(FROM_HERE, base::TimeDelta::FromMicroseconds(
base::Time::kMicrosecondsPerSecond /
configuration.frequency()),
this, &PollingSensorReader::PollForData);
is_reading_active_ = true;
}
void PollingSensorReader::PollForData() {
DCHECK(polling_task_runner_->BelongsToCurrentThread());
base::ThreadRestrictions::AssertIOAllowed();
SensorReading readings;
DCHECK_LE(sensor_file_paths_.size(), arraysize(readings.values));
int i = 0;
for (const auto& path : sensor_file_paths_) {
std::string new_read_value;
if (!base::ReadFileToString(path, &new_read_value)) {
NotifyReadError();
StopFetchingData();
return;
}
double new_value = 0;
base::TrimWhitespaceASCII(new_read_value, base::TRIM_ALL, &new_read_value);
if (!base::StringToDouble(new_read_value, &new_value)) {
NotifyReadError();
StopFetchingData();
return;
}
readings.values[i++] = new_value;
}
if (!apply_scaling_func_.is_null())
apply_scaling_func_.Run(scaling_value_, offset_value_, readings);
if (is_reading_active_) {
task_runner_->PostTask(
FROM_HERE, base::Bind(&PlatformSensorLinux::UpdatePlatformSensorReading,
base::Unretained(sensor_), readings));
}
}
// static
std::unique_ptr<SensorReader> SensorReader::Create(
const SensorInfoLinux* sensor_device,
PlatformSensorLinux* sensor,
scoped_refptr<base::SingleThreadTaskRunner> polling_thread_task_runner) {
// TODO(maksims): implement triggered reading. At the moment,
// only polling read is supported.
return base::MakeUnique<PollingSensorReader>(sensor_device, sensor,
polling_thread_task_runner);
}
SensorReader::SensorReader(
PlatformSensorLinux* sensor,
scoped_refptr<base::SingleThreadTaskRunner> polling_task_runner)
: sensor_(sensor),
polling_task_runner_(polling_task_runner),
task_runner_(base::ThreadTaskRunnerHandle::Get()),
is_reading_active_(false) {}
SensorReader::~SensorReader() = default;
void SensorReader::NotifyReadError() {
if (is_reading_active_) {
task_runner_->PostTask(
FROM_HERE, base::Bind(&PlatformSensorLinux::NotifyPlatformSensorError,
base::Unretained(sensor_)));
}
}
} // namespace device
// 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.
#ifndef DEVICE_GENERIC_SENSOR_PLATFORM_SENSOR_READER_LINUX_H_
#define DEVICE_GENERIC_SENSOR_PLATFORM_SENSOR_READER_LINUX_H_
#include "base/memory/ref_counted.h"
#include "device/generic_sensor/generic_sensor_export.h"
namespace base {
class SingleThreadTaskRunner;
}
namespace device {
class PlatformSensorLinux;
class PlatformSensorConfiguration;
struct SensorInfoLinux;
// A generic reader class that can be implemented with two different strategies:
// polling and on trigger.
class SensorReader {
public:
// Creates a new instance of SensorReader. At the moment, only polling
// reader is supported.
static std::unique_ptr<SensorReader> Create(
const SensorInfoLinux* sensor_device,
PlatformSensorLinux* sensor,
scoped_refptr<base::SingleThreadTaskRunner> polling_thread_task_runner);
virtual ~SensorReader();
// Starts fetching data based on strategy this reader has chosen.
// Only polling strategy is supported at the moment. Thread safe.
virtual bool StartFetchingData(
const PlatformSensorConfiguration& configuration) = 0;
// Stops fetching data. Thread safe.
virtual void StopFetchingData() = 0;
protected:
SensorReader(PlatformSensorLinux* sensor,
scoped_refptr<base::SingleThreadTaskRunner> polling_task_runner);
// Notifies |sensor_| about an error.
void NotifyReadError();
// Non-owned pointer to a sensor that created this reader.
PlatformSensorLinux* sensor_;
// A task runner that is used to poll data.
scoped_refptr<base::SingleThreadTaskRunner> polling_task_runner_;
// A task runner that belongs to a thread this reader is created on.
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
// Indicates if reading is active.
bool is_reading_active_;
DISALLOW_COPY_AND_ASSIGN(SensorReader);
};
} // namespace device
#endif // DEVICE_GENERIC_SENSOR_PLATFORM_SENSOR_READER_LINUX_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment