blob: fa37fe621c913d839f91eb3a11483e0e3d2c6a86 [file] [log] [blame]
// 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