blob: 8a78ea731de413bfcd2757e4930afa137998ddd7 [file] [log] [blame]
// 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 "base/sys_info.h"
#include "base/version.h"
#include "device/generic_sensor/generic_sensor_consts.h"
#include "device/generic_sensor/linux/sensor_data_linux.h"
#include "device/generic_sensor/public/cpp/sensor_reading.h"
namespace device {
namespace {
using mojom::SensorType;
#if defined(OS_CHROMEOS)
// ChromeOS kernel version, when axes were changed to XYZ. Before 3.18,
// they were YXZ.
const char kChangedAxisKernelVersion[] = "3.18.0";
#endif
const base::FilePath::CharType* kSensorsBasePath =
FILE_PATH_LITERAL("/sys/bus/iio/devices");
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->default_configuration =
PlatformSensorConfiguration(kDefaultAmbientLightFrequencyHz);
}
// Depending on a kernel version, CrOS has a different axes plane.
// Before 3.18 it was YXZ and after XYZ.
// TODO(maksims): Track crbug.com/501184. 3.14 will have the same sensor stack
// as 3.18 has, which will probably change the order of axes.
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,
SensorPathsLinux* data) {
#if defined(OS_CHROMEOS)
const base::Version checked_kernel_version(kChangedAxisKernelVersion);
DCHECK(checked_kernel_version.IsValid());
const base::Version current_version(base::SysInfo::OperatingSystemVersion());
if (current_version.IsValid() && current_version < checked_kernel_version) {
data->sensor_file_names.push_back(file_names_y);
data->sensor_file_names.push_back(file_names_x);
} else {
data->sensor_file_names.push_back(file_names_x);
data->sensor_file_names.push_back(file_names_y);
}
data->sensor_file_names.push_back(file_names_z);
#else
data->sensor_file_names.push_back(file_names_x);
data->sensor_file_names.push_back(file_names_y);
data->sensor_file_names.push_back(file_names_z);
#endif
}
// TODO(maksims): add support for lid accelerometer on chromeos.
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",
"in_accel_y_raw"};
std::vector<std::string> file_names_z{"in_accel_z_base_raw",
"in_accel_z_raw"};
#if defined(OS_CHROMEOS)
data->sensor_scale_name = "in_accel_base_scale";
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->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 * 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->default_configuration =
PlatformSensorConfiguration(kDefaultAccelerometerFrequencyHz);
}
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",
"in_anglvel_y_raw"};
std::vector<std::string> file_names_z{"in_anglvel_z_base_raw",
"in_anglvel_z_raw"};
#if defined(OS_CHROMEOS)
data->sensor_scale_name = "in_anglvel_base_scale";
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 + offset;
// Adapt CrOS reading values to generic sensor api specs.
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_anglvel_scale";
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->default_configuration =
PlatformSensorConfiguration(kDefaultGyroscopeFrequencyHz);
}
// TODO(maksims): Verify magnitometer works correctly on a chromebook when
// I get one with that sensor onboard.
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->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->default_configuration =
PlatformSensorConfiguration(kDefaultMagnetometerFrequencyHz);
}
} // namespace
SensorPathsLinux::SensorPathsLinux()
: base_path_sensor_linux(kSensorsBasePath) {}
SensorPathsLinux::~SensorPathsLinux() = default;
SensorPathsLinux::SensorPathsLinux(const SensorPathsLinux& other) = default;
bool InitSensorData(SensorType type, SensorPathsLinux* data) {
DCHECK(data);
data->type = type;
switch (type) {
case SensorType::AMBIENT_LIGHT:
InitAmbientLightSensorData(data);
break;
case SensorType::ACCELEROMETER:
InitAccelerometerSensorData(data);
break;
case SensorType::GYROSCOPE:
InitGyroscopeSensorData(data);
break;
case SensorType::MAGNETOMETER:
InitMagnitometerSensorData(data);
break;
default:
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