| // Copyright 2019 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 "garnet/bin/ui/input_reader/sensor.h" |
| |
| #include <hid-parser/parser.h> |
| #include <hid-parser/report.h> |
| #include <hid-parser/units.h> |
| #include <hid-parser/usages.h> |
| |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <vector> |
| |
| #include <lib/fxl/logging.h> |
| |
| namespace { |
| |
| bool IsXUsage(const hid::Usage& u) { |
| return (u == hid::USAGE(hid::usage::Page::kSensor, |
| hid::usage::Sensor::kAccelerationAxisX)) || |
| (u == hid::USAGE(hid::usage::Page::kSensor, |
| hid::usage::Sensor::kDistanceAxisX)) || |
| (u == hid::USAGE(hid::usage::Page::kSensor, |
| hid::usage::Sensor::kTiltAxisX)) || |
| (u == hid::USAGE(hid::usage::Page::kSensor, |
| hid::usage::Sensor::kMagneticFluxAxisX)); |
| } |
| |
| bool IsYUsage(const hid::Usage& u) { |
| return (u == hid::USAGE(hid::usage::Page::kSensor, |
| hid::usage::Sensor::kAccelerationAxisY)) || |
| (u == hid::USAGE(hid::usage::Page::kSensor, |
| hid::usage::Sensor::kDistanceAxisY)) || |
| (u == hid::USAGE(hid::usage::Page::kSensor, |
| hid::usage::Sensor::kTiltAxisY)) || |
| (u == hid::USAGE(hid::usage::Page::kSensor, |
| hid::usage::Sensor::kMagneticFluxAxisY)); |
| } |
| |
| bool IsZUsage(const hid::Usage& u) { |
| return (u == hid::USAGE(hid::usage::Page::kSensor, |
| hid::usage::Sensor::kAccelerationAxisZ)) || |
| (u == hid::USAGE(hid::usage::Page::kSensor, |
| hid::usage::Sensor::kDistanceAxisZ)) || |
| (u == hid::USAGE(hid::usage::Page::kSensor, |
| hid::usage::Sensor::kTiltAxisZ)) || |
| (u == hid::USAGE(hid::usage::Page::kSensor, |
| hid::usage::Sensor::kMagneticFluxAxisZ)); |
| } |
| |
| } // namespace |
| |
| namespace mozart { |
| |
| bool Sensor::ParseReportDescriptor( |
| const hid::ReportDescriptor& report_descriptor, |
| Descriptor* device_descriptor) { |
| FXL_CHECK(device_descriptor); |
| |
| fuchsia::ui::input::SensorType sensor_type; |
| hid::Attributes x = {}; |
| hid::Attributes y = {}; |
| hid::Attributes z = {}; |
| hid::Attributes scalar = {}; |
| uint32_t caps = 0; |
| |
| auto sensor_usage = report_descriptor.input_fields[0].col->usage; |
| if (sensor_usage == hid::USAGE(hid::usage::Page::kSensor, |
| hid::usage::Sensor::kAccelerometer3D)) { |
| sensor_type = fuchsia::ui::input::SensorType::ACCELEROMETER; |
| |
| } else if (sensor_usage == hid::USAGE(hid::usage::Page::kSensor, |
| hid::usage::Sensor::kGyrometer3D)) { |
| sensor_type = fuchsia::ui::input::SensorType::GYROSCOPE; |
| |
| } else if (sensor_usage == hid::USAGE(hid::usage::Page::kSensor, |
| hid::usage::Sensor::kMagnetometer)) { |
| sensor_type = fuchsia::ui::input::SensorType::MAGNETOMETER; |
| |
| } else if (sensor_usage == hid::USAGE(hid::usage::Page::kSensor, |
| hid::usage::Sensor::kAmbientLight)) { |
| sensor_type = fuchsia::ui::input::SensorType::LIGHTMETER; |
| |
| } else { |
| FXL_LOG(ERROR) << "Sensor report descriptor: Sensor page not supported (0x" |
| << std::hex << sensor_usage.usage << ")"; |
| return false; |
| } |
| |
| for (size_t i = 0; i < report_descriptor.input_count; i++) { |
| const hid::ReportField& field = report_descriptor.input_fields[i]; |
| |
| if (IsXUsage(field.attr.usage)) { |
| x = field.attr; |
| caps |= Capabilities::X; |
| } else if (IsYUsage(field.attr.usage)) { |
| y = field.attr; |
| caps |= Capabilities::Y; |
| } else if (IsZUsage(field.attr.usage)) { |
| z = field.attr; |
| caps |= Capabilities::Z; |
| } else { |
| // At this point, any non X, Y, Z fields in a sensor are put into |
| // scalar. InputReport only supports a single scalar so we will |
| // pick the last value we see. |
| scalar = field.attr; |
| caps |= Capabilities::SCALAR; |
| } |
| } |
| |
| if ((caps & Capabilities::SCALAR) && |
| (caps & (Capabilities::X | Capabilities::Y | Capabilities::Z))) { |
| FXL_LOG(ERROR) << "Sensor report descriptor: Sensor describes Axis and " |
| "Scalar, must only describe one"; |
| return false; |
| } |
| |
| if (caps == 0) { |
| FXL_LOG(ERROR) << "Sensor report descriptor: Sensor has no capabilities"; |
| return false; |
| } |
| |
| // TODO(SCN-1312): In order to get min sampling rate, max sampling rate, |
| // phys_min, and phys_max, we will need to see example reports of how these |
| // things are set. This is currently not supported by the hardcoded sensors |
| // either. |
| |
| x_ = x; |
| y_ = y; |
| z_ = z; |
| scalar_ = scalar; |
| capabilities_ = caps; |
| |
| report_size_ = report_descriptor.input_byte_sz; |
| report_id_ = report_descriptor.report_id; |
| |
| // Set the device descriptor. |
| device_descriptor->protocol = Protocol::Sensor; |
| device_descriptor->has_sensor = true; |
| device_descriptor->sensor_descriptor = |
| fuchsia::ui::input::SensorDescriptor::New(); |
| device_descriptor->sensor_descriptor->type = sensor_type; |
| return true; |
| } |
| |
| bool Sensor::ParseReport(const uint8_t* data, size_t len, |
| fuchsia::ui::input::InputReport* report) { |
| FXL_CHECK(report); |
| FXL_CHECK(report->sensor); |
| double x = 0; |
| double y = 0; |
| double z = 0; |
| double scalar = 0; |
| |
| if (report_size_ != len) { |
| FXL_LOG(ERROR) << "Sensor report: Expected size " << report_size_ |
| << "Recieved size " << len; |
| return false; |
| } |
| |
| if (capabilities_ & Capabilities::X) { |
| if (!hid::ExtractAsUnit(data, len, x_, &x)) { |
| FXL_LOG(ERROR) << "Sensor report: Failed to parse X"; |
| return false; |
| } |
| } |
| if (capabilities_ & Capabilities::Y) { |
| if (!hid::ExtractAsUnit(data, len, y_, &y)) { |
| FXL_LOG(ERROR) << "Sensor report: Failed to parse Y"; |
| return false; |
| } |
| } |
| if (capabilities_ & Capabilities::Z) { |
| if (!hid::ExtractAsUnit(data, len, z_, &z)) { |
| FXL_LOG(ERROR) << "Sensor report: Failed to parse Z"; |
| return false; |
| } |
| } |
| if (capabilities_ & Capabilities::SCALAR) { |
| if (!hid::ExtractAsUnit(data, len, scalar_, &scalar)) { |
| FXL_LOG(ERROR) << "Sensor report: Failed to parse Scalar"; |
| return false; |
| } |
| } |
| |
| FXL_DCHECK(x >= INT16_MIN && x <= INT16_MAX) |
| << "X sensor value is truncated."; |
| FXL_DCHECK(y >= INT16_MIN && y <= INT16_MAX) |
| << "Y sensor value is truncated."; |
| FXL_DCHECK(z >= INT16_MIN && z <= INT16_MAX) |
| << "Z sensor value is truncated."; |
| |
| if (capabilities_ & (Capabilities::X | Capabilities::Y | Capabilities::Z)) { |
| fidl::Array<int16_t, 3> axis; |
| axis[0] = x; |
| axis[1] = y; |
| axis[2] = z; |
| report->sensor->set_vector(std::move(axis)); |
| } else if (capabilities_ & Capabilities::SCALAR) { |
| report->sensor->set_scalar(scalar); |
| } |
| |
| return true; |
| } |
| |
| } // namespace mozart |