blob: 70cac8f02ee47f43e2317293561510aef4dec43f [file] [log] [blame]
// Copyright 2021 The Chromium OS 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 "iioservice/daemon/sensor_device_fusion_gravity.h"
#include <utility>
#include <base/logging.h>
#include <base/strings/stringprintf.h>
#include <base/strings/string_number_conversions.h>
#include "iioservice/daemon/samples_handler_fusion_gravity.h"
#include "iioservice/include/common.h"
namespace iioservice {
// static
constexpr char SensorDeviceFusionGravity::kName[];
constexpr double SensorDeviceFusionGravity::kAccelMinFrequency;
constexpr double SensorDeviceFusionGravity::kGyroMinFrequency;
// static
SensorDeviceFusion::ScopedSensorDeviceFusion SensorDeviceFusionGravity::Create(
int32_t id,
Location location,
scoped_refptr<base::SequencedTaskRunner> ipc_task_runner,
base::RepeatingCallback<
void(int32_t iio_device_id,
mojo::PendingReceiver<cros::mojom::SensorDevice> request,
const std::set<cros::mojom::DeviceType>& types)>
iio_add_receiver_callback,
double max_frequency,
int32_t accel_id,
int32_t gyro_id) {
DCHECK(ipc_task_runner->RunsTasksInCurrentSequence());
ScopedSensorDeviceFusion device(nullptr, SensorDeviceFusionDeleter);
device.reset(new SensorDeviceFusionGravity(
id, location, std::move(ipc_task_runner),
std::move(iio_add_receiver_callback), max_frequency, GetGravityChannels(),
accel_id, gyro_id));
return device;
}
SensorDeviceFusionGravity::~SensorDeviceFusionGravity() = default;
void SensorDeviceFusionGravity::GetAttributes(
const std::vector<std::string>& attr_names,
GetAttributesCallback callback) {
DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence());
accel_->GetAttributes(attr_names, std::move(callback));
}
void SensorDeviceFusionGravity::GetChannelsAttributes(
const std::vector<int32_t>& iio_chn_indices,
const std::string& attr_name,
GetChannelsAttributesCallback callback) {
DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence());
// Do not provide gravity device channels' attributes.
std::move(callback).Run(std::vector<base::Optional<std::string>>(
iio_chn_indices.size(), base::nullopt));
}
void SensorDeviceFusionGravity::UpdateRequestedFrequency(double frequency) {
DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence());
SensorDeviceFusion::UpdateRequestedFrequency(frequency);
accel_->SetFrequency(FixFrequencyWithMin(kAccelMinFrequency, frequency),
base::BindOnce(&SamplesHandlerFusion::SetDevFrequency,
samples_handler_->GetWeakPtr()));
gyro_->SetFrequency(FixFrequencyWithMin(kGyroMinFrequency, frequency));
}
SensorDeviceFusionGravity::SensorDeviceFusionGravity(
int32_t id,
Location location,
scoped_refptr<base::SequencedTaskRunner> ipc_task_runner,
base::RepeatingCallback<
void(int32_t iio_device_id,
mojo::PendingReceiver<cros::mojom::SensorDevice> request,
const std::set<cros::mojom::DeviceType>& types)>
iio_add_receiver_callback,
double max_frequency,
std::vector<std::string> channel_ids,
int32_t accel_id,
int32_t gyro_id)
: SensorDeviceFusion(id,
cros::mojom::DeviceType::GRAVITY,
location,
std::move(ipc_task_runner),
std::move(iio_add_receiver_callback),
max_frequency,
std::move(channel_ids)) {
auto samples_handler = std::make_unique<SamplesHandlerFusionGravity>(
ipc_task_runner_, channel_ids_,
base::BindRepeating(&SensorDeviceFusionGravity::UpdateRequestedFrequency,
weak_factory_.GetWeakPtr()));
DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence());
auto accel = std::make_unique<IioDeviceHandler>(
ipc_task_runner_, accel_id, cros::mojom::DeviceType::ACCEL,
iio_add_receiver_callback_,
base::BindRepeating(&SamplesHandlerFusionGravity::HandleAccelSample,
samples_handler->GetWeakPtr()),
base::BindRepeating(&SensorDeviceFusionGravity::OnReadFailed,
weak_factory_.GetWeakPtr(),
cros::mojom::DeviceType::ACCEL),
base::BindOnce(&SensorDeviceFusionGravity::Invalidate,
weak_factory_.GetWeakPtr()));
accel_ = accel.get();
iio_device_handlers_.push_back(std::move(accel));
auto gyro = std::make_unique<IioDeviceHandler>(
ipc_task_runner_, gyro_id, cros::mojom::DeviceType::ANGLVEL,
iio_add_receiver_callback_,
base::BindRepeating(&SamplesHandlerFusionGravity::HandleGyroSample,
samples_handler->GetWeakPtr()),
base::BindRepeating(&SensorDeviceFusionGravity::OnReadFailed,
weak_factory_.GetWeakPtr(),
cros::mojom::DeviceType::ANGLVEL),
base::BindOnce(&SensorDeviceFusionGravity::Invalidate,
weak_factory_.GetWeakPtr()));
gyro_ = gyro.get();
iio_device_handlers_.push_back(std::move(gyro));
samples_handler_ = std::move(samples_handler);
accel_->SetAttribute(
cros::mojom::kSamplingFrequencyAvailable,
GetSamplingFrequencyAvailable(kAccelMinFrequency, max_frequency));
// Reuse "gravity" as the device name.
accel_->SetAttribute(cros::mojom::kDeviceName, kName);
accel_->GetAttributes(
{cros::mojom::kScale},
base::BindOnce(&SensorDeviceFusionGravity::GetScaleCallback,
weak_factory_.GetWeakPtr(),
cros::mojom::DeviceType::ACCEL));
gyro_->GetAttributes(
{cros::mojom::kScale},
base::BindOnce(&SensorDeviceFusionGravity::GetScaleCallback,
weak_factory_.GetWeakPtr(),
cros::mojom::DeviceType::ANGLVEL));
}
void SensorDeviceFusionGravity::GetScaleCallback(
cros::mojom::DeviceType type,
const std::vector<base::Optional<std::string>>& values) {
DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence());
double scale = 1.0;
if (values.empty() || !values[0]) {
LOGF(ERROR) << "Cannot retrieve scale attribute from type: " << type;
} else {
if (values.size() > 1)
LOGF(ERROR) << "Invalid size of attribute values: " << values.size();
if (!values[0] || !base::StringToDouble(*values[0], &scale)) {
LOGF(ERROR) << "Invalid scale: " << values[0].value_or("")
<< ", for DeviceType: " << type;
}
}
static_cast<SamplesHandlerFusionGravity*>(samples_handler_.get())
->SetScale(type, scale);
}
void SensorDeviceFusionGravity::OnReadFailed(cros::mojom::DeviceType type) {
DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence());
LOGF(ERROR) << "OnReadFailed: " << type;
// TODO(chenghaoyang)
}
} // namespace iioservice