123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443 |
- // Copyright 2020 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 "services/device/generic_sensor/platform_sensor_chromeos.h"
- #include <iterator>
- #include <utility>
- #include "base/bind.h"
- #include "base/containers/contains.h"
- #include "base/ranges/algorithm.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/time/time.h"
- #include "services/device/public/cpp/generic_sensor/sensor_traits.h"
- namespace device {
- namespace {
- constexpr char kAxes[][3] = {"_x", "_y", "_z"};
- } // namespace
- PlatformSensorChromeOS::PlatformSensorChromeOS(
- int32_t iio_device_id,
- mojom::SensorType type,
- SensorReadingSharedBuffer* reading_buffer,
- PlatformSensorProvider* provider,
- mojo::ConnectionErrorWithReasonCallback sensor_device_disconnect_callback,
- double scale,
- mojo::Remote<chromeos::sensors::mojom::SensorDevice> sensor_device_remote)
- : PlatformSensor(type, reading_buffer, provider),
- iio_device_id_(iio_device_id),
- sensor_device_disconnect_callback_(
- std::move(sensor_device_disconnect_callback)),
- default_configuration_(
- PlatformSensorConfiguration(GetSensorMaxAllowedFrequency(type))),
- scale_(scale),
- sensor_device_remote_(std::move(sensor_device_remote)) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(sensor_device_remote_.is_bound());
- DCHECK_GT(scale_, 0.0);
- sensor_device_remote_.set_disconnect_with_reason_handler(
- base::BindOnce(&PlatformSensorChromeOS::OnSensorDeviceDisconnect,
- weak_factory_.GetWeakPtr()));
- sensor_device_remote_->SetTimeout(0);
- sensor_device_remote_->GetAllChannelIds(
- base::BindOnce(&PlatformSensorChromeOS::GetAllChannelIdsCallback,
- weak_factory_.GetWeakPtr()));
- }
- PlatformSensorChromeOS::~PlatformSensorChromeOS() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- }
- mojom::ReportingMode PlatformSensorChromeOS::GetReportingMode() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (GetType() == mojom::SensorType::AMBIENT_LIGHT)
- return mojom::ReportingMode::ON_CHANGE;
- return mojom::ReportingMode::CONTINUOUS;
- }
- void PlatformSensorChromeOS::OnSampleUpdated(
- const base::flat_map<int32_t, int64_t>& sample) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(!channel_indices_.empty());
- if (sample.size() != channel_indices_.size()) {
- LOG(WARNING) << "Invalid sample with size: " << sample.size();
- OnErrorOccurred(chromeos::sensors::mojom::ObserverErrorType::READ_FAILED);
- return;
- }
- for (auto index : channel_indices_) {
- if (!base::Contains(sample, index)) {
- LOG(ERROR) << "Missing channel: " << iio_channel_ids_[index]
- << " in sample.";
- OnErrorOccurred(chromeos::sensors::mojom::ObserverErrorType::READ_FAILED);
- return;
- }
- }
- if (num_failed_reads_ > 0 && ++num_recovery_reads_ == kNumRecoveryReads) {
- num_recovery_reads_ = 0;
- --num_failed_reads_;
- }
- SensorReading reading;
- switch (GetType()) {
- case mojom::SensorType::AMBIENT_LIGHT:
- DCHECK_EQ(channel_indices_.size(), 2u);
- reading.als.value = GetScaledValue(sample.at(channel_indices_[0]));
- break;
- case mojom::SensorType::PROXIMITY:
- DCHECK_EQ(channel_indices_.size(), 2u);
- reading.proximity.value = GetScaledValue(sample.at(channel_indices_[0]));
- break;
- case mojom::SensorType::ACCELEROMETER:
- case mojom::SensorType::GRAVITY:
- DCHECK_EQ(channel_indices_.size(), 4u);
- reading.accel.x = GetScaledValue(sample.at(channel_indices_[0]));
- reading.accel.y = GetScaledValue(sample.at(channel_indices_[1]));
- reading.accel.z = GetScaledValue(sample.at(channel_indices_[2]));
- break;
- case mojom::SensorType::GYROSCOPE:
- DCHECK_EQ(channel_indices_.size(), 4u);
- reading.gyro.x = GetScaledValue(sample.at(channel_indices_[0]));
- reading.gyro.y = GetScaledValue(sample.at(channel_indices_[1]));
- reading.gyro.z = GetScaledValue(sample.at(channel_indices_[2]));
- break;
- case mojom::SensorType::MAGNETOMETER:
- DCHECK_EQ(channel_indices_.size(), 4u);
- reading.magn.x = GetScaledValue(sample.at(channel_indices_[0]));
- reading.magn.y = GetScaledValue(sample.at(channel_indices_[1]));
- reading.magn.z = GetScaledValue(sample.at(channel_indices_[2]));
- break;
- default:
- break;
- }
- reading.raw.timestamp =
- base::Nanoseconds(sample.at(channel_indices_.back())).InSecondsF();
- UpdateSharedBufferAndNotifyClients(reading);
- }
- void PlatformSensorChromeOS::OnErrorOccurred(
- chromeos::sensors::mojom::ObserverErrorType type) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- switch (type) {
- case chromeos::sensors::mojom::ObserverErrorType::ALREADY_STARTED:
- LOG(ERROR) << "Sensor " << iio_device_id_
- << ": Another observer has already started to read samples";
- ResetOnError();
- break;
- case chromeos::sensors::mojom::ObserverErrorType::FREQUENCY_INVALID:
- LOG(ERROR) << "Sensor " << iio_device_id_
- << ": Observer started with an invalid frequency";
- ResetOnError();
- break;
- case chromeos::sensors::mojom::ObserverErrorType::NO_ENABLED_CHANNELS:
- LOG(ERROR) << "Sensor " << iio_device_id_
- << ": Observer started with no channels enabled";
- SetChannelsEnabled();
- break;
- case chromeos::sensors::mojom::ObserverErrorType::SET_FREQUENCY_IO_FAILED:
- LOG(ERROR) << "Sensor " << iio_device_id_
- << ": Failed to set frequency to the physical device";
- break;
- case chromeos::sensors::mojom::ObserverErrorType::GET_FD_FAILED:
- LOG(ERROR) << "Sensor " << iio_device_id_
- << ": Failed to get the device's fd to poll on";
- break;
- case chromeos::sensors::mojom::ObserverErrorType::READ_FAILED:
- LOG(ERROR) << "Sensor " << iio_device_id_ << ": Failed to read a sample";
- OnReadFailure();
- break;
- case chromeos::sensors::mojom::ObserverErrorType::READ_TIMEOUT:
- LOG(ERROR) << "Sensor " << iio_device_id_ << ": A read timed out";
- break;
- default:
- LOG(ERROR) << "Sensor " << iio_device_id_ << ": error "
- << static_cast<int>(type);
- break;
- }
- }
- bool PlatformSensorChromeOS::StartSensor(
- const PlatformSensorConfiguration& configuration) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (!sensor_device_remote_.is_bound()) {
- LOG(WARNING) << "Unbound sensor_device_remote_, skipping StartSensor.";
- return false;
- }
- if (configuration.frequency() <= 0.0) {
- LOG(ERROR) << "Invalid frequency: " << configuration.frequency()
- << " in sensor with id: " << iio_device_id_;
- return false;
- }
- if (receiver_.is_bound() &&
- configuration.frequency() == current_configuration_.frequency()) {
- // Nothing to do.
- return true;
- }
- current_configuration_ = configuration;
- StartReadingIfReady();
- return true;
- }
- void PlatformSensorChromeOS::StopSensor() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- receiver_.reset();
- }
- bool PlatformSensorChromeOS::CheckSensorConfiguration(
- const PlatformSensorConfiguration& configuration) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- return configuration.frequency() > 0 &&
- configuration.frequency() <= default_configuration_.frequency();
- }
- PlatformSensorConfiguration PlatformSensorChromeOS::GetDefaultConfiguration() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- return default_configuration_;
- }
- void PlatformSensorChromeOS::SensorReplaced() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- VLOG(1) << "SensorReplaced with id: " << iio_device_id_;
- ResetReadingBuffer();
- ResetOnError();
- }
- void PlatformSensorChromeOS::ResetOnError() {
- LOG(ERROR) << "ResetOnError of sensor with id: " << iio_device_id_;
- sensor_device_remote_.reset();
- receiver_.reset();
- NotifySensorError();
- }
- void PlatformSensorChromeOS::OnSensorDeviceDisconnect(
- uint32_t custom_reason_code,
- const std::string& description) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- auto reason =
- static_cast<chromeos::sensors::mojom::SensorDeviceDisconnectReason>(
- custom_reason_code);
- LOG(ERROR) << "OnSensorDeviceDisconnect, reason: " << reason
- << ", description: " << description;
- std::move(sensor_device_disconnect_callback_)
- .Run(custom_reason_code, description);
- ResetOnError();
- }
- void PlatformSensorChromeOS::StartReadingIfReady() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(sensor_device_remote_.is_bound());
- if (required_channel_ids_.empty() ||
- current_configuration_.frequency() <= 0.0) {
- // Not ready yet.
- return;
- }
- UpdateSensorDeviceFrequency();
- if (receiver_.is_bound())
- return;
- sensor_device_remote_->StartReadingSamples(BindNewPipeAndPassRemote());
- }
- mojo::PendingRemote<chromeos::sensors::mojom::SensorDeviceSamplesObserver>
- PlatformSensorChromeOS::BindNewPipeAndPassRemote() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(!receiver_.is_bound());
- auto pending_remote = receiver_.BindNewPipeAndPassRemote(main_task_runner());
- receiver_.set_disconnect_with_reason_handler(
- base::BindOnce(&PlatformSensorChromeOS::OnObserverDisconnect,
- weak_factory_.GetWeakPtr()));
- return pending_remote;
- }
- void PlatformSensorChromeOS::OnObserverDisconnect(
- uint32_t custom_reason_code,
- const std::string& description) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(receiver_.is_bound());
- auto reason =
- static_cast<chromeos::sensors::mojom::SensorDeviceDisconnectReason>(
- custom_reason_code);
- LOG(ERROR) << "OnObserverDisconnect, reason: " << reason
- << ", description: " << description;
- std::move(sensor_device_disconnect_callback_)
- .Run(custom_reason_code, description);
- ResetOnError();
- }
- void PlatformSensorChromeOS::SetRequiredChannels() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(required_channel_ids_.empty()); // Should only be called once.
- absl::optional<std::string> axes_prefix = absl::nullopt;
- switch (GetType()) {
- case mojom::SensorType::AMBIENT_LIGHT:
- required_channel_ids_.push_back(chromeos::sensors::mojom::kLightChannel);
- break;
- case mojom::SensorType::ACCELEROMETER:
- axes_prefix = chromeos::sensors::mojom::kAccelerometerChannel;
- break;
- case mojom::SensorType::GYROSCOPE:
- axes_prefix = chromeos::sensors::mojom::kGyroscopeChannel;
- break;
- case mojom::SensorType::MAGNETOMETER:
- axes_prefix = chromeos::sensors::mojom::kMagnetometerChannel;
- break;
- case mojom::SensorType::GRAVITY:
- axes_prefix = chromeos::sensors::mojom::kGravityChannel;
- break;
- default:
- break;
- }
- if (axes_prefix.has_value()) {
- for (const auto* axis : kAxes)
- required_channel_ids_.push_back(axes_prefix.value() + std::string(axis));
- }
- required_channel_ids_.push_back(chromeos::sensors::mojom::kTimestampChannel);
- }
- void PlatformSensorChromeOS::GetAllChannelIdsCallback(
- const std::vector<std::string>& iio_channel_ids) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- SetRequiredChannels();
- DCHECK(!required_channel_ids_.empty());
- iio_channel_ids_ = iio_channel_ids;
- for (const std::string& channel : required_channel_ids_) {
- auto it = base::ranges::find(iio_channel_ids_, channel);
- if (it == iio_channel_ids_.end()) {
- LOG(ERROR) << "Missing channel: " << channel;
- ResetOnError();
- return;
- }
- channel_indices_.push_back(std::distance(iio_channel_ids_.begin(), it));
- }
- DCHECK_EQ(channel_indices_.size(), required_channel_ids_.size());
- SetChannelsEnabled();
- StartReadingIfReady();
- }
- void PlatformSensorChromeOS::UpdateSensorDeviceFrequency() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(sensor_device_remote_.is_bound());
- sensor_device_remote_->SetFrequency(
- current_configuration_.frequency(),
- base::BindOnce(&PlatformSensorChromeOS::SetFrequencyCallback,
- weak_factory_.GetWeakPtr(),
- current_configuration_.frequency()));
- }
- void PlatformSensorChromeOS::SetFrequencyCallback(double target_frequency,
- double result_frequency) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if ((target_frequency <= 0.0 && result_frequency <= 0.0) ||
- (target_frequency > 0.0 && result_frequency > 0.0)) {
- return;
- }
- LOG(ERROR) << "SetFrequency failed. Target frequency: " << target_frequency
- << ", result requency: " << result_frequency;
- ResetOnError();
- }
- void PlatformSensorChromeOS::SetChannelsEnabled() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (!sensor_device_remote_.is_bound()) {
- LOG(WARNING)
- << "Unbound sensor_device_remote_, skipping SetChannelEnabled.";
- return;
- }
- sensor_device_remote_->SetChannelsEnabled(
- channel_indices_, true,
- base::BindOnce(&PlatformSensorChromeOS::SetChannelsEnabledCallback,
- weak_factory_.GetWeakPtr()));
- }
- void PlatformSensorChromeOS::SetChannelsEnabledCallback(
- const std::vector<int32_t>& failed_indices) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (failed_indices.empty())
- return;
- for (int32_t index : failed_indices) {
- LOG(ERROR) << "Failed to enable channel: " << iio_channel_ids_[index]
- << " in sensor with id: " << iio_device_id_;
- }
- ResetOnError();
- }
- double PlatformSensorChromeOS::GetScaledValue(int64_t value) const {
- return value * scale_;
- }
- void PlatformSensorChromeOS::OnReadFailure() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (++num_failed_reads_ < kNumFailedReadsBeforeGivingUp) {
- LOG(ERROR) << "ReadSamples error #" << num_failed_reads_ << " occurred";
- return;
- }
- num_failed_reads_ = num_recovery_reads_ = 0;
- LOG(ERROR) << "Too many failed reads";
- ResetOnError();
- }
- } // namespace device
|