blob: 815910cd7337b058a26f2ed69bf4eae2815ab4ef [file] [log] [blame]
// Copyright 2021 The Fuchsia 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 "src/ui/input/drivers/goldfish_sensor/input_device.h"
#include <fidl/fuchsia.input.report/cpp/wire.h>
#include <lib/async/dispatcher.h>
#include <lib/ddk/debug.h>
#include <lib/fidl/cpp/wire/arena.h>
#include <lib/fit/function.h>
#include <lib/zx/clock.h>
#include <cmath>
#include <cstdint>
#include "src/ui/input/drivers/goldfish_sensor/parser.h"
#include "src/ui/input/drivers/goldfish_sensor/root_device.h"
namespace fir_fidl = ::fuchsia_input_report::wire;
namespace goldfish::sensor {
namespace {
// A "measurement ID" was sent at the end of sensor data payload which allows
// filtering stale sensor values.
constexpr uint64_t kMeasurementIdSize = 1u;
} // namespace
InputDevice::InputDevice(zx_device_t* parent, async_dispatcher_t* dispatcher,
OnDestroyCallback on_destroy)
: InputDeviceType(parent), dispatcher_(dispatcher), on_destroy_(std::move(on_destroy)) {}
InputDevice::~InputDevice() {
if (on_destroy_) {
on_destroy_(this);
}
}
void AccelerationInputDevice::InputReport::ToFidlInputReport(
fidl::WireTableBuilder<fir_fidl::InputReport>& input_report, fidl::AnyArena& allocator) const {
auto sensor_report = fir_fidl::SensorInputReport::Builder(allocator);
fidl::VectorView<int64_t> values(allocator, 3);
// Sensor reading uses unit |m/s^2|, while InputReport uses unit
// |m/s^2 * 1e-2| and only accepts integer.
// This converts the sensor reading to InputReport values.
constexpr auto SensorReadingToFidlReportValue = [](float reading) -> int {
return static_cast<int>(reading * 100);
};
values[0] = SensorReadingToFidlReportValue(x);
values[1] = SensorReadingToFidlReportValue(y);
values[2] = SensorReadingToFidlReportValue(z);
sensor_report.values(values);
input_report.event_time(event_time.get());
input_report.sensor(sensor_report.Build());
}
fpromise::result<InputDevice*, zx_status_t> AccelerationInputDevice::Create(
RootDevice* sensor, async_dispatcher_t* dispatcher) {
// Parent device (sensor) is guaranteed to outlive the child input device
// (dev), so it's safe to use raw pointers here.
auto device = std::make_unique<AccelerationInputDevice>(
sensor->zxdev(), dispatcher,
[sensor](InputDevice* dev) { sensor->input_devices()->RemoveDevice(dev); });
zx_status_t status;
if ((status = device->DdkAdd("goldfish-sensor-accel")) != ZX_OK) {
return fpromise::error(status);
}
// Device will be owned by devmgr.
return fpromise::ok(device.release());
}
zx_status_t AccelerationInputDevice::OnReport(const SensorReport& rpt) {
InputReport input_report;
input_report.event_time = zx::clock::get_monotonic();
if (rpt.data.size() != 3 && rpt.data.size() != 3 + kMeasurementIdSize) {
zxlogf(ERROR, "AccelerationInputDevice: invalid data size: %lu", rpt.data.size());
return ZX_ERR_INVALID_ARGS;
}
if (auto p = std::get_if<Numeric>(&rpt.data[0]); p != nullptr) {
input_report.x = static_cast<float>(p->Double());
} else {
zxlogf(ERROR, "AccelerationInputDevice: invalid x");
return ZX_ERR_INVALID_ARGS;
}
if (auto p = std::get_if<Numeric>(&rpt.data[1]); p != nullptr) {
input_report.y = static_cast<float>(p->Double());
} else {
zxlogf(ERROR, "AccelerationInputDevice: invalid y");
return ZX_ERR_INVALID_ARGS;
}
if (auto p = std::get_if<Numeric>(&rpt.data[2]); p != nullptr) {
input_report.z = static_cast<float>(p->Double());
} else {
zxlogf(ERROR, "AccelerationInputDevice: invalid z");
return ZX_ERR_INVALID_ARGS;
}
input_report_readers_.SendReportToAllReaders(input_report);
return ZX_OK;
}
void AccelerationInputDevice::GetDescriptor(GetDescriptorCompleter::Sync& completer) {
constexpr size_t kDescriptorBufferSize = 512;
constexpr fir_fidl::Axis kAxis = {
.range = {.min = INT64_MIN, .max = INT64_MAX},
// unit: 0.01 m/s^2
.unit = {.type = fir_fidl::UnitType::kSiLinearAcceleration, .exponent = -2},
};
fidl::Arena<kDescriptorBufferSize> allocator;
auto device_info = fir_fidl::DeviceInformation::Builder(allocator);
device_info.vendor_id(static_cast<uint32_t>(fir_fidl::VendorId::kGoogle));
device_info.product_id(
static_cast<uint32_t>(fir_fidl::VendorGoogleProductId::kGoldfishAccelerationSensor));
fidl::VectorView<fir_fidl::SensorAxis> sensor_axes(allocator, 3);
sensor_axes[0].axis = kAxis;
sensor_axes[1].axis = kAxis;
sensor_axes[2].axis = kAxis;
sensor_axes[0].type = fir_fidl::SensorType::kAccelerometerX;
sensor_axes[1].type = fir_fidl::SensorType::kAccelerometerY;
sensor_axes[2].type = fir_fidl::SensorType::kAccelerometerZ;
fidl::VectorView<fir_fidl::SensorInputDescriptor> sensor_input_descriptor(allocator, 1);
sensor_input_descriptor[0] =
fir_fidl::SensorInputDescriptor::Builder(allocator).values(sensor_axes).Build();
auto sensor_descriptor = fir_fidl::SensorDescriptor::Builder(allocator);
sensor_descriptor.input(sensor_input_descriptor);
auto descriptor = fir_fidl::DeviceDescriptor::Builder(allocator);
descriptor.device_information(device_info.Build());
descriptor.sensor(sensor_descriptor.Build());
completer.Reply(descriptor.Build());
}
void AccelerationInputDevice::GetInputReportsReader(
GetInputReportsReaderRequestView request, GetInputReportsReaderCompleter::Sync& completer) {
zx_status_t status = input_report_readers_.CreateReader(dispatcher(), std::move(request->reader));
ZX_DEBUG_ASSERT(status == ZX_OK);
}
void GyroscopeInputDevice::InputReport::ToFidlInputReport(
fidl::WireTableBuilder<fir_fidl::InputReport>& input_report, fidl::AnyArena& allocator) const {
auto sensor_report = fir_fidl::SensorInputReport::Builder(allocator);
fidl::VectorView<int64_t> values(allocator, 3);
// Raw sensor reading uses unit |rad/s|, while InputReport uses unit
// |deg/s * 1e-2| and only accepts integer.
// This converts the sensor reading to InputReport values.
constexpr auto SensorReadingToFidlReportValue = [](float reading) -> int {
return static_cast<int>(reading * 180 / M_PI * 100);
};
values[0] = SensorReadingToFidlReportValue(x);
values[1] = SensorReadingToFidlReportValue(y);
values[2] = SensorReadingToFidlReportValue(z);
sensor_report.values(values);
input_report.event_time(event_time.get());
input_report.sensor(sensor_report.Build());
}
fpromise::result<InputDevice*, zx_status_t> GyroscopeInputDevice::Create(
RootDevice* sensor, async_dispatcher_t* dispatcher) {
// Parent device (sensor) is guaranteed to outlive the child input device
// (dev), so it's safe to use raw pointers here.
auto device = std::make_unique<GyroscopeInputDevice>(
sensor->zxdev(), dispatcher,
[sensor](InputDevice* dev) { sensor->input_devices()->RemoveDevice(dev); });
zx_status_t status;
if ((status = device->DdkAdd("goldfish-sensor-gyroscope")) != ZX_OK) {
return fpromise::error(status);
}
// Device will be owned by devmgr.
return fpromise::ok(device.release());
}
zx_status_t GyroscopeInputDevice::OnReport(const SensorReport& rpt) {
InputReport input_report;
input_report.event_time = zx::clock::get_monotonic();
if (rpt.data.size() != 3 && rpt.data.size() != 3 + kMeasurementIdSize) {
zxlogf(ERROR, "GyroscopeInputDevice: invalid data size: %lu", rpt.data.size());
return ZX_ERR_INVALID_ARGS;
}
if (auto p = std::get_if<Numeric>(&rpt.data[0]); p != nullptr) {
input_report.x = static_cast<float>(p->Double());
} else {
zxlogf(ERROR, "GyroscopeInputDevice: invalid x");
return ZX_ERR_INVALID_ARGS;
}
if (auto p = std::get_if<Numeric>(&rpt.data[1]); p != nullptr) {
input_report.y = static_cast<float>(p->Double());
} else {
zxlogf(ERROR, "GyroscopeInputDevice: invalid y");
return ZX_ERR_INVALID_ARGS;
}
if (auto p = std::get_if<Numeric>(&rpt.data[2]); p != nullptr) {
input_report.z = static_cast<float>(p->Double());
} else {
zxlogf(ERROR, "GyroscopeInputDevice: invalid z");
return ZX_ERR_INVALID_ARGS;
}
input_report_readers_.SendReportToAllReaders(input_report);
return ZX_OK;
}
void GyroscopeInputDevice::GetDescriptor(GetDescriptorCompleter::Sync& completer) {
constexpr size_t kDescriptorBufferSize = 512;
constexpr fir_fidl::Axis kAxis = {
.range = {.min = INT64_MIN, .max = INT64_MAX},
// unit: 0.01 deg/s
.unit = {.type = fir_fidl::UnitType::kEnglishAngularVelocity, .exponent = -2},
};
fidl::Arena<kDescriptorBufferSize> allocator;
auto device_info = fir_fidl::DeviceInformation::Builder(allocator);
device_info.vendor_id(static_cast<uint32_t>(fir_fidl::VendorId::kGoogle));
device_info.product_id(
static_cast<uint32_t>(fir_fidl::VendorGoogleProductId::kGoldfishGyroscopeSensor));
fidl::VectorView<fir_fidl::SensorAxis> sensor_axes(allocator, 3);
sensor_axes[0].axis = kAxis;
sensor_axes[1].axis = kAxis;
sensor_axes[2].axis = kAxis;
sensor_axes[0].type = fir_fidl::SensorType::kGyroscopeX;
sensor_axes[1].type = fir_fidl::SensorType::kGyroscopeY;
sensor_axes[2].type = fir_fidl::SensorType::kGyroscopeZ;
fidl::VectorView<fir_fidl::SensorInputDescriptor> sensor_input_descriptor(allocator, 1);
sensor_input_descriptor[0] =
fir_fidl::SensorInputDescriptor::Builder(allocator).values(sensor_axes).Build();
auto sensor_descriptor = fir_fidl::SensorDescriptor::Builder(allocator);
sensor_descriptor.input(sensor_input_descriptor);
auto descriptor = fir_fidl::DeviceDescriptor::Builder(allocator);
descriptor.device_information(device_info.Build());
descriptor.sensor(sensor_descriptor.Build());
completer.Reply(descriptor.Build());
}
void GyroscopeInputDevice::GetInputReportsReader(GetInputReportsReaderRequestView request,
GetInputReportsReaderCompleter::Sync& completer) {
zx_status_t status = input_report_readers_.CreateReader(dispatcher(), std::move(request->reader));
ZX_DEBUG_ASSERT(status == ZX_OK);
}
void RgbcLightInputDevice::InputReport::ToFidlInputReport(
fidl::WireTableBuilder<fir_fidl::InputReport>& input_report, fidl::AnyArena& allocator) const {
auto sensor_report = fir_fidl::SensorInputReport::Builder(allocator);
fidl::VectorView<int64_t> values(allocator, 4);
values[0] = static_cast<int64_t>(r);
values[1] = static_cast<int64_t>(g);
values[2] = static_cast<int64_t>(b);
values[3] = static_cast<int64_t>(c);
sensor_report.values(values);
input_report.event_time(event_time.get());
input_report.sensor(sensor_report.Build());
}
fpromise::result<InputDevice*, zx_status_t> RgbcLightInputDevice::Create(
RootDevice* sensor, async_dispatcher_t* dispatcher) {
// Parent device (sensor) is guaranteed to outlive the child input device
// (dev), so it's safe to use raw pointers here.
auto device = std::make_unique<RgbcLightInputDevice>(
sensor->zxdev(), dispatcher,
[sensor](InputDevice* dev) { sensor->input_devices()->RemoveDevice(dev); });
zx_status_t status;
if ((status = device->DdkAdd("goldfish-sensor-rgbclight")) != ZX_OK) {
return fpromise::error(status);
}
// Device will be owned by devmgr.
return fpromise::ok(device.release());
}
zx_status_t RgbcLightInputDevice::OnReport(const SensorReport& rpt) {
InputReport input_report;
input_report.event_time = zx::clock::get_monotonic();
if (rpt.data.size() != 4 && rpt.data.size() != 4 + kMeasurementIdSize) {
zxlogf(ERROR, "RgbcLightInputDevice: invalid data size: %lu", rpt.data.size());
return ZX_ERR_INVALID_ARGS;
}
if (auto p = std::get_if<Numeric>(&rpt.data[0]); p != nullptr) {
input_report.r = static_cast<float>(p->Double());
} else {
zxlogf(ERROR, "RgbcLightInputDevice: invalid r");
return ZX_ERR_INVALID_ARGS;
}
if (auto p = std::get_if<Numeric>(&rpt.data[1]); p != nullptr) {
input_report.g = static_cast<float>(p->Double());
} else {
zxlogf(ERROR, "RgbcLightInputDevice: invalid g");
return ZX_ERR_INVALID_ARGS;
}
if (auto p = std::get_if<Numeric>(&rpt.data[2]); p != nullptr) {
input_report.b = static_cast<float>(p->Double());
} else {
zxlogf(ERROR, "RgbcLightInputDevice: invalid b");
return ZX_ERR_INVALID_ARGS;
}
if (auto p = std::get_if<Numeric>(&rpt.data[3]); p != nullptr) {
input_report.c = static_cast<float>(p->Double());
} else {
zxlogf(ERROR, "RgbcLightInputDevice: invalid c");
return ZX_ERR_INVALID_ARGS;
}
input_report_readers_.SendReportToAllReaders(input_report);
return ZX_OK;
}
void RgbcLightInputDevice::GetDescriptor(GetDescriptorCompleter::Sync& completer) {
constexpr size_t kDescriptorBufferSize = 512;
constexpr fir_fidl::Axis kAxis = {
.range = {.min = 0, .max = UINT16_MAX},
.unit = {.type = fir_fidl::UnitType::kNone},
};
fidl::Arena<kDescriptorBufferSize> allocator;
auto device_info = fir_fidl::DeviceInformation::Builder(allocator);
device_info.vendor_id(static_cast<uint32_t>(fir_fidl::VendorId::kGoogle));
device_info.product_id(
static_cast<uint32_t>(fir_fidl::VendorGoogleProductId::kGoldfishRgbcLightSensor));
fidl::VectorView<fir_fidl::SensorAxis> sensor_axes(allocator, 4);
sensor_axes[0].axis = kAxis;
sensor_axes[1].axis = kAxis;
sensor_axes[2].axis = kAxis;
sensor_axes[3].axis = kAxis;
sensor_axes[0].type = fir_fidl::SensorType::kLightRed;
sensor_axes[1].type = fir_fidl::SensorType::kLightGreen;
sensor_axes[2].type = fir_fidl::SensorType::kLightBlue;
sensor_axes[3].type = fir_fidl::SensorType::kLightIlluminance;
fidl::VectorView<fir_fidl::SensorInputDescriptor> sensor_input_descriptor(allocator, 1);
sensor_input_descriptor[0] =
fir_fidl::SensorInputDescriptor::Builder(allocator).values(sensor_axes).Build();
auto sensor_descriptor = fir_fidl::SensorDescriptor::Builder(allocator);
sensor_descriptor.input(sensor_input_descriptor);
auto descriptor = fir_fidl::DeviceDescriptor::Builder(allocator);
descriptor.device_information(device_info.Build());
descriptor.sensor(sensor_descriptor.Build());
completer.Reply(descriptor.Build());
}
void RgbcLightInputDevice::GetInputReportsReader(GetInputReportsReaderRequestView request,
GetInputReportsReaderCompleter::Sync& completer) {
zx_status_t status = input_report_readers_.CreateReader(dispatcher(), std::move(request->reader));
ZX_DEBUG_ASSERT(status == ZX_OK);
}
} // namespace goldfish::sensor