Merge sc-v2-dev-plus-aosp-without-vendor@8084891
Bug: 214455710 Merged-In: I975390f8f495267ef0cd24dc8e73db859e541146 Change-Id: Ia540313ff7bb064b9de8a8655b59fed8c40a8aaa
This commit is contained in:
commit
f911d3a70d
21 changed files with 757 additions and 104 deletions
|
@ -38,5 +38,8 @@ LOCAL_CFLAGS:= -DLOG_TAG=\"gralloc\" -Wno-missing-field-initializers
|
|||
ifeq ($(TARGET_USE_PAN_DISPLAY),true)
|
||||
LOCAL_CFLAGS += -DUSE_PAN_DISPLAY=1
|
||||
endif
|
||||
ifneq ($(GRALLOC_FRAMEBUFFER_NUM),)
|
||||
LOCAL_CFLAGS += -DNUM_BUFFERS=$(GRALLOC_FRAMEBUFFER_NUM)
|
||||
endif
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
|
|
@ -45,8 +45,10 @@
|
|||
#define USE_PAN_DISPLAY 0
|
||||
#endif
|
||||
|
||||
// numbers of buffers for page flipping
|
||||
// Enabling page flipping by default
|
||||
#ifndef NUM_BUFFERS
|
||||
#define NUM_BUFFERS 2
|
||||
#endif
|
||||
|
||||
|
||||
enum {
|
||||
|
@ -157,7 +159,8 @@ int mapFrameBufferLocked(struct private_module_t* module, int format)
|
|||
info.activate = FB_ACTIVATE_NOW;
|
||||
|
||||
/*
|
||||
* Request NUM_BUFFERS screens (at lest 2 for page flipping)
|
||||
* Request NUM_BUFFERS screens
|
||||
* To enable page flipping, NUM_BUFFERS should be at least 2.
|
||||
*/
|
||||
info.yres_virtual = info.yres * NUM_BUFFERS;
|
||||
|
||||
|
|
|
@ -108,7 +108,23 @@ cc_library_shared {
|
|||
|
||||
cflags: ["-DLOG_TAG=\"DynamicSensorHal\""],
|
||||
|
||||
srcs: ["sensors.cpp"],
|
||||
srcs: [
|
||||
"DynamicSensorsSubHal.cpp",
|
||||
"sensors.cpp",
|
||||
],
|
||||
shared_libs: [
|
||||
"android.hardware.sensors@2.0",
|
||||
"android.hardware.sensors@2.0-ScopedWakelock",
|
||||
"android.hardware.sensors@2.1",
|
||||
"libhidlbase",
|
||||
],
|
||||
static_libs: [
|
||||
"android.hardware.sensors@1.0-convert",
|
||||
],
|
||||
header_libs: [
|
||||
"android.hardware.sensors@2.X-multihal.header",
|
||||
"android.hardware.sensors@2.X-shared-utils",
|
||||
],
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -42,6 +42,7 @@ void BaseSensorObject::getUuid(uint8_t* uuid) const {
|
|||
int BaseSensorObject::flush() {
|
||||
static const sensors_event_t event = {
|
||||
.type = SENSOR_TYPE_META_DATA,
|
||||
.meta_data.what = META_DATA_FLUSH_COMPLETE,
|
||||
.timestamp = TIMESTAMP_AUTO_FILL // timestamp will be filled at dispatcher
|
||||
};
|
||||
generateEvent(event);
|
||||
|
|
|
@ -57,8 +57,6 @@ SocketConnectionDetector::SocketConnectionDetector(BaseDynamicSensorDaemon *d, i
|
|||
std::ostringstream s;
|
||||
s << "socket:" << port;
|
||||
mDevice = s.str();
|
||||
|
||||
run("ddad_socket");
|
||||
}
|
||||
|
||||
SocketConnectionDetector::~SocketConnectionDetector() {
|
||||
|
@ -67,6 +65,12 @@ SocketConnectionDetector::~SocketConnectionDetector() {
|
|||
}
|
||||
}
|
||||
|
||||
void SocketConnectionDetector::Init() {
|
||||
// run adds a strong reference to this object, so it can't be invoked from
|
||||
// the constructor.
|
||||
run("ddad_socket");
|
||||
}
|
||||
|
||||
int SocketConnectionDetector::waitForConnection() {
|
||||
return ::accept(mListenFd, nullptr, nullptr);
|
||||
}
|
||||
|
@ -124,9 +128,6 @@ FileConnectionDetector::FileConnectionDetector (
|
|||
ALOGE("Cannot setup watch on dir %s", path.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// mLooper != null && mInotifyFd added to looper
|
||||
run("ddad_file");
|
||||
}
|
||||
|
||||
FileConnectionDetector::~FileConnectionDetector() {
|
||||
|
@ -138,6 +139,13 @@ FileConnectionDetector::~FileConnectionDetector() {
|
|||
}
|
||||
}
|
||||
|
||||
void FileConnectionDetector::Init() {
|
||||
// mLooper != null && mInotifyFd added to looper
|
||||
// run adds a strong reference to this object, so it can't be invoked from
|
||||
// the constructor.
|
||||
run("ddad_file");
|
||||
}
|
||||
|
||||
bool FileConnectionDetector::matches(const std::string &name) const {
|
||||
return std::regex_match(name, mRegex);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ class ConnectionDetector : virtual public RefBase {
|
|||
public:
|
||||
ConnectionDetector(BaseDynamicSensorDaemon *d) : mDaemon(d) { }
|
||||
virtual ~ConnectionDetector() = default;
|
||||
virtual void Init() {}
|
||||
protected:
|
||||
BaseDynamicSensorDaemon* mDaemon;
|
||||
};
|
||||
|
@ -45,6 +46,7 @@ class SocketConnectionDetector : public ConnectionDetector, public Thread {
|
|||
public:
|
||||
SocketConnectionDetector(BaseDynamicSensorDaemon *d, int port);
|
||||
virtual ~SocketConnectionDetector();
|
||||
void Init() override;
|
||||
private:
|
||||
// implement virtual of Thread
|
||||
virtual bool threadLoop();
|
||||
|
@ -62,6 +64,7 @@ public:
|
|||
FileConnectionDetector(
|
||||
BaseDynamicSensorDaemon *d, const std::string &path, const std::string ®ex);
|
||||
virtual ~FileConnectionDetector();
|
||||
void Init() override;
|
||||
private:
|
||||
static constexpr int POLL_IDENT = 1;
|
||||
// implement virtual of Thread
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include <netinet/in.h>
|
||||
#include <algorithm> //std::max
|
||||
|
||||
#define SYSPROP_PREFIX "dynamic_sensor.dummy"
|
||||
#define SYSPROP_PREFIX "vendor.dynamic_sensor.mock"
|
||||
#define FILE_NAME_BASE "dummy_accel_file"
|
||||
#define FILE_NAME_REGEX ("^" FILE_NAME_BASE "[0-9]$")
|
||||
|
||||
|
@ -43,11 +43,13 @@ DummyDynamicAccelDaemon::DummyDynamicAccelDaemon(DynamicSensorManager& manager)
|
|||
if (strcmp(property, "") != 0) {
|
||||
mFileDetector = new FileConnectionDetector(
|
||||
this, std::string(property), std::string(FILE_NAME_REGEX));
|
||||
mFileDetector->Init();
|
||||
}
|
||||
|
||||
property_get(SYSPROP_PREFIX ".socket", property, "");
|
||||
if (strcmp(property, "") != 0) {
|
||||
mSocketDetector = new SocketConnectionDetector(this, atoi(property));
|
||||
mSocketDetector->Init();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ bool DynamicSensorManager::owns(int handle) const {
|
|||
|
||||
int DynamicSensorManager::activate(int handle, bool enable) {
|
||||
if (handle == mHandleRange.first) {
|
||||
// ignored
|
||||
mMetaSensorActive = enable;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -109,13 +109,17 @@ int DynamicSensorManager::setDelay(int handle, nsecs_t sample_period) {
|
|||
|
||||
int DynamicSensorManager::flush(int handle) {
|
||||
if (handle == mHandleRange.first) {
|
||||
// submit a flush complete here
|
||||
static const sensors_event_t event = {
|
||||
.sensor = mHandleRange.first,
|
||||
.type = SENSOR_TYPE_META_DATA,
|
||||
.timestamp = TIMESTAMP_AUTO_FILL, // timestamp will be filled at dispatcher
|
||||
};
|
||||
submitEvent(nullptr, event);
|
||||
if (mMetaSensorActive) {
|
||||
static const sensors_event_t event = {
|
||||
.sensor = mHandleRange.first,
|
||||
.type = SENSOR_TYPE_META_DATA,
|
||||
.meta_data.what = META_DATA_FLUSH_COMPLETE,
|
||||
.timestamp = TIMESTAMP_AUTO_FILL, // timestamp will be filled at dispatcher
|
||||
};
|
||||
submitEvent(nullptr, event);
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return operateSensor(handle, [] (sp<BaseSensorObject> s)->int {return s->flush();});
|
||||
|
|
|
@ -95,15 +95,18 @@ private:
|
|||
// TF: int foo(sp<BaseSensorObject> obj);
|
||||
template <typename TF>
|
||||
int operateSensor(int handle, TF f) const {
|
||||
std::lock_guard<std::mutex> lk(mLock);
|
||||
const auto i = mMap.find(handle);
|
||||
if (i == mMap.end()) {
|
||||
return BAD_VALUE;
|
||||
}
|
||||
sp<BaseSensorObject> s = i->second.promote();
|
||||
if (s == nullptr) {
|
||||
// sensor object is already gone
|
||||
return BAD_VALUE;
|
||||
sp<BaseSensorObject> s;
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(mLock);
|
||||
const auto i = mMap.find(handle);
|
||||
if (i == mMap.end()) {
|
||||
return BAD_VALUE;
|
||||
}
|
||||
s = i->second.promote();
|
||||
if (s == nullptr) {
|
||||
// sensor object is already gone
|
||||
return BAD_VALUE;
|
||||
}
|
||||
}
|
||||
return f(s);
|
||||
}
|
||||
|
@ -111,6 +114,7 @@ private:
|
|||
// available sensor handle space
|
||||
const std::pair<int, int> mHandleRange;
|
||||
sensor_t mMetaSensor;
|
||||
bool mMetaSensorActive = false;
|
||||
|
||||
// immutable pointer to event callback, used in extention mode.
|
||||
SensorEventCallback * const mCallback;
|
||||
|
|
239
modules/sensors/dynamic_sensor/DynamicSensorsSubHal.cpp
Normal file
239
modules/sensors/dynamic_sensor/DynamicSensorsSubHal.cpp
Normal file
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
* Copyright (C) 2021 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 "BaseSensorObject.h"
|
||||
#include "DynamicSensorsSubHal.h"
|
||||
|
||||
#include <convertV2_1.h>
|
||||
#include <hardware/sensors-base.h>
|
||||
#include <log/log.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
using ::android::hardware::sensors::V1_0::Result;
|
||||
using ::android::hardware::sensors::V2_0::implementation::ScopedWakelock;
|
||||
using ::android::hardware::sensors::V2_1::implementation::convertFromSensorEvent;
|
||||
using ::android::hardware::sensors::V2_1::SensorInfo;
|
||||
using ::android::hardware::sensors::V2_1::SensorType;
|
||||
template<class T> using Return = ::android::hardware::Return<T>;
|
||||
using ::android::hardware::Void;
|
||||
|
||||
namespace android {
|
||||
namespace SensorHalExt {
|
||||
|
||||
static Result ResultFromStatus(status_t err) {
|
||||
switch (err) {
|
||||
case ::android::OK:
|
||||
return Result::OK;
|
||||
case ::android::PERMISSION_DENIED:
|
||||
return Result::PERMISSION_DENIED;
|
||||
case ::android::NO_MEMORY:
|
||||
return Result::NO_MEMORY;
|
||||
case ::android::BAD_VALUE:
|
||||
return Result::BAD_VALUE;
|
||||
default:
|
||||
return Result::INVALID_OPERATION;
|
||||
}
|
||||
}
|
||||
|
||||
DynamicSensorsSubHal::DynamicSensorsSubHal() {
|
||||
// initialize dynamic sensor manager
|
||||
mDynamicSensorManager.reset(
|
||||
DynamicSensorManager::createInstance(kDynamicHandleBase,
|
||||
kMaxDynamicHandleCount,
|
||||
this /* callback */));
|
||||
}
|
||||
|
||||
// ISensors.
|
||||
Return<Result> DynamicSensorsSubHal::setOperationMode(OperationMode mode) {
|
||||
return (mode == static_cast<OperationMode>(SENSOR_HAL_NORMAL_MODE) ?
|
||||
Result::OK : Result::BAD_VALUE);
|
||||
}
|
||||
|
||||
Return<Result> DynamicSensorsSubHal::activate(int32_t sensor_handle,
|
||||
bool enabled) {
|
||||
int rc = mDynamicSensorManager->activate(sensor_handle, enabled);
|
||||
return ResultFromStatus(rc);
|
||||
}
|
||||
|
||||
Return<Result> DynamicSensorsSubHal::batch(
|
||||
int32_t sensor_handle, int64_t sampling_period_ns,
|
||||
int64_t max_report_latency_ns) {
|
||||
int rc = mDynamicSensorManager->batch(sensor_handle, sampling_period_ns,
|
||||
max_report_latency_ns);
|
||||
return ResultFromStatus(rc);
|
||||
}
|
||||
|
||||
Return<Result> DynamicSensorsSubHal::flush(int32_t sensor_handle) {
|
||||
int rc = mDynamicSensorManager->flush(sensor_handle);
|
||||
return ResultFromStatus(rc);
|
||||
}
|
||||
|
||||
Return<void> DynamicSensorsSubHal::registerDirectChannel(
|
||||
const SharedMemInfo& mem __unused,
|
||||
registerDirectChannel_cb callback __unused) {
|
||||
ALOGE("DynamicSensorsSubHal::registerDirectChannel not supported.");
|
||||
|
||||
return Void();
|
||||
}
|
||||
|
||||
Return<Result> DynamicSensorsSubHal::unregisterDirectChannel(
|
||||
int32_t channel_handle __unused) {
|
||||
ALOGE("DynamicSensorsSubHal::unregisterDirectChannel not supported.");
|
||||
|
||||
return Result::INVALID_OPERATION;
|
||||
}
|
||||
|
||||
Return<void> DynamicSensorsSubHal::configDirectReport(
|
||||
int32_t sensor_handle __unused, int32_t channel_handle __unused,
|
||||
RateLevel rate __unused, configDirectReport_cb callback __unused) {
|
||||
ALOGE("DynamicSensorsSubHal::configDirectReport not supported.");
|
||||
|
||||
return Void();
|
||||
}
|
||||
|
||||
Return<void> DynamicSensorsSubHal::getSensorsList_2_1(
|
||||
getSensorsList_2_1_cb callback) {
|
||||
const sensor_t& sensor_info = mDynamicSensorManager->getDynamicMetaSensor();
|
||||
std::vector<SensorInfo> sensors;
|
||||
|
||||
ALOGD("DynamicSensorsSubHal::getSensorsList_2_1 invoked.");
|
||||
|
||||
// get the dynamic sensor info
|
||||
sensors.resize(1);
|
||||
sensors[0].sensorHandle = sensor_info.handle;
|
||||
sensors[0].name = sensor_info.name;
|
||||
sensors[0].vendor = sensor_info.vendor;
|
||||
sensors[0].version = 1;
|
||||
sensors[0].type = static_cast<SensorType>(sensor_info.type);
|
||||
sensors[0].typeAsString = sensor_info.stringType;
|
||||
sensors[0].maxRange = sensor_info.maxRange;
|
||||
sensors[0].resolution = sensor_info.resolution;
|
||||
sensors[0].power = sensor_info.power;
|
||||
sensors[0].minDelay = sensor_info.minDelay;
|
||||
sensors[0].fifoReservedEventCount = sensor_info.fifoReservedEventCount;
|
||||
sensors[0].fifoMaxEventCount = sensor_info.fifoMaxEventCount;
|
||||
sensors[0].requiredPermission = sensor_info.requiredPermission;
|
||||
sensors[0].maxDelay = sensor_info.maxDelay;
|
||||
sensors[0].flags = sensor_info.flags;
|
||||
|
||||
callback(sensors);
|
||||
|
||||
return Void();
|
||||
}
|
||||
|
||||
Return<Result> DynamicSensorsSubHal::injectSensorData_2_1(
|
||||
const Event& event __unused) {
|
||||
ALOGE("DynamicSensorsSubHal::injectSensorData_2_1 not supported.");
|
||||
|
||||
return Result::INVALID_OPERATION;
|
||||
}
|
||||
|
||||
Return<void> DynamicSensorsSubHal::debug(
|
||||
const hidl_handle& handle __unused,
|
||||
const hidl_vec<hidl_string>& args __unused) {
|
||||
return Void();
|
||||
}
|
||||
|
||||
// ISensorsSubHal.
|
||||
Return<Result> DynamicSensorsSubHal::initialize(
|
||||
const sp<IHalProxyCallback>& hal_proxy_callback) {
|
||||
ALOGD("DynamicSensorsSubHal::initialize invoked.");
|
||||
|
||||
mHalProxyCallback = hal_proxy_callback;
|
||||
|
||||
return Result::OK;
|
||||
}
|
||||
|
||||
// SensorEventCallback.
|
||||
int DynamicSensorsSubHal::submitEvent(SP(BaseSensorObject) sensor,
|
||||
const sensors_event_t& e) {
|
||||
std::vector<Event> events;
|
||||
Event hal_event;
|
||||
bool wakeup;
|
||||
|
||||
if (e.type == SENSOR_TYPE_DYNAMIC_SENSOR_META) {
|
||||
const dynamic_sensor_meta_event_t* sensor_meta;
|
||||
|
||||
sensor_meta = static_cast<const dynamic_sensor_meta_event_t*>(
|
||||
&(e.dynamic_sensor_meta));
|
||||
if (sensor_meta->connected != 0) {
|
||||
// The sensor framework must be notified of the connected sensor
|
||||
// through the callback before handling the sensor added event. If
|
||||
// it isn't, it will assert when looking up the sensor handle when
|
||||
// processing the sensor added event.
|
||||
//
|
||||
// TODO (b/201529167): Fix dynamic sensors addition / removal when
|
||||
// converting to AIDL.
|
||||
// The sensor framework runs in a separate process from the sensor
|
||||
// HAL, and it processes events in a dedicated thread, so it's
|
||||
// possible the event handling can be done before the callback is
|
||||
// run. Thus, a delay is added after sending notification of the
|
||||
// connected sensor.
|
||||
onSensorConnected(sensor_meta->handle, sensor_meta->sensor);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
}
|
||||
}
|
||||
|
||||
convertFromSensorEvent(e, &hal_event);
|
||||
events.push_back(hal_event);
|
||||
if (sensor && sensor->getSensor()) {
|
||||
wakeup = sensor->getSensor()->flags & SENSOR_FLAG_WAKE_UP;
|
||||
} else {
|
||||
wakeup = false;
|
||||
}
|
||||
ScopedWakelock wakelock = mHalProxyCallback->createScopedWakelock(wakeup);
|
||||
mHalProxyCallback->postEvents(events, std::move(wakelock));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DynamicSensorsSubHal::onSensorConnected(
|
||||
int handle, const sensor_t* sensor_info) {
|
||||
hidl_vec<SensorInfo> sensor_list;
|
||||
|
||||
sensor_list.resize(1);
|
||||
sensor_list[0].sensorHandle = handle;
|
||||
sensor_list[0].name = sensor_info->name;
|
||||
sensor_list[0].vendor = sensor_info->vendor;
|
||||
sensor_list[0].version = 1;
|
||||
sensor_list[0].type = static_cast<SensorType>(sensor_info->type);
|
||||
sensor_list[0].typeAsString = sensor_info->stringType;
|
||||
sensor_list[0].maxRange = sensor_info->maxRange;
|
||||
sensor_list[0].resolution = sensor_info->resolution;
|
||||
sensor_list[0].power = sensor_info->power;
|
||||
sensor_list[0].minDelay = sensor_info->minDelay;
|
||||
sensor_list[0].fifoReservedEventCount = sensor_info->fifoReservedEventCount;
|
||||
sensor_list[0].fifoMaxEventCount = sensor_info->fifoMaxEventCount;
|
||||
sensor_list[0].requiredPermission = sensor_info->requiredPermission;
|
||||
sensor_list[0].maxDelay = sensor_info->maxDelay;
|
||||
sensor_list[0].flags = sensor_info->flags;
|
||||
|
||||
mHalProxyCallback->onDynamicSensorsConnected_2_1(sensor_list);
|
||||
}
|
||||
|
||||
} // namespace SensorHalExt
|
||||
} // namespace android
|
||||
|
||||
using ::android::hardware::sensors::V2_1::implementation::ISensorsSubHal;
|
||||
ISensorsSubHal* sensorsHalGetSubHal_2_1(uint32_t* version) {
|
||||
static android::SensorHalExt::DynamicSensorsSubHal subHal;
|
||||
|
||||
*version = SUB_HAL_2_1_VERSION;
|
||||
return &subHal;
|
||||
}
|
||||
|
89
modules/sensors/dynamic_sensor/DynamicSensorsSubHal.h
Normal file
89
modules/sensors/dynamic_sensor/DynamicSensorsSubHal.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright (C) 2021 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_DYNAMIC_SENSORS_SUB_HAL_H
|
||||
#define ANDROID_SENSORHAL_EXT_DYNAMIC_SENSORS_SUB_HAL_H
|
||||
|
||||
#include "DynamicSensorManager.h"
|
||||
|
||||
#include <V2_1/SubHal.h>
|
||||
|
||||
namespace android {
|
||||
namespace SensorHalExt {
|
||||
|
||||
class DynamicSensorsSubHal :
|
||||
public SensorEventCallback,
|
||||
public ::android::hardware::sensors::V2_1::implementation::ISensorsSubHal {
|
||||
using Event = ::android::hardware::sensors::V2_1::Event;
|
||||
using hidl_handle = ::android::hardware::hidl_handle;
|
||||
using hidl_string = ::android::hardware::hidl_string;
|
||||
template<class T> using hidl_vec = ::android::hardware::hidl_vec<T>;
|
||||
using IHalProxyCallback =
|
||||
::android::hardware::sensors::V2_1::implementation::IHalProxyCallback;
|
||||
using OperationMode = ::android::hardware::sensors::V1_0::OperationMode;
|
||||
using RateLevel = ::android::hardware::sensors::V1_0::RateLevel;
|
||||
using Result = ::android::hardware::sensors::V1_0::Result;
|
||||
template<class T> using Return = ::android::hardware::Return<T>;
|
||||
using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo;
|
||||
|
||||
public:
|
||||
DynamicSensorsSubHal();
|
||||
|
||||
// ISensors.
|
||||
Return<Result> setOperationMode(OperationMode mode) override;
|
||||
Return<Result> activate(int32_t sensor_handle, bool enabled) override;
|
||||
Return<Result> batch(int32_t sensor_handle, int64_t sampling_period_ns,
|
||||
int64_t max_report_latency_ns) override;
|
||||
Return<Result> flush(int32_t sensor_handle) override;
|
||||
Return<void> registerDirectChannel(
|
||||
const SharedMemInfo& mem,
|
||||
registerDirectChannel_cb callback) override;
|
||||
Return<Result> unregisterDirectChannel(int32_t channel_handle) override;
|
||||
Return<void> configDirectReport(
|
||||
int32_t sensor_handle, int32_t channel_handle, RateLevel rate,
|
||||
configDirectReport_cb callback) override;
|
||||
Return<void> getSensorsList_2_1(getSensorsList_2_1_cb callback) override;
|
||||
Return<Result> injectSensorData_2_1(const Event& event) override;
|
||||
Return<void> debug(
|
||||
const hidl_handle& handle,
|
||||
const hidl_vec<hidl_string>& args) override;
|
||||
|
||||
// ISensorsSubHal.
|
||||
const std::string getName() override { return "Dynamic-SubHAL"; }
|
||||
Return<Result> initialize(
|
||||
const sp<IHalProxyCallback>& hal_proxy_callback) override;
|
||||
|
||||
// SensorEventCallback.
|
||||
int submitEvent(SP(BaseSensorObject) sensor,
|
||||
const sensors_event_t& e) override;
|
||||
|
||||
private:
|
||||
static constexpr int32_t kDynamicHandleBase = 0;
|
||||
static constexpr int32_t kDynamicHandleEnd = 0x1000000;
|
||||
static constexpr int32_t kMaxDynamicHandleCount = kDynamicHandleEnd -
|
||||
kDynamicHandleBase;
|
||||
|
||||
void onSensorConnected(int handle, const sensor_t* sensor_info);
|
||||
|
||||
std::unique_ptr<DynamicSensorManager> mDynamicSensorManager;
|
||||
sp<IHalProxyCallback> mHalProxyCallback;
|
||||
};
|
||||
|
||||
} // namespace SensorHalExt
|
||||
} // namespace android
|
||||
|
||||
#endif // ANDROID_SENSORHAL_EXT_DYNAMIC_SENSORS_SUB_HAL_H
|
||||
|
|
@ -19,6 +19,8 @@
|
|||
#include <utils/Errors.h>
|
||||
#include "HidLog.h"
|
||||
|
||||
#include <HidUtils.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cfloat>
|
||||
#include <codecvt>
|
||||
|
@ -490,13 +492,8 @@ bool HidRawSensor::populateFeatureValueFromFeatureReport(
|
|||
}
|
||||
break;
|
||||
case SENSOR_DESCRIPTION:
|
||||
if (!r.isByteAligned() || r.bitSize != 16 || r.count < 1
|
||||
|| (r.bitOffset / 8 + r.count * 2) > buffer.size() ) {
|
||||
// invalid description
|
||||
break;
|
||||
}
|
||||
if (decodeString(r, buffer, &str)) {
|
||||
mFeatureInfo.isAndroidCustom = detectAndroidCustomSensor(str);
|
||||
detectSensorFromDescription(str);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -581,26 +578,34 @@ bool HidRawSensor::validateFeatureValueAndBuildSensor() {
|
|||
|
||||
bool HidRawSensor::decodeString(
|
||||
const HidParser::ReportItem &report, const std::vector<uint8_t> &buffer, std::string *d) {
|
||||
if (!report.isByteAligned() || report.bitSize != 16 || report.count < 1) {
|
||||
if (!report.isByteAligned() ||
|
||||
(report.bitSize != 8 && report.bitSize != 16) || report.count < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t charSize = report.bitSize / 8;
|
||||
size_t offset = report.bitOffset / 8;
|
||||
if (offset + report.count * 2 > buffer.size()) {
|
||||
if (offset + report.count * charSize > buffer.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint16_t> data(report.count);
|
||||
auto i = data.begin();
|
||||
auto j = buffer.begin() + offset;
|
||||
for ( ; i != data.end(); ++i, j += sizeof(uint16_t)) {
|
||||
// hid specified little endian
|
||||
*i = *j + (*(j + 1) << 8);
|
||||
}
|
||||
std::wstring wstr(data.begin(), data.end());
|
||||
if (charSize == 1) {
|
||||
*d = std::string(buffer.begin() + offset,
|
||||
buffer.begin() + offset + report.count);
|
||||
} else {
|
||||
std::vector<uint16_t> data(report.count);
|
||||
auto i = data.begin();
|
||||
auto j = buffer.begin() + offset;
|
||||
for ( ; i != data.end(); ++i, j += sizeof(uint16_t)) {
|
||||
// hid specified little endian
|
||||
*i = *j + (*(j + 1) << 8);
|
||||
}
|
||||
std::wstring wstr(data.begin(), data.end());
|
||||
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
|
||||
*d = converter.to_bytes(wstr);
|
||||
}
|
||||
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
|
||||
*d = converter.to_bytes(wstr);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -619,6 +624,28 @@ std::vector<std::string> split(const std::string &text, char sep) {
|
|||
return tokens;
|
||||
}
|
||||
|
||||
void HidRawSensor::detectSensorFromDescription(const std::string &description) {
|
||||
if (detectAndroidHeadTrackerSensor(description) ||
|
||||
detectAndroidCustomSensor(description)) {
|
||||
mFeatureInfo.isAndroidCustom = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool HidRawSensor::detectAndroidHeadTrackerSensor(
|
||||
const std::string &description) {
|
||||
if (description.find("#AndroidHeadTracker#1.") != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mFeatureInfo.type = SENSOR_TYPE_DEVICE_PRIVATE_BASE;
|
||||
mFeatureInfo.typeString = CUSTOM_TYPE_PREFIX + "headtracker";
|
||||
mFeatureInfo.reportModeFlag = SENSOR_FLAG_CONTINUOUS_MODE;
|
||||
mFeatureInfo.permission = "";
|
||||
mFeatureInfo.isWakeUp = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HidRawSensor::detectAndroidCustomSensor(const std::string &description) {
|
||||
size_t nullPosition = description.find('\0');
|
||||
if (nullPosition == std::string::npos) {
|
||||
|
@ -784,50 +811,83 @@ bool HidRawSensor::detectAndroidCustomSensor(const std::string &description) {
|
|||
}
|
||||
|
||||
bool HidRawSensor::findSensorControlUsage(const std::vector<HidParser::ReportPacket> &packets) {
|
||||
using namespace Hid::Sensor::PowerStateUsage;
|
||||
using namespace Hid::Sensor::PropertyUsage;
|
||||
using namespace Hid::Sensor::RawMinMax;
|
||||
using namespace Hid::Sensor::ReportingStateUsage;
|
||||
|
||||
//REPORTING_STATE
|
||||
const HidParser::ReportItem *reportingState
|
||||
= find(packets, REPORTING_STATE, HidParser::REPORT_TYPE_FEATURE);
|
||||
|
||||
if (reportingState == nullptr
|
||||
|| !reportingState->isByteAligned()
|
||||
|| reportingState->bitSize != 8
|
||||
|| reportingState->minRaw != REPORTING_STATE_MIN
|
||||
|| reportingState->maxRaw != REPORTING_STATE_MAX) {
|
||||
if (reportingState == nullptr) {
|
||||
LOG_W << "Cannot find valid reporting state feature" << LOG_ENDL;
|
||||
} else {
|
||||
mReportingStateId = reportingState->id;
|
||||
mReportingStateOffset = reportingState->bitOffset / 8;
|
||||
mReportingStateBitOffset = reportingState->bitOffset;
|
||||
mReportingStateBitSize = reportingState->bitSize;
|
||||
|
||||
mReportingStateDisableIndex = -1;
|
||||
mReportingStateEnableIndex = -1;
|
||||
for (unsigned i = 0; i < reportingState->usageVector.size(); ++i) {
|
||||
if (reportingState->usageVector[i] == REPORTING_STATE_NO_EVENTS) {
|
||||
mReportingStateDisableIndex = i;
|
||||
}
|
||||
if (reportingState->usageVector[i] == REPORTING_STATE_ALL_EVENTS) {
|
||||
mReportingStateEnableIndex = i;
|
||||
}
|
||||
}
|
||||
if (mReportingStateDisableIndex < 0) {
|
||||
LOG_W << "Cannot find reporting state to disable sensor"
|
||||
<< LOG_ENDL;
|
||||
mReportingStateId = -1;
|
||||
}
|
||||
if (mReportingStateEnableIndex < 0) {
|
||||
LOG_W << "Cannot find reporting state to enable sensor" << LOG_ENDL;
|
||||
mReportingStateId = -1;
|
||||
}
|
||||
}
|
||||
|
||||
//POWER_STATE
|
||||
const HidParser::ReportItem *powerState
|
||||
= find(packets, POWER_STATE, HidParser::REPORT_TYPE_FEATURE);
|
||||
if (powerState == nullptr
|
||||
|| !powerState->isByteAligned()
|
||||
|| powerState->bitSize != 8
|
||||
|| powerState->minRaw != POWER_STATE_MIN
|
||||
|| powerState->maxRaw != POWER_STATE_MAX) {
|
||||
if (powerState == nullptr) {
|
||||
LOG_W << "Cannot find valid power state feature" << LOG_ENDL;
|
||||
} else {
|
||||
mPowerStateId = powerState->id;
|
||||
mPowerStateOffset = powerState->bitOffset / 8;
|
||||
mPowerStateBitOffset = powerState->bitOffset;
|
||||
mPowerStateBitSize = powerState->bitSize;
|
||||
|
||||
mPowerStateOffIndex = -1;
|
||||
mPowerStateOnIndex = -1;
|
||||
for (unsigned i = 0; i < powerState->usageVector.size(); ++i) {
|
||||
if (powerState->usageVector[i] == POWER_STATE_D4_POWER_OFF) {
|
||||
mPowerStateOffIndex = i;
|
||||
}
|
||||
if (powerState->usageVector[i] == POWER_STATE_D0_FULL_POWER) {
|
||||
mPowerStateOnIndex = i;
|
||||
}
|
||||
}
|
||||
if (mPowerStateOffIndex < 0) {
|
||||
LOG_W << "Cannot find power state to power off sensor"
|
||||
<< LOG_ENDL;
|
||||
mPowerStateId = -1;
|
||||
}
|
||||
if (mPowerStateOnIndex < 0) {
|
||||
LOG_W << "Cannot find power state to power on sensor" << LOG_ENDL;
|
||||
mPowerStateId = -1;
|
||||
}
|
||||
}
|
||||
|
||||
//REPORT_INTERVAL
|
||||
const HidParser::ReportItem *reportInterval
|
||||
= find(packets, REPORT_INTERVAL, HidParser::REPORT_TYPE_FEATURE);
|
||||
if (reportInterval == nullptr
|
||||
|| !reportInterval->isByteAligned()
|
||||
|| reportInterval->minRaw < 0
|
||||
|| (reportInterval->bitSize != 16 && reportInterval->bitSize != 32)) {
|
||||
|| reportInterval->minRaw < 0) {
|
||||
LOG_W << "Cannot find valid report interval feature" << LOG_ENDL;
|
||||
} else {
|
||||
mReportIntervalId = reportInterval->id;
|
||||
mReportIntervalOffset = reportInterval->bitOffset / 8;
|
||||
mReportIntervalSize = reportInterval->bitSize / 8;
|
||||
mReportIntervalBitOffset = reportInterval->bitOffset;
|
||||
mReportIntervalBitSize = reportInterval->bitSize;
|
||||
|
||||
mFeatureInfo.minDelay = std::max(static_cast<int64_t>(1), reportInterval->minRaw) * 1000;
|
||||
mFeatureInfo.maxDelay = std::min(static_cast<int64_t>(1000000),
|
||||
|
@ -846,7 +906,6 @@ void HidRawSensor::getUuid(uint8_t* uuid) const {
|
|||
}
|
||||
|
||||
int HidRawSensor::enable(bool enable) {
|
||||
using namespace Hid::Sensor::StateValue;
|
||||
SP(HidDevice) device = PROMOTE(mDevice);
|
||||
|
||||
if (device == nullptr) {
|
||||
|
@ -863,8 +922,11 @@ int HidRawSensor::enable(bool enable) {
|
|||
setPowerOk = false;
|
||||
uint8_t id = static_cast<uint8_t>(mPowerStateId);
|
||||
if (device->getFeature(id, &buffer)
|
||||
&& buffer.size() > mPowerStateOffset) {
|
||||
buffer[mPowerStateOffset] = enable ? POWER_STATE_FULL_POWER : POWER_STATE_POWER_OFF;
|
||||
&& (8 * buffer.size()) >=
|
||||
(mPowerStateBitOffset + mPowerStateBitSize)) {
|
||||
uint8_t index = enable ? mPowerStateOnIndex : mPowerStateOffIndex;
|
||||
HidUtil::copyBits(&index, &(buffer[0]), buffer.size(),
|
||||
0, mPowerStateBitOffset, mPowerStateBitSize);
|
||||
setPowerOk = device->setFeature(id, buffer);
|
||||
} else {
|
||||
LOG_E << "enable: changing POWER STATE failed" << LOG_ENDL;
|
||||
|
@ -876,9 +938,12 @@ int HidRawSensor::enable(bool enable) {
|
|||
setReportingOk = false;
|
||||
uint8_t id = static_cast<uint8_t>(mReportingStateId);
|
||||
if (device->getFeature(id, &buffer)
|
||||
&& buffer.size() > mReportingStateOffset) {
|
||||
buffer[mReportingStateOffset]
|
||||
= enable ? REPORTING_STATE_ALL_EVENT : REPORTING_STATE_NO_EVENT;
|
||||
&& (8 * buffer.size()) >
|
||||
(mReportingStateBitOffset + mReportingStateBitSize)) {
|
||||
uint8_t index = enable ? mReportingStateEnableIndex :
|
||||
mReportingStateDisableIndex;
|
||||
HidUtil::copyBits(&index, &(buffer[0]), buffer.size(),0,
|
||||
mReportingStateBitOffset, mReportingStateBitSize);
|
||||
setReportingOk = device->setFeature(id, buffer);
|
||||
} else {
|
||||
LOG_E << "enable: changing REPORTING STATE failed" << LOG_ENDL;
|
||||
|
@ -911,22 +976,15 @@ int HidRawSensor::batch(int64_t samplingPeriod, int64_t batchingPeriod) {
|
|||
ok = false;
|
||||
uint8_t id = static_cast<uint8_t>(mReportIntervalId);
|
||||
if (device->getFeature(id, &buffer)
|
||||
&& buffer.size() >= mReportIntervalOffset + mReportIntervalSize) {
|
||||
&& (8 * buffer.size()) >=
|
||||
(mReportIntervalBitOffset + mReportIntervalBitSize)) {
|
||||
int64_t periodMs = samplingPeriod / 1000000; //ns -> ms
|
||||
switch (mReportIntervalSize) {
|
||||
case sizeof(uint16_t):
|
||||
periodMs = std::min(periodMs, static_cast<int64_t>(UINT16_MAX));
|
||||
buffer[mReportIntervalOffset] = periodMs & 0xFF;
|
||||
buffer[mReportIntervalOffset + 1] = (periodMs >> 8) & 0xFF;
|
||||
break;
|
||||
case sizeof(uint32_t):
|
||||
periodMs = std::min(periodMs, static_cast<int64_t>(UINT32_MAX));
|
||||
buffer[mReportIntervalOffset] = periodMs & 0xFF;
|
||||
buffer[mReportIntervalOffset + 1] = (periodMs >> 8) & 0xFF;
|
||||
buffer[mReportIntervalOffset + 2] = (periodMs >> 16) & 0xFF;
|
||||
buffer[mReportIntervalOffset + 3] = (periodMs >> 24) & 0xFF;
|
||||
break;
|
||||
}
|
||||
int64_t maxPeriodMs =
|
||||
(1LL << std::min(mReportIntervalBitSize, 63U)) - 1;
|
||||
periodMs = std::min(periodMs, maxPeriodMs);
|
||||
HidUtil::copyBits(&periodMs, &(buffer[0]), buffer.size(),
|
||||
0, mReportIntervalBitOffset,
|
||||
mReportIntervalBitSize);
|
||||
ok = device->setFeature(id, buffer);
|
||||
}
|
||||
}
|
||||
|
@ -1019,7 +1077,11 @@ std::string HidRawSensor::dump() const {
|
|||
ss << " Power state ";
|
||||
if (mPowerStateId >= 0) {
|
||||
ss << "found, id: " << mPowerStateId
|
||||
<< " offset: " << mPowerStateOffset << LOG_ENDL;
|
||||
<< " bit offset: " << mPowerStateBitOffset
|
||||
<< " bit size: " << mPowerStateBitSize
|
||||
<< " power off index: " << mPowerStateOffIndex
|
||||
<< " power on index: " << mPowerStateOnIndex
|
||||
<< LOG_ENDL;
|
||||
} else {
|
||||
ss << "not found" << LOG_ENDL;
|
||||
}
|
||||
|
@ -1027,7 +1089,11 @@ std::string HidRawSensor::dump() const {
|
|||
ss << " Reporting state ";
|
||||
if (mReportingStateId >= 0) {
|
||||
ss << "found, id: " << mReportingStateId
|
||||
<< " offset: " << mReportingStateOffset << LOG_ENDL;
|
||||
<< " bit offset: " << mReportingStateBitOffset
|
||||
<< " bit size: " << mReportingStateBitSize
|
||||
<< " disable index: " << mReportingStateDisableIndex
|
||||
<< " enable index: " << mReportingStateEnableIndex
|
||||
<< LOG_ENDL;
|
||||
} else {
|
||||
ss << "not found" << LOG_ENDL;
|
||||
}
|
||||
|
@ -1035,8 +1101,8 @@ std::string HidRawSensor::dump() const {
|
|||
ss << " Report interval ";
|
||||
if (mReportIntervalId >= 0) {
|
||||
ss << "found, id: " << mReportIntervalId
|
||||
<< " offset: " << mReportIntervalOffset
|
||||
<< " size: " << mReportIntervalSize << LOG_ENDL;
|
||||
<< " bit offset: " << mReportIntervalBitOffset
|
||||
<< " bit size: " << mReportIntervalBitSize << LOG_ENDL;
|
||||
} else {
|
||||
ss << "not found" << LOG_ENDL;
|
||||
}
|
||||
|
|
|
@ -121,6 +121,14 @@ private:
|
|||
// 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 any
|
||||
// known sensors
|
||||
void detectSensorFromDescription(const std::string &description);
|
||||
|
||||
// try to parse sensor description feature value to see if it matches the
|
||||
// Android header tracker sensor
|
||||
bool detectAndroidHeadTrackerSensor(const std::string &description);
|
||||
|
||||
// try to parse sensor description feature value to see if it matches
|
||||
// android specified custom sensor definition.
|
||||
bool detectAndroidCustomSensor(const std::string &description);
|
||||
|
@ -137,14 +145,20 @@ private:
|
|||
|
||||
// Features for control sensor
|
||||
int mReportingStateId;
|
||||
unsigned int mReportingStateOffset;
|
||||
unsigned int mReportingStateBitOffset;
|
||||
unsigned int mReportingStateBitSize;
|
||||
int mReportingStateDisableIndex;
|
||||
int mReportingStateEnableIndex;
|
||||
|
||||
int mPowerStateId;
|
||||
unsigned int mPowerStateOffset;
|
||||
unsigned int mPowerStateBitOffset;
|
||||
unsigned int mPowerStateBitSize;
|
||||
int mPowerStateOffIndex;
|
||||
int mPowerStateOnIndex;
|
||||
|
||||
int mReportIntervalId;
|
||||
unsigned int mReportIntervalOffset;
|
||||
unsigned int mReportIntervalSize;
|
||||
unsigned int mReportIntervalBitOffset;
|
||||
unsigned int mReportIntervalBitSize;
|
||||
|
||||
// Input report translate table
|
||||
std::vector<ReportTranslateRecord> mTranslateTable;
|
||||
|
|
|
@ -39,6 +39,7 @@ HidRawSensorDaemon::HidRawSensorDaemon(DynamicSensorManager& manager)
|
|||
: BaseDynamicSensorDaemon(manager) {
|
||||
mDetector = new FileConnectionDetector(
|
||||
this, std::string(DEV_PATH), std::string(DEV_NAME_REGEX));
|
||||
mDetector->Init();
|
||||
}
|
||||
|
||||
BaseSensorVector HidRawSensorDaemon::createSensor(const std::string &deviceKey) {
|
||||
|
|
|
@ -77,24 +77,28 @@ enum {
|
|||
};
|
||||
} // namespace ReportUsage
|
||||
|
||||
namespace RawMinMax {
|
||||
namespace ReportingStateUsage {
|
||||
enum {
|
||||
REPORTING_STATE_MIN = 0,
|
||||
REPORTING_STATE_MAX = 5,
|
||||
POWER_STATE_MIN = 0,
|
||||
POWER_STATE_MAX = 5,
|
||||
REPORTING_STATE_NO_EVENTS = 0x0840,
|
||||
REPORTING_STATE_ALL_EVENTS = 0x0841,
|
||||
REPORTING_STATE_REPORT_THRESHOLD_EVENTS = 0x0842,
|
||||
REPORTING_STATE_REPORT_WAKE_ON_NO_EVENTS = 0x0843,
|
||||
REPORTING_STATE_REPORT_WAKE_ON_ALL_EVENTS = 0x0844,
|
||||
REPORTING_STATE_REPORT_WAKE_ON_THRESHOLD_EVENTS = 0x0845,
|
||||
};
|
||||
} // namespace RawMinMax
|
||||
} // namespace ReportingStateUsage
|
||||
|
||||
namespace StateValue {
|
||||
namespace PowerStateUsage {
|
||||
enum {
|
||||
POWER_STATE_FULL_POWER = 1,
|
||||
POWER_STATE_POWER_OFF = 5,
|
||||
|
||||
REPORTING_STATE_ALL_EVENT = 1,
|
||||
REPORTING_STATE_NO_EVENT = 0,
|
||||
POWER_STATE_UNDEFINED = 0x0850,
|
||||
POWER_STATE_D0_FULL_POWER = 0x0851,
|
||||
POWER_STATE_D1_LOW_POWER = 0x0852,
|
||||
POWER_STATE_D2_STANDBY_POWER_WITH_WAKEUP = 0x0853,
|
||||
POWER_STATE_D3_SLEEP_WITH_WAKEUP = 0x0854,
|
||||
POWER_STATE_D4_POWER_OFF = 0x0855,
|
||||
};
|
||||
} // StateValue
|
||||
} // namespace PowerStateUsage
|
||||
|
||||
} // namespace Sensor
|
||||
} // namespace Hid
|
||||
#endif // HID_SENSOR_DEF_H_
|
||||
|
|
|
@ -45,6 +45,7 @@ cc_library {
|
|||
"HidParser.cpp",
|
||||
"HidReport.cpp",
|
||||
"HidTree.cpp",
|
||||
"HidUtils.cpp",
|
||||
],
|
||||
export_include_dirs: ["."],
|
||||
|
||||
|
@ -99,3 +100,20 @@ cc_test_host {
|
|||
|
||||
local_include_dirs: ["test"],
|
||||
}
|
||||
|
||||
//
|
||||
// Test for HidUtils
|
||||
//
|
||||
cc_test_host {
|
||||
name: "hid_utils_test",
|
||||
defaults: ["hid_defaults"],
|
||||
|
||||
srcs: ["test/CopyBitsTest.cpp"],
|
||||
|
||||
shared_libs: [
|
||||
"libhidparser",
|
||||
],
|
||||
|
||||
local_include_dirs: ["test"],
|
||||
}
|
||||
|
||||
|
|
|
@ -248,6 +248,7 @@ std::vector<HidParser::ReportPacket> HidParser::convertGroupToPacket(
|
|||
ReportItem digest = {
|
||||
.usage = r.getFullUsage(),
|
||||
.id = id,
|
||||
.usageVector = r.getUsageVector(),
|
||||
.minRaw = logical.first,
|
||||
.maxRaw = logical.second,
|
||||
.a = scale,
|
||||
|
@ -316,4 +317,5 @@ std::ostream& operator<<(std::ostream &os, const HidParser::DigestVector &digest
|
|||
os << LOG_ENDL;
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace HidUtil
|
||||
|
|
|
@ -89,6 +89,7 @@ struct HidParser::ReportItem {
|
|||
unsigned int usage;
|
||||
unsigned int id;
|
||||
int type; // feature, input or output
|
||||
std::vector<unsigned int> usageVector;
|
||||
|
||||
int64_t minRaw;
|
||||
int64_t maxRaw;
|
||||
|
@ -173,6 +174,7 @@ struct HidParser::ReportPacket {
|
|||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream &os, const HidParser::DigestVector &digest2);
|
||||
|
||||
} // namespace HidUtil
|
||||
|
||||
#endif // HIDUTIL_HIDPARSER_H_
|
||||
|
|
72
modules/sensors/dynamic_sensor/HidUtils/HidUtils.cpp
Normal file
72
modules/sensors/dynamic_sensor/HidUtils/HidUtils.cpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (C) 2021 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 "HidUtils.h"
|
||||
#include <stdint.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace HidUtil {
|
||||
|
||||
void copyBits(const void *src, void *dst, size_t dst_size,
|
||||
unsigned int src_bit_offset, unsigned int dst_bit_offset,
|
||||
unsigned int bit_count) {
|
||||
const uint8_t *p_src;
|
||||
uint8_t *p_dst;
|
||||
uint8_t dst_mask;
|
||||
unsigned int bits_rem;
|
||||
unsigned int bit_block_count;
|
||||
|
||||
// Do nothing if copying past the end of the destination buffer.
|
||||
if ((static_cast<size_t>(dst_bit_offset) > (8 * dst_size)) ||
|
||||
(static_cast<size_t>(bit_count) > (8 * dst_size)) ||
|
||||
(static_cast<size_t>(dst_bit_offset + bit_count) > (8 * dst_size))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy bits from source to destination buffer.
|
||||
p_src = static_cast<const uint8_t*>(src) + (src_bit_offset / 8);
|
||||
src_bit_offset = src_bit_offset % 8;
|
||||
p_dst = static_cast<uint8_t*>(dst) + (dst_bit_offset / 8);
|
||||
dst_bit_offset = dst_bit_offset % 8;
|
||||
bits_rem = bit_count;
|
||||
while (bits_rem > 0) {
|
||||
// Determine the size of the next block of bits to copy. The block must
|
||||
// not cross a source or desintation byte boundary.
|
||||
bit_block_count = std::min(bits_rem, 8 - src_bit_offset);
|
||||
bit_block_count = std::min(bit_block_count, 8 - dst_bit_offset);
|
||||
|
||||
// Determine the destination bit block mask.
|
||||
dst_mask = ((1 << bit_block_count) - 1) << dst_bit_offset;
|
||||
|
||||
// Copy the block of bits.
|
||||
*p_dst = (*p_dst & ~dst_mask) |
|
||||
(((*p_src >> src_bit_offset) << dst_bit_offset) & dst_mask);
|
||||
|
||||
// Advance past the block of copied bits in the source.
|
||||
src_bit_offset += bit_block_count;
|
||||
p_src += src_bit_offset / 8;
|
||||
src_bit_offset = src_bit_offset % 8;
|
||||
|
||||
// Advance past the block of copied bits in the destination.
|
||||
dst_bit_offset += bit_block_count;
|
||||
p_dst += dst_bit_offset / 8;
|
||||
dst_bit_offset = dst_bit_offset % 8;
|
||||
|
||||
// Decrement the number of bits remaining.
|
||||
bits_rem -= bit_block_count;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace HidUtil
|
29
modules/sensors/dynamic_sensor/HidUtils/HidUtils.h
Normal file
29
modules/sensors/dynamic_sensor/HidUtils/HidUtils.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (C) 2021 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 HIDUTIL_HIDUTILS_H_
|
||||
#define HIDUTIL_HIDUTILS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace HidUtil {
|
||||
|
||||
void copyBits(const void *src, void *dst, size_t dst_size,
|
||||
unsigned int src_bit_offset, unsigned int dst_bit_offset,
|
||||
unsigned int bit_count);
|
||||
|
||||
} // namespace HidUtil
|
||||
|
||||
#endif // HIDUTIL_HIDUTILS_H_
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright (C) 2021 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 "HidUtils.h"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using HidUtil::copyBits;
|
||||
|
||||
TEST(CopyBitsTest, CopyBits) {
|
||||
const struct {
|
||||
uint32_t src;
|
||||
uint32_t dst;
|
||||
int src_bit_offset;
|
||||
int dst_bit_offset;
|
||||
int bit_count;
|
||||
uint32_t expected_dst;
|
||||
} kTestVectorList[] = {
|
||||
{ 0x00000005, 0x00000000, 0, 0, 8, 0x00000005 },
|
||||
{ 0x00000005, 0x00000000, 0, 4, 8, 0x00000050 },
|
||||
{ 0x0000000C, 0x00000020, 0, 4, 8, 0x000000C0 },
|
||||
{ 0x00000005, 0x0000F02F, 0, 4, 8, 0x0000F05F },
|
||||
{ 0x12345678, 0x87654321, 5, 11, 17, 0x8D159B21 },
|
||||
{ 0x12345678, 0x87654321, 11, 5, 17, 0x8748D141 },
|
||||
};
|
||||
|
||||
for (auto test_vector : kTestVectorList) {
|
||||
uint32_t dst = test_vector.dst;
|
||||
copyBits(&(test_vector.src), &dst, sizeof(dst),
|
||||
test_vector.src_bit_offset, test_vector.dst_bit_offset,
|
||||
test_vector.bit_count);
|
||||
EXPECT_EQ(test_vector.expected_dst, dst);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CopyBitsTest, Overflow) {
|
||||
const struct {
|
||||
uint32_t src;
|
||||
uint32_t dst;
|
||||
unsigned int src_bit_offset;
|
||||
unsigned int dst_bit_offset;
|
||||
unsigned int bit_count;
|
||||
uint32_t expected_dst;
|
||||
} kTestVectorList[] = {
|
||||
{ 0x000000FF, 0x00000000, 0, 0, 8, 0x000000FF },
|
||||
{ 0x000000FF, 0x00000000, 0, 24, 8, 0xFF000000 },
|
||||
{ 0x000000FF, 0x00000000, 0, 25, 8, 0x00000000 },
|
||||
{ 0x000000FF, 0x00000000, 0, 32, 8, 0x00000000 },
|
||||
{ 0x000000FF, 0x00000000, 0, UINT_MAX, 8, 0x00000000 },
|
||||
{ 0x000000FF, 0x00000000, 0, 8, UINT_MAX, 0x00000000 },
|
||||
};
|
||||
|
||||
for (auto test_vector : kTestVectorList) {
|
||||
uint32_t dst = test_vector.dst;
|
||||
copyBits(&(test_vector.src), &dst, sizeof(dst),
|
||||
test_vector.src_bit_offset, test_vector.dst_bit_offset,
|
||||
test_vector.bit_count);
|
||||
EXPECT_EQ(test_vector.expected_dst, dst);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in a new issue