HID dynamic sensor: add support to three types of sensor am: 4715d1734d

am: 852a75717d

Change-Id: I27ab261f0a6d859a74241fb03bffd572e71f4b47
This commit is contained in:
Peng Xu 2017-04-21 17:19:16 +00:00 committed by android-build-merger
commit fada5a0a18
24 changed files with 2545 additions and 61 deletions

View file

@ -15,6 +15,24 @@
LOCAL_PATH := $(call my-dir)
COMMON_CFLAGS := -Wall -Werror -Wextra
dynamic_sensor_src := \
BaseDynamicSensorDaemon.cpp \
BaseSensorObject.cpp \
ConnectionDetector.cpp \
DummyDynamicAccelDaemon.cpp \
DynamicSensorManager.cpp \
HidRawDevice.cpp \
HidRawSensor.cpp \
HidRawSensorDaemon.cpp \
HidRawSensorDevice.cpp \
RingBuffer.cpp
dynamic_sensor_shared_lib := \
libbase \
libcutils \
libhidparser \
liblog \
libutils
#
# There are two ways to utilize the dynamic sensor module:
# 1. Use as an extension in an existing hal: declare dependency on libdynamic_sensor_ext shared
@ -25,7 +43,6 @@ COMMON_CFLAGS := -Wall -Werror -Wextra
#
# Please take only one of these two options to avoid conflict over hardware resource.
#
#
# Option 1: sensor extension module
#
@ -37,18 +54,9 @@ LOCAL_PROPRIETARY_MODULE := true
LOCAL_CFLAGS += $(COMMON_CFLAGS) -DLOG_TAG=\"DynamicSensorExt\"
LOCAL_SRC_FILES := \
BaseDynamicSensorDaemon.cpp \
BaseSensorObject.cpp \
ConnectionDetector.cpp \
DummyDynamicAccelDaemon.cpp \
DynamicSensorManager.cpp \
RingBuffer.cpp
LOCAL_SRC_FILES := $(dynamic_sensor_src)
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
liblog
LOCAL_SHARED_LIBRARIES := $(dynamic_sensor_shared_lib)
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
@ -66,23 +74,53 @@ LOCAL_PROPRIETARY_MODULE := true
LOCAL_CFLAGS += $(COMMON_CFLAGS) -DLOG_TAG=\"DynamicSensorHal\"
LOCAL_SRC_FILES := \
BaseDynamicSensorDaemon.cpp \
BaseSensorObject.cpp \
ConnectionDetector.cpp \
DummyDynamicAccelDaemon.cpp \
DynamicSensorManager.cpp \
RingBuffer.cpp \
sensors.cpp
LOCAL_SRC_FILES := $(dynamic_sensor_src) sensors.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
liblog
LOCAL_SHARED_LIBRARIES := $(dynamic_sensor_shared_lib)
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
include $(BUILD_SHARED_LIBRARY)
include $(LOCAL_PATH)/HidUtils/Android.mk
#
# Host test for HidRawSensor. Test with dummy test HID descriptors.
#
include $(CLEAR_VARS)
LOCAL_MODULE := hidrawsensor_host_test
LOCAL_MODULE_TAGS := optional
LOCAL_CFLAGS += $(COMMON_CFLAGS)
LOCAL_SRC_FILES := \
HidRawSensor.cpp \
BaseSensorObject.cpp \
HidUtils/test/TestHidDescriptor.cpp \
test/HidRawSensorTest.cpp
LOCAL_SHARED_LIBRARIES := libhidparser_host
LOCAL_C_INCLUDES += $(LOCAL_PATH)/test $(LOCAL_PATH)/HidUtils/test
include $(BUILD_HOST_EXECUTABLE)
#
# Host test for HidRawDevice and HidRawSensor. Test with hidraw
# device node.
#
include $(CLEAR_VARS)
LOCAL_MODULE := hidrawdevice_host_test
LOCAL_MODULE_TAGS := optional
LOCAL_CFLAGS += $(COMMON_CFLAGS)
LOCAL_SRC_FILES := \
HidRawDevice.cpp \
HidRawSensor.cpp \
BaseSensorObject.cpp \
test/HidRawDeviceTest.cpp
LOCAL_SHARED_LIBRARIES := libhidparser_host
LOCAL_C_INCLUDES += $(LOCAL_PATH)/test $(LOCAL_PATH)/HidUtils/test
include $(BUILD_HOST_EXECUTABLE)
include $(LOCAL_PATH)/HidUtils/Android.mk

View file

@ -23,14 +23,23 @@ namespace SensorHalExt {
bool BaseDynamicSensorDaemon::onConnectionChange(const std::string &deviceKey, bool connected) {
bool ret = false;
auto i = mDevices.find(deviceKey);
auto i = mDeviceKeySensorMap.find(deviceKey);
if (connected) {
if (i == mDevices.end()) {
if (i == mDeviceKeySensorMap.end()) {
ALOGV("device %s is connected", deviceKey.c_str());
BaseSensorObject* s = createSensor(deviceKey);
if (s) {
mDevices.emplace(deviceKey, sp<BaseSensorObject>(s));
mManager.registerSensor(s);
// get sensors from implementation
BaseSensorVector sensors = createSensor(deviceKey);
if (sensors.empty()) {
ALOGI("no valid sensor is defined in device %s, ignore", deviceKey.c_str());
} else {
ALOGV("discovered %zu sensors from device", sensors.size());
// build internal table first
auto result = mDeviceKeySensorMap.emplace(deviceKey, std::move(sensors));
// then register sensor to dynamic sensor manager, result.first is the iterator
// of key-value pair; result.first->second is the value, which is s.
for (auto &i : result.first->second) {
mManager.registerSensor(i);
}
ALOGV("device %s is registered", deviceKey.c_str());
ret = true;
}
@ -39,13 +48,18 @@ bool BaseDynamicSensorDaemon::onConnectionChange(const std::string &deviceKey, b
}
} else {
ALOGV("device %s is disconnected", deviceKey.c_str());
if (i != mDevices.end()) {
mManager.unregisterSensor(i->second.get());
mDevices.erase(i);
if (i != mDeviceKeySensorMap.end()) {
BaseSensorVector sensors = i->second;
for (auto &sensor : sensors) {
mManager.unregisterSensor(sensor);
}
mDeviceKeySensorMap.erase(i);
// notify implementation
removeSensor(deviceKey);
ALOGV("device %s is unregistered", deviceKey.c_str());
ret = true;
} else {
ALOGD("device not found in registry");
ALOGV("device not found in registry");
}
}

View file

@ -28,6 +28,8 @@ namespace SensorHalExt {
class DynamicSensorManager;
typedef std::vector<sp<BaseSensorObject>> BaseSensorVector;
class BaseDynamicSensorDaemon : public RefBase {
public:
BaseDynamicSensorDaemon(DynamicSensorManager& manager) : mManager(manager) {}
@ -35,10 +37,11 @@ public:
virtual bool onConnectionChange(const std::string &deviceKey, bool connected);
protected:
virtual BaseSensorObject * createSensor(const std::string &deviceKey) = 0;
virtual BaseSensorVector createSensor(const std::string &deviceKey) = 0;
virtual void removeSensor(const std::string &/*deviceKey*/) {};
DynamicSensorManager &mManager;
std::unordered_map<std::string, sp<BaseSensorObject> > mDevices;
std::unordered_map<std::string, BaseSensorVector> mDeviceKeySensorMap;
};
} // namespace SensorHalExt

View file

@ -16,8 +16,8 @@
#include "BaseSensorObject.h"
#include "SensorEventCallback.h"
#include "Utils.h"
#include <utils/Log.h>
#include <cstring>
namespace android {
@ -28,7 +28,6 @@ BaseSensorObject::BaseSensorObject() : mCallback(nullptr) {
bool BaseSensorObject::setEventCallback(SensorEventCallback* callback) {
if (mCallback != nullptr) {
ALOGE("callback is already assigned, cannot change.");
return false;
}
mCallback = callback;
@ -51,7 +50,7 @@ int BaseSensorObject::flush() {
void BaseSensorObject::generateEvent(const sensors_event_t &e) {
if (mCallback) {
mCallback->submitEvent(this, e);
mCallback->submitEvent(SP_THIS, e);
}
}

View file

@ -17,8 +17,7 @@
#ifndef ANDROID_SENSORHAL_BASE_SENSOR_OBJECT_H
#define ANDROID_SENSORHAL_BASE_SENSOR_OBJECT_H
#include <utils/RefBase.h>
#include <utils/Timers.h> // for nsecs_t
#include "Utils.h"
#include <cstdint>
struct sensor_t;
@ -29,7 +28,7 @@ namespace SensorHalExt {
class SensorEventCallback;
class BaseSensorObject : virtual public RefBase {
class BaseSensorObject : virtual public REF_BASE(BaseSensorObject) {
public:
BaseSensorObject();
virtual ~BaseSensorObject() = default;
@ -48,7 +47,8 @@ public:
virtual int enable(bool enable) = 0;
// set sample period and batching period of sensor.
virtual int batch(nsecs_t samplePeriod, nsecs_t batchPeriod) = 0;
// both sample period and batch period are in nano-seconds.
virtual int batch(int64_t samplePeriod, int64_t batchPeriod) = 0;
// flush sensor, default implementation will send a flush complete event back.
virtual int flush();

View file

@ -31,7 +31,7 @@ namespace SensorHalExt {
// SocketConnectionDetector functions
SocketConnectionDetector::SocketConnectionDetector(BaseDynamicSensorDaemon *d, int port)
: ConnectionDetector(d) {
: ConnectionDetector(d), Thread(false /*canCallJava*/) {
// initialize socket that accept connection to localhost:port
mListenFd = ::socket(AF_INET, SOCK_STREAM, 0);
if (mListenFd < 0) {
@ -105,7 +105,7 @@ bool SocketConnectionDetector::threadLoop() {
// FileConnectionDetector functions
FileConnectionDetector::FileConnectionDetector (
BaseDynamicSensorDaemon *d, const std::string &path, const std::string &regex)
: ConnectionDetector(d), mPath(path), mRegex(regex) {
: ConnectionDetector(d), Thread(false /*callCallJava*/), mPath(path), mRegex(regex) {
mInotifyFd = ::inotify_init1(IN_NONBLOCK);
if (mInotifyFd < 0) {
ALOGE("Cannot init inotify");

View file

@ -51,23 +51,30 @@ DummyDynamicAccelDaemon::DummyDynamicAccelDaemon(DynamicSensorManager& manager)
}
}
BaseSensorObject * DummyDynamicAccelDaemon::createSensor(const std::string &deviceKey) {
BaseSensorVector DummyDynamicAccelDaemon::createSensor(const std::string &deviceKey) {
BaseSensorVector ret;
if (deviceKey.compare(0, 1, "/") == 0) {
// file detector result, deviceKey is file absolute path
size_t start = std::max(static_cast<size_t>(0),
deviceKey.length() - (::strlen(FILE_NAME_BASE) + 1));
return new DummySensor(deviceKey.substr(start));
const size_t len = ::strlen(FILE_NAME_BASE) + 1; // +1 for number
if (deviceKey.length() < len) {
ALOGE("illegal file device key %s", deviceKey.c_str());
} else {
size_t start = deviceKey.length() - len;
ret.emplace_back(new DummySensor(deviceKey.substr(start)));
}
} else if (deviceKey.compare(0, ::strlen("socket:"), "socket:") == 0) {
return new DummySensor(deviceKey);
ret.emplace_back(new DummySensor(deviceKey));
} else {
// unknown deviceKey
return nullptr;
ALOGE("unknown deviceKey: %s", deviceKey.c_str());
}
return ret;
}
DummyDynamicAccelDaemon::DummySensor::DummySensor(const std::string &name) : mRunState(false) {
DummyDynamicAccelDaemon::DummySensor::DummySensor(const std::string &name)
: Thread(false /*canCallJava*/), mRunState(false) {
mSensorName = "Dummy Accel - " + name;
// fake sensor information for dummy sensor
mSensor = (struct sensor_t) {
mSensorName.c_str(),
"DemoSense, Inc.",
@ -120,7 +127,8 @@ int DummyDynamicAccelDaemon::DummySensor::enable(bool enable) {
return 0;
}
int DummyDynamicAccelDaemon::DummySensor::batch(nsecs_t, nsecs_t) {
int DummyDynamicAccelDaemon::DummySensor::batch(int64_t /*samplePeriod*/, int64_t /*batchPeriod*/) {
// Dummy sensor does not support changing rate and batching. But return successful anyway.
return 0;
}

View file

@ -61,7 +61,7 @@ private:
bool mRunState;
};
// implement BaseDynamicSensorDaemon function
BaseSensorObject * createSensor(const std::string &deviceKey) override;
virtual BaseSensorVector createSensor(const std::string &deviceKey) override;
sp<ConnectionDetector> mFileDetector;
sp<ConnectionDetector> mSocketDetector;

View file

@ -17,6 +17,7 @@
#include "BaseDynamicSensorDaemon.h"
#include "BaseSensorObject.h"
#include "DummyDynamicAccelDaemon.h"
#include "HidRawSensorDaemon.h"
#include "DynamicSensorManager.h"
#include <utils/Log.h>
@ -31,6 +32,7 @@ DynamicSensorManager* DynamicSensorManager::createInstance(
int handleBase, int handleCount, SensorEventCallback *callback) {
auto m = new DynamicSensorManager(handleBase, handleBase + handleCount - 1, callback);
m->mDaemonVector.push_back(new DummyDynamicAccelDaemon(*m));
m->mDaemonVector.push_back(new HidRawSensorDaemon(*m));
return m;
}
@ -107,7 +109,7 @@ int DynamicSensorManager::setDelay(int handle, nsecs_t sample_period) {
int DynamicSensorManager::flush(int handle) {
if (handle == mHandleRange.first) {
// TODO: submit a flush complete here
// submit a flush complete here
static const sensors_event_t event = {
.type = SENSOR_TYPE_META_DATA,
.sensor = mHandleRange.first,

View file

@ -123,7 +123,7 @@ private:
// mapping between handle and SensorObjects
mutable std::mutex mLock;
int mNextHandle;
std::unordered_map<int, wp<BaseSensorObject> > mMap;
std::unordered_map<int, wp<BaseSensorObject>> mMap;
std::unordered_map<void *, int> mReverseMap;
mutable std::unordered_map<int, ConnectionReport> mPendingReport;

View file

@ -0,0 +1,57 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_SENSORHAL_EXT_HID_DEVICE_H
#define ANDROID_SENSORHAL_EXT_HID_DEVICE_H
#include "Utils.h"
#include <string>
#include <vector>
#include <unordered_set>
namespace android {
namespace SensorHalExt {
class HidDevice : virtual public REF_BASE(HidDevice) {
public:
virtual ~HidDevice() = default;
struct HidDeviceInfo {
std::string name;
std::string physicalPath;
std::string busType;
uint16_t vendorId;
uint16_t productId;
std::vector<uint8_t> descriptor;
};
virtual const HidDeviceInfo& getDeviceInfo() = 0;
// get feature from device
virtual bool getFeature(uint8_t id, std::vector<uint8_t> *out) = 0;
// write feature to device
virtual bool setFeature(uint8_t id, const std::vector<uint8_t> &in) = 0;
// send report to default output endpoint
virtual bool sendReport(uint8_t id, std::vector<uint8_t> &data) = 0;
// receive from default input endpoint
virtual bool receiveReport(uint8_t *id, std::vector<uint8_t> *data) = 0;
};
} // namespace SensorHalExt
} // namespace android
#endif // ANDROID_SENSORHAL_EXT_HID_DEVICE_H

View file

@ -0,0 +1,332 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "HidRawDevice.h"
#include "HidLog.h"
#include "Utils.h"
#include <fcntl.h>
#include <linux/input.h>
#include <linux/hidraw.h>
#include <linux/hiddev.h> // HID_STRING_SIZE
#include <sys/ioctl.h>
#include <unistd.h>
#include <set>
namespace android {
namespace SensorHalExt {
using HidUtil::HidItem;
HidRawDevice::HidRawDevice(
const std::string &devName, const std::unordered_set<unsigned int> &usageSet)
: mDevFd(-1), mMultiIdDevice(false), mValid(false) {
// open device
mDevFd = ::open(devName.c_str(), O_RDWR); // read write?
if (mDevFd < 0) {
LOG_E << "Error in open device node: " << errno << " (" << ::strerror(errno) << ")"
<< LOG_ENDL;
return;
}
// get device information, including hid descriptor
if (!populateDeviceInfo()) {
LOG_E << "Error obtaining HidRaw device information" << LOG_ENDL;
return;
}
if (!generateDigest(usageSet)) {
LOG_E << "Cannot parse hid descriptor" << LOG_ENDL;
return;
}
// digest error checking
std::unordered_set<unsigned int> reportIdSet;
for (auto const &digest : mDigestVector) {
for (auto const &packet : digest.packets) {
if (mReportTypeIdMap.emplace(
std::make_pair(packet.type, packet.id), &packet).second == false) {
LOG_E << "Same type - report id pair (" << packet.type << ", " << packet.id << ")"
<< "is used by more than one usage collection" << LOG_ENDL;
return;
}
reportIdSet.insert(packet.id);
}
}
if (mReportTypeIdMap.empty()) {
return;
}
if (reportIdSet.size() > 1) {
if (reportIdSet.find(0) != reportIdSet.end()) {
LOG_E << "Default report id 0 is not expected when more than one report id is found."
<< LOG_ENDL;
return;
}
mMultiIdDevice = true;
} else { // reportIdSet.size() == 1
mMultiIdDevice = !(reportIdSet.find(0) != reportIdSet.end());
}
mValid = true;
}
HidRawDevice::~HidRawDevice() {
if (mDevFd > 0) {
::close(mDevFd);
mDevFd = -1;
}
}
bool HidRawDevice::populateDeviceInfo() {
HidDeviceInfo info;
char buffer[HID_STRING_SIZE + 1];
if (mDevFd < 0) {
return false;
}
// name
if (ioctl(mDevFd, HIDIOCGRAWNAME(sizeof(buffer) - 1), buffer) < 0) {
return false;
}
buffer[sizeof(buffer) - 1] = '\0';
info.name = buffer;
// physical path
if (ioctl(mDevFd, HIDIOCGRAWPHYS(sizeof(buffer) - 1), buffer) < 0) {
return false;
}
buffer[sizeof(buffer) - 1] = '\0';
info.physicalPath = buffer;
// raw device info
hidraw_devinfo devInfo;
if (ioctl(mDevFd, HIDIOCGRAWINFO, &devInfo) < 0) {
return false;
}
switch (devInfo.bustype) {
case BUS_USB:
info.busType = "USB";
break;
case BUS_HIL:
info.busType = "HIL";
break;
case BUS_BLUETOOTH:
info.busType = "Bluetooth";
break;
case BUS_VIRTUAL:
info.busType = "Virtual";
break;
default:
info.busType = "Other";
break;
}
info.vendorId = devInfo.vendor;
info.productId = devInfo.vendor;
uint32_t descriptorSize;
/* Get Report Descriptor Size */
if (ioctl(mDevFd, HIDIOCGRDESCSIZE, &descriptorSize) < 0) {
return false;
}
struct hidraw_report_descriptor reportDescriptor;
memset(&reportDescriptor, 0, sizeof(reportDescriptor));
info.descriptor.resize(descriptorSize);
reportDescriptor.size = descriptorSize;
if (ioctl(mDevFd, HIDIOCGRDESC, &reportDescriptor) < 0) {
return false;
}
std::copy(reportDescriptor.value, reportDescriptor.value + descriptorSize,
info.descriptor.begin());
mDeviceInfo = info;
return true;
}
bool HidRawDevice::generateDigest(const std::unordered_set<unsigned int> &usage) {
if (mDeviceInfo.descriptor.empty()) {
return false;
}
std::vector<HidItem> tokens = HidItem::tokenize(mDeviceInfo.descriptor);
HidParser parser;
if (!parser.parse(tokens)) {
return false;
}
parser.filterTree();
mDigestVector = parser.generateDigest(usage);
return mDigestVector.size() > 0;
}
bool HidRawDevice::isValid() {
return mValid;
}
bool HidRawDevice::getFeature(uint8_t id, std::vector<uint8_t> *out) {
if (mDevFd < 0) {
return false;
}
if (out == nullptr) {
return false;
}
const HidParser::ReportPacket *packet = getReportPacket(HidParser::REPORT_TYPE_FEATURE, id);
if (packet == nullptr) {
LOG_E << "HidRawDevice::getFeature: unknown feature " << id << LOG_ENDL;
return false;
}
size_t size = packet->getByteSize() + 1; // report id size
std::lock_guard<std::mutex> l(mIoBufferLock);
if (mIoBuffer.size() < size) {
mIoBuffer.resize(size);
}
mIoBuffer[0] = id;
int res = ::ioctl(mDevFd, HIDIOCGFEATURE(size), mIoBuffer.data());
if (res < 0) {
LOG_E << "HidRawDevice::getFeature: feature " << static_cast<int>(id)
<< " ioctl returns " << res << " (" << ::strerror(res) << ")" << LOG_ENDL;
return false;
}
if (static_cast<size_t>(res) != size) {
LOG_E << "HidRawDevice::getFeature: get feature " << static_cast<int>(id)
<< " returned " << res << " bytes, does not match expected " << size << LOG_ENDL;
return false;
}
if (mIoBuffer.front() != id) {
LOG_E << "HidRawDevice::getFeature: get feature " << static_cast<int>(id)
<< " result has header " << mIoBuffer.front() << LOG_ENDL;
}
out->resize(size - 1);
std::copy(mIoBuffer.begin() + 1, mIoBuffer.begin() + size, out->begin());
return true;
}
bool HidRawDevice::setFeature(uint8_t id, const std::vector<uint8_t> &in) {
if (mDevFd < 0) {
return false;
}
const HidParser::ReportPacket *packet = getReportPacket(HidParser::REPORT_TYPE_FEATURE, id);
if (packet == nullptr) {
LOG_E << "HidRawDevice::setFeature: Unknown feature " << id << LOG_ENDL;
return false;
}
size_t size = packet->getByteSize();
if (size != in.size()) {
LOG_E << "HidRawDevice::setFeature: set feature " << id << " size mismatch, need "
<< size << " bytes, have " << in.size() << " bytes" << LOG_ENDL;
return false;
}
++size; // report id byte
std::lock_guard<std::mutex> l(mIoBufferLock);
if (mIoBuffer.size() < size) {
mIoBuffer.resize(size);
}
mIoBuffer[0] = id;
std::copy(in.begin(), in.end(), &mIoBuffer[1]);
int res = ::ioctl(mDevFd, HIDIOCSFEATURE(size), mIoBuffer.data());
if (res < 0) {
LOG_E << "HidRawDevice::setFeature: feature " << id << " ioctl returns " << res
<< " (" << ::strerror(res) << ")" << LOG_ENDL;
return false;
}
return true;
}
bool HidRawDevice::sendReport(uint8_t id, std::vector<uint8_t> &data) {
if (mDevFd < 0) {
return false;
}
const HidParser::ReportPacket *packet = getReportPacket(HidParser::REPORT_TYPE_OUTPUT, id);
if (packet == nullptr) {
LOG_E << "HidRawDevice::sendReport: unknown output " << id << LOG_ENDL;
return false;
}
size_t size = packet->getByteSize();
if (size != data.size()) {
LOG_E << "HidRawDevice::sendReport: send report " << id << " size mismatch, need "
<< size << " bytes, have " << data.size() << " bytes" << LOG_ENDL;
return false;
}
int res;
if (mMultiIdDevice) {
std::lock_guard<std::mutex> l(mIoBufferLock);
++size;
if (mIoBuffer.size() < size) {
mIoBuffer.resize(size);
}
mIoBuffer[0] = id;
std::copy(mIoBuffer.begin() + 1, mIoBuffer.end(), data.begin());
res = ::write(mDevFd, mIoBuffer.data(), size);
} else {
res = ::write(mDevFd, data.data(), size);
}
if (res < 0) {
LOG_E << "HidRawDevice::sendReport: output " << id << " write returns " << res
<< " (" << ::strerror(res) << ")" << LOG_ENDL;
return false;
}
return true;
}
bool HidRawDevice::receiveReport(uint8_t *id, std::vector<uint8_t> *data) {
if (mDevFd < 0) {
return false;
}
uint8_t buffer[256];
int res = ::read(mDevFd, buffer, 256);
if (res < 0) {
LOG_E << "HidRawDevice::receiveReport: read returns " << res
<< " (" << ::strerror(res) << ")" << LOG_ENDL;
return false;
}
if (mMultiIdDevice) {
if (!(res > 1)) {
LOG_E << "read hidraw returns data too short, len: " << res << LOG_ENDL;
return false;
}
data->resize(static_cast<size_t>(res - 1));
std::copy(buffer + 1, buffer + res, data->begin());
*id = buffer[0];
} else {
data->resize(static_cast<size_t>(res));
std::copy(buffer, buffer + res, data->begin());
*id = 0;
}
return true;
}
const HidParser::ReportPacket *HidRawDevice::getReportPacket(unsigned int type, unsigned int id) {
auto i = mReportTypeIdMap.find(std::make_pair(type, id));
return (i == mReportTypeIdMap.end()) ? nullptr : i->second;
}
} // namespace SensorHalExt
} // namespace android

View file

@ -0,0 +1,85 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_SENSORHAL_EXT_HIDRAW_DEVICE_H
#define ANDROID_SENSORHAL_EXT_HIDRAW_DEVICE_H
#include "HidDevice.h"
#include <HidParser.h>
#include <string>
#include <vector>
#include <unordered_set>
#include <unordered_map>
namespace android {
namespace SensorHalExt {
using HidUtil::HidParser;
using HidUtil::HidReport;
class HidRawDevice : public HidDevice {
friend class HidRawDeviceTest;
public:
HidRawDevice(const std::string &devName, const std::unordered_set<unsigned int> &usageSet);
virtual ~HidRawDevice();
// test if the device initialized successfully
bool isValid();
// implement HidDevice pure virtuals
virtual HidDeviceInfo& getDeviceInfo() override { return mDeviceInfo; }
virtual bool getFeature(uint8_t id, std::vector<uint8_t> *out) override;
virtual bool setFeature(uint8_t id, const std::vector<uint8_t> &in) override;
virtual bool sendReport(uint8_t id, std::vector<uint8_t> &data) override;
virtual bool receiveReport(uint8_t *id, std::vector<uint8_t> *data) override;
protected:
bool populateDeviceInfo();
size_t getReportSize(int type, uint8_t id);
bool generateDigest(const std::unordered_set<uint32_t> &usage);
size_t calculateReportBitSize(const std::vector<HidReport> &reportItems);
const HidParser::ReportPacket *getReportPacket(unsigned int type, unsigned int id);
typedef std::pair<unsigned int, unsigned int> ReportTypeIdPair;
struct UnsignedIntPairHash {
size_t operator()(const ReportTypeIdPair& v) const {
std::hash<unsigned int> hash;
return hash(v.first) ^ hash(v.second);
}
};
std::unordered_map<ReportTypeIdPair, const HidParser::ReportPacket *, UnsignedIntPairHash>
mReportTypeIdMap;
HidParser::DigestVector mDigestVector;
private:
std::mutex mIoBufferLock;
std::vector<uint8_t> mIoBuffer;
int mDevFd;
HidDeviceInfo mDeviceInfo;
bool mMultiIdDevice;
int mValid;
HidRawDevice(const HidRawDevice &) = delete;
void operator=(const HidRawDevice &) = delete;
};
} // namespace SensorHalExt
} // namespace android
#endif // ANDROID_SENSORHAL_EXT_HIDRAW_DEVICE_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,168 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_SENSORHAL_EXT_HIDRAW_SENSOR_H
#define ANDROID_SENSORHAL_EXT_HIDRAW_SENSOR_H
#include "BaseSensorObject.h"
#include "HidDevice.h"
#include "Utils.h"
#include <HidParser.h>
#include <hardware/sensors.h>
namespace android {
namespace SensorHalExt {
using HidUtil::HidParser;
using ReportPacket = HidParser::ReportPacket;
using ReportItem = HidParser::ReportItem;
class HidRawSensor : public BaseSensorObject {
friend class HidRawSensorTest;
friend class HidRawDeviceTest;
public:
HidRawSensor(SP(HidDevice) device, uint32_t usage,
const std::vector<HidParser::ReportPacket> &report);
// implements BaseSensorObject
virtual const sensor_t* getSensor() const;
virtual void getUuid(uint8_t* uuid) const;
virtual int enable(bool enable);
virtual int batch(int64_t samplePeriod, int64_t batchPeriod); // unit nano-seconds
// handle input report received
void handleInput(uint8_t id, const std::vector<uint8_t> &message);
// indicate if the HidRawSensor is a valid one
bool isValid() const { return mValid; };
private:
// structure used for holding descriptor parse result for each report field
enum {
TYPE_FLOAT,
TYPE_INT64,
TYPE_ACCURACY
};
struct ReportTranslateRecord {
int type;
int index;
int64_t maxValue;
int64_t minValue;
size_t byteOffset;
size_t byteSize;
double a;
int64_t b;
};
// sensor related information parsed from HID descriptor
struct FeatureValue {
// information needed to furnish sensor_t structure (see hardware/sensors.h)
std::string name;
std::string vendor;
std::string permission;
std::string typeString;
int32_t type;
int version;
float maxRange;
float resolution;
float power;
int32_t minDelay;
int64_t maxDelay;
size_t fifoSize;
size_t fifoMaxSize;
uint32_t reportModeFlag;
bool isWakeUp;
// dynamic sensor specific
std::string uniqueId;
uint8_t uuid[16];
// if the device is custom sensor HID device that furnished android specific descriptors
bool isAndroidCustom;
};
// helper function to find the first report item with specified usage, type and id.
// if parameter id is omitted, this function looks for usage with all ids.
// return nullptr if nothing is found.
static const HidParser::ReportItem* find
(const std::vector<HidParser::ReportPacket> &packets,
unsigned int usage, int type, int id = -1);
// helper function to decode std::string from HID feature report buffer.
static bool decodeString(
const HidParser::ReportItem &report,
const std::vector<uint8_t> &buffer, std::string *d);
// initialize default feature values default based on hid device info
static void initFeatureValueFromHidDeviceInfo(
FeatureValue *featureValue, const HidDevice::HidDeviceInfo &info);
// populates feature values from descripitors and hid feature reports
bool populateFeatureValueFromFeatureReport(
FeatureValue *featureValue, const std::vector<HidParser::ReportPacket> &packets);
// validate feature values and construct sensor_t structure if values are ok.
bool validateFeatureValueAndBuildSensor();
// helper function to find sensor control feature usage from packets
bool findSensorControlUsage(const std::vector<HidParser::ReportPacket> &packets);
// try to parse sensor description feature value to see if it matches
// android specified custom sensor definition.
bool detectAndroidCustomSensor(const std::string &description);
// process HID sensor spec defined three axis sensors usages: accel, gyro, mag.
bool processTriAxisUsage(const std::vector<HidParser::ReportPacket> &packets,
uint32_t usageX, uint32_t usageY, uint32_t usageZ, double defaultScaling = 1);
// process HID snesor spec defined orientation(quaternion) sensor usages.
bool processQuaternionUsage(const std::vector<HidParser::ReportPacket> &packets);
// dump data for test/debug purpose
std::string dump() const;
// Features for control sensor
int mReportingStateId;
unsigned int mReportingStateOffset;
int mPowerStateId;
unsigned int mPowerStateOffset;
int mReportIntervalId;
unsigned int mReportIntervalOffset;
unsigned int mReportIntervalSize;
// Input report translate table
std::vector<ReportTranslateRecord> mTranslateTable;
unsigned mInputReportId;
FeatureValue mFeatureInfo;
sensor_t mSensor;
// runtime states variable
bool mEnabled;
int64_t mSamplingPeriod; // ns
int64_t mBatchingPeriod; // ns
WP(HidDevice) mDevice;
bool mValid;
};
} // namespace SensorHalExt
} // namespace android
#endif // ANDROID_SENSORHAL_EXT_HIDRAW_SENSOR_H

View file

@ -0,0 +1,71 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "HidRawSensorDaemon.h"
#include "ConnectionDetector.h"
#include "DynamicSensorManager.h"
#include "HidRawSensorDevice.h"
#include <utils/Log.h>
#include <utils/SystemClock.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iomanip>
#include <sstream>
#define DEV_PATH "/dev/"
#define DEV_NAME_REGEX "^hidraw[0-9]+$"
namespace android {
namespace SensorHalExt {
HidRawSensorDaemon::HidRawSensorDaemon(DynamicSensorManager& manager)
: BaseDynamicSensorDaemon(manager) {
mDetector = new FileConnectionDetector(
this, std::string(DEV_PATH), std::string(DEV_NAME_REGEX));
}
BaseSensorVector HidRawSensorDaemon::createSensor(const std::string &deviceKey) {
BaseSensorVector ret;
sp<HidRawSensorDevice> device(HidRawSensorDevice::create(deviceKey));
if (device != nullptr) {
ALOGV("created HidRawSensorDevice(%p) successfully on device %s contains %zu sensors",
device.get(), deviceKey.c_str(), device->getSensors().size());
// convert type
for (auto &i : device->getSensors()) {
ret.push_back(i);
}
mHidRawSensorDevices.emplace(deviceKey, device);
} else {
ALOGE("failed to create HidRawSensorDevice object");
}
ALOGE("return %zu sensors", ret.size());
return ret;
}
void HidRawSensorDaemon::removeSensor(const std::string &deviceKey) {
mHidRawSensorDevices.erase(deviceKey);
}
} // namespace SensorHalExt
} // namespace android

View file

@ -0,0 +1,63 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_SENSORHAL_EXT_HIDRAW_SENSOR_DAEMON_H
#define ANDROID_SENSORHAL_EXT_HIDRAW_SENSOR_DAEMON_H
#include "BaseDynamicSensorDaemon.h"
#include <HidParser.h>
#include <hardware/sensors.h>
#include <utils/Thread.h>
#include <memory>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
using HidUtil::HidParser;
using HidUtil::HidReport;
using HidUtil::HidItem;
namespace android {
namespace SensorHalExt {
class HidRawSensorDevice;
class ConnectionDetector;
class HidRawSensorDaemon : public BaseDynamicSensorDaemon {
friend class HidRawSensorDaemonTest;
public:
HidRawSensorDaemon(DynamicSensorManager& manager);
virtual ~HidRawSensorDaemon() = default;
private:
virtual BaseSensorVector createSensor(const std::string &deviceKey);
virtual void removeSensor(const std::string &deviceKey);
class HidRawSensor;
void registerExisting();
sp<ConnectionDetector> mDetector;
std::unordered_map<std::string, sp<HidRawSensorDevice>> mHidRawSensorDevices;
};
} // namespace SensorHalExt
} // namespace android
#endif // ANDROID_SENSORHAL_EXT_HIDRAW_SENSOR_DAEMON_H

View file

@ -0,0 +1,123 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "HidRawSensorDevice.h"
#include "HidRawSensor.h"
#include "HidSensorDef.h"
#include <utils/Log.h>
#include <fcntl.h>
#include <linux/input.h>
#include <linux/hidraw.h>
#include <sys/ioctl.h>
#include <set>
namespace android {
namespace SensorHalExt {
using namespace Hid::Sensor::SensorTypeUsage;
using namespace Hid::Sensor::PropertyUsage;
const std::unordered_set<unsigned int> HidRawSensorDevice::sInterested{
ACCELEROMETER_3D, GYROMETER_3D, COMPASS_3D, CUSTOM};
sp<HidRawSensorDevice> HidRawSensorDevice::create(const std::string &devName) {
sp<HidRawSensorDevice> device(new HidRawSensorDevice(devName));
// remove +1 strong count added by constructor
device->decStrong(device.get());
if (device->mValid) {
return device;
} else {
return nullptr;
}
}
HidRawSensorDevice::HidRawSensorDevice(const std::string &devName)
: RefBase(), HidRawDevice(devName, sInterested),
Thread(false /*canCallJava*/), mValid(false) {
if (!HidRawDevice::isValid()) {
return;
}
// create HidRawSensor objects from digest
// HidRawSensor object will take sp<HidRawSensorDevice> as parameter, so increment strong count
// to prevent "this" being destructed.
this->incStrong(this);
for (const auto &digest : mDigestVector) { // for each usage - vec<ReportPacket> pair
uint32_t usage = static_cast<uint32_t>(digest.fullUsage);
sp<HidRawSensor> s(new HidRawSensor(this, usage, digest.packets));
if (s->isValid()) {
for (const auto &packet : digest.packets) {
if (packet.type == HidParser::REPORT_TYPE_INPUT) { // only used for input mapping
mSensors.emplace(packet.id/* report id*/, s);
}
}
}
}
if (mSensors.size() == 0) {
return;
}
run("HidRawSensor");
mValid = true;
}
HidRawSensorDevice::~HidRawSensorDevice() {
ALOGV("~HidRawSensorDevice %p", this);
requestExitAndWait();
ALOGV("~HidRawSensorDevice %p, thread exited", this);
}
bool HidRawSensorDevice::threadLoop() {
ALOGV("Hid Raw Device thread started %p", this);
std::vector<uint8_t> buffer;
bool ret;
uint8_t usageId;
while(!Thread::exitPending()) {
ret = receiveReport(&usageId, &buffer);
if (!ret) {
break;
}
auto i = mSensors.find(usageId);
if (i == mSensors.end()) {
ALOGW("Input of unknow usage id %u received", usageId);
continue;
}
i->second->handleInput(usageId, buffer);
}
ALOGI("Hid Raw Device thread ended for %p", this);
return false;
}
BaseSensorVector HidRawSensorDevice::getSensors() const {
BaseSensorVector ret;
std::set<sp<BaseSensorObject>> set;
for (const auto &s : mSensors) {
if (set.find(s.second) == set.end()) {
ret.push_back(s.second);
set.insert(s.second);
}
}
return ret;
}
} // namespace SensorHalExt
} // namespace android

View file

@ -0,0 +1,54 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_SENSORHAL_EXT_HIDRAW_SENSOR_DEVICE_H
#define ANDROID_SENSORHAL_EXT_HIDRAW_SENSOR_DEVICE_H
#include "BaseSensorObject.h"
#include "BaseDynamicSensorDaemon.h" // BaseSensorVector
#include "HidRawDevice.h"
#include "HidRawSensor.h"
#include <HidParser.h>
#include <utils/Thread.h>
#include <string>
#include <vector>
namespace android {
namespace SensorHalExt {
class HidRawSensorDevice : public HidRawDevice, public Thread {
public:
static sp<HidRawSensorDevice> create(const std::string &devName);
virtual ~HidRawSensorDevice();
// get a list of sensors associated with this device
BaseSensorVector getSensors() const;
private:
static const std::unordered_set<unsigned int> sInterested;
// constructor will result in +1 strong count
explicit HidRawSensorDevice(const std::string &devName);
// implement function of Thread
virtual bool threadLoop() override;
std::unordered_map<unsigned int/*reportId*/, sp<HidRawSensor>> mSensors;
bool mValid;
};
} // namespace SensorHalExt
} // namespace android
#endif // ANDROID_SENSORHAL_EXT_HIDRAW_DEVICE_H

View file

@ -0,0 +1,101 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef HID_SENSOR_DEF_H_
#define HID_SENSOR_DEF_H_
namespace Hid {
namespace Sensor {
namespace GeneralUsage {
enum {
STATE = 0x200201,
EVENT = 0x200202,
};
} //namespace Usage
namespace PropertyUsage {
enum {
FRIENDLY_NAME = 0x200301,
MINIMUM_REPORT_INTERVAL = 0x200304,
PERSISTENT_UNIQUE_ID = 0x200302,
POWER_STATE = 0x200319,
RANGE_MAXIMUM = 0x200314,
RANGE_MINIMUM = 0x200315,
REPORTING_STATE = 0x200316,
REPORT_INTERVAL = 0x20030E,
RESOLUTION = 0x200313,
SAMPLING_RATE =0x200317,
SENSOR_CONNECTION_TYPE = 0x200309,
SENSOR_DESCRIPTION = 0x200308,
SENSOR_MANUFACTURER = 0x200305,
SENSOR_MODEL = 0x200306,
SENSOR_SERIAL_NUMBER = 0x200307,
SENSOR_STATUS = 0x200303,
};
} // nsmespace PropertyUsage
namespace SensorTypeUsage {
enum {
ACCELEROMETER_3D = 0x200073,
COMPASS_3D = 0x200083,
CUSTOM = 0x2000E1,
DEVICE_ORIENTATION = 0x20008A,
GYROMETER_3D = 0x200076,
};
} // namespace SensorTypeUsage
namespace ReportUsage {
enum {
ACCELERATION_X_AXIS = 0x200453,
ACCELERATION_Y_AXIS = 0x200454,
ACCELERATION_Z_AXIS = 0x200455,
ANGULAR_VELOCITY_X_AXIS = 0x200457,
ANGULAR_VELOCITY_Y_AXIS = 0x200458,
ANGULAR_VELOCITY_Z_AXIS = 0x200459,
CUSTOM_VALUE_1 = 0x200544,
CUSTOM_VALUE_2 = 0x200545,
CUSTOM_VALUE_3 = 0x200546,
CUSTOM_VALUE_4 = 0x200547,
CUSTOM_VALUE_5 = 0x200548,
CUSTOM_VALUE_6 = 0x200549,
MAGNETIC_FLUX_X_AXIS = 0x200485,
MAGNETIC_FLUX_Y_AXIS = 0x200486,
MAGNETIC_FLUX_Z_AXIS = 0x200487,
MAGNETOMETER_ACCURACY = 0x200488,
ORIENTATION_QUATERNION = 0x200483,
};
} // namespace ReportUsage
namespace RawMinMax {
enum {
REPORTING_STATE_MIN = 0,
REPORTING_STATE_MAX = 5,
POWER_STATE_MIN = 0,
POWER_STATE_MAX = 5,
};
} // namespace RawMinMax
namespace StateValue {
enum {
POWER_STATE_FULL_POWER = 1,
POWER_STATE_POWER_OFF = 5,
REPORTING_STATE_ALL_EVENT = 1,
REPORTING_STATE_NO_EVENT = 0,
};
} // StateValue
} // namespace Sensor
} // namespace Hid
#endif // HID_SENSOR_DEF_H_

View file

@ -17,12 +17,11 @@
#ifndef ANDROID_SENSORHAL_DSE_SENSOR_EVENT_CALLBACK_H
#define ANDROID_SENSORHAL_DSE_SENSOR_EVENT_CALLBACK_H
#include "Utils.h"
#include <hardware/sensors.h>
#include <utils/RefBase.h>
namespace android {
namespace SensorHalExt {
class BaseSensorObject;
// if timestamp in sensors_event_t has this value, it will be filled at dispatcher.
@ -30,7 +29,7 @@ constexpr int64_t TIMESTAMP_AUTO_FILL = -1;
class SensorEventCallback {
public:
virtual int submitEvent(sp<BaseSensorObject> sensor, const sensors_event_t &e) = 0;
virtual int submitEvent(SP(BaseSensorObject) sensor, const sensors_event_t &e) = 0;
virtual ~SensorEventCallback() = default;
};

View file

@ -0,0 +1,36 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_SENSORHAL_EXT_UTILS_H
#define ANDROID_SENSORHAL_EXT_UTILS_H
// Host build does not have RefBase
#ifdef __ANDROID__
#include <utils/RefBase.h>
#define REF_BASE(a) ::android::RefBase
#define SP(a) sp<a>
#define WP(a) wp<a>
#define SP_THIS this
#define PROMOTE(a) (a).promote()
#else
#include <memory>
#define REF_BASE(a) std::enable_shared_from_this<a>
#define SP(a) std::shared_ptr<a>
#define WP(a) std::weak_ptr<a>
#define SP_THIS shared_from_this()
#define PROMOTE(a) (a).lock()
#endif
#endif // ANDROID_SENSORHAL_EXT_UTILS_H

View file

@ -0,0 +1,125 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "HidRawDeviceTest"
#include "HidRawDevice.h"
#include "HidRawSensor.h"
#include "HidSensorDef.h"
#include "SensorEventCallback.h"
#include "Utils.h"
#include "HidLog.h"
#include "StreamIoUtil.h"
namespace android {
namespace SensorHalExt {
/*
* Host test that verifies HidRawDevice and HidRawSensor works correctly.
*/
class HidRawDeviceTest {
public:
static void test(const char *devicePath) {
using namespace Hid::Sensor::SensorTypeUsage;
using HidUtil::hexdumpToStream;
std::unordered_set<unsigned int> interestedUsage{
ACCELEROMETER_3D, GYROMETER_3D, COMPASS_3D, CUSTOM};
SP(HidRawDevice) device =
std::make_shared<HidRawDevice>(std::string(devicePath), interestedUsage);
const HidDevice::HidDeviceInfo &info = device->getDeviceInfo();
LOG_V << "Sizeof descriptor: " << info.descriptor.size() << LOG_ENDL;
LOG_V << "Descriptor: " << LOG_ENDL;
hexdumpToStream(LOG_V, info.descriptor.begin(), info.descriptor.end());
if (!device->isValid()) {
LOG_E << "invalid device" << LOG_ENDL;
return;
}
LOG_V << "Digest: " << LOG_ENDL;
LOG_V << device->mDigestVector;
std::vector<uint8_t> buffer;
// Dump first few feature ID to help debugging.
// If device does not implement all these features, it will show error messages.
for (int featureId = 0; featureId <= 5; ++featureId) {
if (!device->getFeature(featureId, &buffer)) {
LOG_E << "cannot get feature " << featureId << LOG_ENDL;
} else {
LOG_V << "Dump of feature " << featureId << LOG_ENDL;
hexdumpToStream(LOG_V, buffer.begin(), buffer.end());
}
}
//
// use HidRawSensor to operate the device, pick first digest
//
auto &reportDigest = device->mDigestVector[0];
SP(HidRawSensor) sensor = std::make_shared<HidRawSensor>(
device, reportDigest.fullUsage, reportDigest.packets);
if (!sensor->isValid()) {
LOG_E << "Sensor is not valid " << LOG_ENDL;
return;
}
const sensor_t *s = sensor->getSensor();
LOG_V << "Sensor name: " << s->name << ", vendor: " << s->vendor << LOG_ENDL;
LOG_V << sensor->dump() << LOG_ENDL;
class Callback : public SensorEventCallback {
virtual int submitEvent(SP(BaseSensorObject) /*sensor*/, const sensors_event_t &e) {
LOG_V << "sensor: " << e.sensor << ", type: " << e.type << ", ts: " << e.timestamp
<< ", values (" << e.data[0] << ", " << e.data[1] << ", " << e.data[2] << ")"
<< LOG_ENDL;
return 1;
}
};
Callback callback;
sensor->setEventCallback(&callback);
// Request sensor samples at to 10Hz (100ms)
sensor->batch(100LL*1000*1000 /*ns*/, 0);
sensor->enable(true);
// get a couple of events
for (size_t i = 0; i < 100; ++i) {
uint8_t id;
if (!device->receiveReport(&id, &buffer)) {
LOG_E << "Receive report error" << LOG_ENDL;
continue;
}
sensor->handleInput(id, buffer);
}
// clean up
sensor->enable(false);
LOG_V << "Done!" << LOG_ENDL;
}
};
} //namespace SensorHalExt
} //namespace android
int main(int argc, char* argv[]) {
if (argc != 2) {
LOG_E << "Usage: " << argv[0] << " hidraw-dev-path" << LOG_ENDL;
return -1;
}
android::SensorHalExt::HidRawDeviceTest::test(argv[1]);
return 0;
}

View file

@ -0,0 +1,162 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "HidRawSensorTest"
#include "HidDevice.h"
#include "HidLog.h"
#include "HidLog.h"
#include "HidParser.h"
#include "HidRawSensor.h"
#include "HidSensorDef.h"
#include "StreamIoUtil.h"
#include "TestHidDescriptor.h"
#include "Utils.h"
#include <deque>
#include <unordered_map>
namespace android {
namespace SensorHalExt {
class HidRawDummyDevice : public HidDevice {
public:
struct DataPair {
uint8_t id;
std::vector<uint8_t> data;
};
HidRawDummyDevice() {
// dummy values
mInfo = {
.name = "Test sensor name",
.physicalPath = "/physical/path",
.busType = "USB",
.vendorId = 0x1234,
.productId = 0x5678,
.descriptor = {0}
};
}
virtual const HidDeviceInfo& getDeviceInfo() {
return mInfo;
}
// get feature from device
virtual bool getFeature(uint8_t id, std::vector<uint8_t> *out) {
auto i = mFeature.find(id);
if (i == mFeature.end()) {
return false;
}
*out = i->second;
return true;
}
// write feature to device
virtual bool setFeature(uint8_t id, const std::vector<uint8_t> &in) {
auto i = mFeature.find(id);
if (i == mFeature.end() || in.size() != i->second.size()) {
return false;
}
i->second = in;
return true;
}
// send report to default output endpoint
virtual bool sendReport(uint8_t id, std::vector<uint8_t> &data) {
DataPair pair = {
.id = id,
.data = data
};
mOutput.push_back(pair);
return true;
}
// receive from default input endpoint
virtual bool receiveReport(uint8_t * /*id*/, std::vector<uint8_t> * /*data*/) {
// not necessary, as input report can be directly feed to HidRawSensor for testing purpose
return false;
}
bool dequeuOutputReport(DataPair *pair) {
if (!mOutput.empty()) {
return false;
}
*pair = mOutput.front();
mOutput.pop_front();
return true;
}
private:
HidDeviceInfo mInfo;
std::deque<DataPair> mOutput;
std::unordered_map<uint8_t, std::vector<uint8_t>> mFeature;
};
class HidRawSensorTest {
public:
static bool test() {
bool ret = true;
using namespace Hid::Sensor::SensorTypeUsage;
std::unordered_set<unsigned int> interestedUsage{
ACCELEROMETER_3D, GYROMETER_3D, COMPASS_3D, CUSTOM};
SP(HidDevice) device(new HidRawDummyDevice());
HidParser hidParser;
for (const TestHidDescriptor *p = gDescriptorArray; ; ++p) {
if (p->data == nullptr || p->len == 0) {
break;
}
const char *name = p->name != nullptr ? p->name : "unnamed";
if (!hidParser.parse(p->data, p->len)) {
LOG_E << name << " parsing error!" << LOG_ENDL;
ret = false;
continue;
}
hidParser.filterTree();
LOG_V << name << " digest: " << LOG_ENDL;
auto digestVector = hidParser.generateDigest(interestedUsage);
LOG_V << digestVector;
if (digestVector.empty()) {
LOG_V << name << " does not contain interested usage" << LOG_ENDL;
continue;
}
LOG_V << name << " sensor: " << LOG_ENDL;
for (const auto &digest : digestVector) {
LOG_I << "Sensor usage " << std::hex << digest.fullUsage << std::dec << LOG_ENDL;
auto *s = new HidRawSensor(device, digest.fullUsage, digest.packets);
if (s->mValid) {
LOG_V << "Usage " << std::hex << digest.fullUsage << std::dec << LOG_ENDL;
LOG_V << s->dump();
} else {
LOG_V << "Sensor of usage " << std::hex << digest.fullUsage << std::dec
<< " not valid!" << LOG_ENDL;
}
}
LOG_V << LOG_ENDL;
}
return ret;
}
};
}// namespace SensorHalExt
}// namespace android
int main() {
return android::SensorHalExt::HidRawSensorTest::test() ? 0 : 1;
}