HID dynamic sensor: add support to three types of sensor am: 4715d1734d
am: 852a75717d
Change-Id: I27ab261f0a6d859a74241fb03bffd572e71f4b47
This commit is contained in:
commit
fada5a0a18
24 changed files with 2545 additions and 61 deletions
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 ®ex)
|
||||
: 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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
57
modules/sensors/dynamic_sensor/HidDevice.h
Normal file
57
modules/sensors/dynamic_sensor/HidDevice.h
Normal 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
|
332
modules/sensors/dynamic_sensor/HidRawDevice.cpp
Normal file
332
modules/sensors/dynamic_sensor/HidRawDevice.cpp
Normal 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
|
85
modules/sensors/dynamic_sensor/HidRawDevice.h
Normal file
85
modules/sensors/dynamic_sensor/HidRawDevice.h
Normal 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
|
||||
|
1044
modules/sensors/dynamic_sensor/HidRawSensor.cpp
Normal file
1044
modules/sensors/dynamic_sensor/HidRawSensor.cpp
Normal file
File diff suppressed because it is too large
Load diff
168
modules/sensors/dynamic_sensor/HidRawSensor.h
Normal file
168
modules/sensors/dynamic_sensor/HidRawSensor.h
Normal 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
|
||||
|
71
modules/sensors/dynamic_sensor/HidRawSensorDaemon.cpp
Normal file
71
modules/sensors/dynamic_sensor/HidRawSensorDaemon.cpp
Normal 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
|
||||
|
63
modules/sensors/dynamic_sensor/HidRawSensorDaemon.h
Normal file
63
modules/sensors/dynamic_sensor/HidRawSensorDaemon.h
Normal 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
|
||||
|
123
modules/sensors/dynamic_sensor/HidRawSensorDevice.cpp
Normal file
123
modules/sensors/dynamic_sensor/HidRawSensorDevice.cpp
Normal 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
|
54
modules/sensors/dynamic_sensor/HidRawSensorDevice.h
Normal file
54
modules/sensors/dynamic_sensor/HidRawSensorDevice.h
Normal 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
|
||||
|
101
modules/sensors/dynamic_sensor/HidSensorDef.h
Normal file
101
modules/sensors/dynamic_sensor/HidSensorDef.h
Normal 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_
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
36
modules/sensors/dynamic_sensor/Utils.h
Normal file
36
modules/sensors/dynamic_sensor/Utils.h
Normal 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
|
125
modules/sensors/dynamic_sensor/test/HidRawDeviceTest.cpp
Normal file
125
modules/sensors/dynamic_sensor/test/HidRawDeviceTest.cpp
Normal 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;
|
||||
}
|
162
modules/sensors/dynamic_sensor/test/HidRawSensorTest.cpp
Normal file
162
modules/sensors/dynamic_sensor/test/HidRawSensorTest.cpp
Normal 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;
|
||||
}
|
Loading…
Reference in a new issue