| // 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 <fuchsia/input/report/llcpp/fidl.h> |
| #include <lib/async/dispatcher.h> |
| #include <lib/ddk/debug.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 { |
| |
| 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(fir_fidl::InputReport& input_report, |
| fidl::AnyAllocator& allocator) { |
| fir_fidl::SensorInputReport sensor_report(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.set_values(allocator, std::move(values)); |
| |
| input_report.set_event_time(allocator, event_time.get()); |
| input_report.set_sensor(allocator, std::move(sensor_report)); |
| } |
| |
| fit::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 fit::error(status); |
| } |
| |
| // Device will be owned by devmgr. |
| return fit::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) { |
| 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(GetDescriptorRequestView request, |
| 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::FidlAllocator<kDescriptorBufferSize> allocator; |
| |
| fir_fidl::DeviceInfo device_info; |
| 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 = sensor_axes[1].axis = 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; |
| |
| fir_fidl::SensorInputDescriptor sensor_input_descriptor(allocator); |
| sensor_input_descriptor.set_values(allocator, std::move(sensor_axes)); |
| |
| fir_fidl::SensorDescriptor sensor_descriptor(allocator); |
| sensor_descriptor.set_input(allocator, std::move(sensor_input_descriptor)); |
| |
| fir_fidl::DeviceDescriptor descriptor(allocator); |
| descriptor.set_device_info(allocator, std::move(device_info)); |
| descriptor.set_sensor(allocator, std::move(sensor_descriptor)); |
| |
| completer.Reply(std::move(descriptor)); |
| } |
| |
| 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(fir_fidl::InputReport& input_report, |
| fidl::AnyAllocator& allocator) { |
| fir_fidl::SensorInputReport sensor_report(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.set_values(allocator, std::move(values)); |
| |
| input_report.set_event_time(allocator, event_time.get()); |
| input_report.set_sensor(allocator, std::move(sensor_report)); |
| } |
| |
| fit::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 fit::error(status); |
| } |
| |
| // Device will be owned by devmgr. |
| return fit::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) { |
| 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(GetDescriptorRequestView request, |
| 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::FidlAllocator<kDescriptorBufferSize> allocator; |
| |
| fir_fidl::DeviceInfo device_info; |
| 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 = sensor_axes[1].axis = 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; |
| |
| fir_fidl::SensorInputDescriptor sensor_input_descriptor(allocator); |
| sensor_input_descriptor.set_values(allocator, std::move(sensor_axes)); |
| |
| fir_fidl::SensorDescriptor sensor_descriptor(allocator); |
| sensor_descriptor.set_input(allocator, std::move(sensor_input_descriptor)); |
| |
| fir_fidl::DeviceDescriptor descriptor(allocator); |
| descriptor.set_device_info(allocator, std::move(device_info)); |
| descriptor.set_sensor(allocator, std::move(sensor_descriptor)); |
| |
| completer.Reply(std::move(descriptor)); |
| } |
| |
| 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); |
| } |
| |
| } // namespace goldfish::sensor |