diff options
-rw-r--r-- | tilt/Android.mk | 79 | ||||
-rw-r--r-- | tilt/InputEventReader.cpp | 114 | ||||
-rw-r--r-- | tilt/InputEventReader.h | 46 | ||||
-rw-r--r-- | tilt/SensorBase.cpp | 152 | ||||
-rw-r--r-- | tilt/SensorBase.h | 97 | ||||
-rw-r--r-- | tilt/TiltSensor.cpp | 219 | ||||
-rw-r--r-- | tilt/TiltSensor.h | 63 | ||||
-rw-r--r-- | tilt/clockwork_sensor.h | 65 | ||||
-rw-r--r-- | tilt/sensors.cpp | 333 | ||||
-rw-r--r-- | tilt/sensors.h | 61 |
10 files changed, 1229 insertions, 0 deletions
diff --git a/tilt/Android.mk b/tilt/Android.mk new file mode 100644 index 0000000..d26ba19 --- /dev/null +++ b/tilt/Android.mk @@ -0,0 +1,79 @@ +# Copyright (C) 2015 Intel Corp +# +# 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. +# + +LOCAL_PATH := $(call my-dir) + +# HAL module implemenation, not prelinked, and stored in +# hw/<SENSORS_HARDWARE_MODULE_ID>.<ro.product.board>.so +include $(CLEAR_VARS) + +# ANDROID version check +MAJOR_VERSION := $(shell echo $(PLATFORM_VERSION) | cut -f1 -d.) +MINOR_VERSION := $(shell echo $(PLATFORM_VERSION) | cut -f2 -d.) + +VERSION_JB := $(shell test $(MAJOR_VERSION) -eq 4 -a $(MINOR_VERSION) -eq 1 && echo true) +VERSION_JB := $(shell test $(MAJOR_VERSION) -eq 4 -a $(MINOR_VERSION) -eq 2 && echo true) +VERSION_JB_MR2 := $(shell test $(MAJOR_VERSION) -eq 4 -a $(MINOR_VERSION) -eq 3 && echo true) +VERSION_KK := $(shell test $(MAJOR_VERSION) -eq 4 -a $(MINOR_VERSION) -eq 4 && echo true) +VERSION_L := $(shell test $(MAJOR_VERSION) -eq 5 && echo true) +#ANDROID version check END + +LOCAL_MODULE := sensor_tilt.$(TARGET_DEVICE) + +LOCAL_PRELINK_MODULE := false +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw + +LOCAL_MODULE_TAGS := optional +# TODO: remove LOG_NDEBUG=0 for production builds, keep it during integration +LOCAL_CFLAGS := -DLOG_TAG=\"MvnSensors\" -DLOG_NDEBUG=0 +LOCAL_CFLAGS += -DINVENSENSE_COMPASS_CAL + +ifeq ($(VERSION_JB),true) +LOCAL_CFLAGS += -DANDROID_JB +endif + +ifeq ($(VERSION_JBMR2),true) +LOCAL_CFLAGS += -DANDROID_JBMR2 +#hal version is greater than and equal 1_0 +LOCAL_CFLAGS += -DHAL_VERSION_GE_1_0 +endif + +ifeq ($(VERSION_KK),true) +LOCAL_CFLAGS += -DANDROID_KK +#hal version is greater than and equal 1_0 +LOCAL_CFLAGS += -DHAL_VERSION_GE_1_0 +#hal version is greater than 1_0 +LOCAL_CFLAGS += -DHAL_VERSION_GT_1_0 +endif + +ifeq ($(VERSION_L),true) +LOCAL_CFLAGS += -DANDROID_L +#hal version is greater than and equal 1_0 +LOCAL_CFLAGS += -DHAL_VERSION_GE_1_0 +#hal version is greater than 1_0 +LOCAL_CFLAGS += -DHAL_VERSION_GT_1_0 +endif + +#LOCAL_C_INCLUDES += hardware/invensense/libsensors_iio +LOCAL_SRC_FILES := \ + sensors.cpp \ + InputEventReader.cpp \ + TiltSensor.cpp \ + SensorBase.cpp + +LOCAL_SHARED_LIBRARIES := liblog libutils libdl + +include $(BUILD_SHARED_LIBRARY) + diff --git a/tilt/InputEventReader.cpp b/tilt/InputEventReader.cpp new file mode 100644 index 0000000..6424501 --- /dev/null +++ b/tilt/InputEventReader.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2015 Intel Corp + * + * 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 <stdint.h> +#include <errno.h> +#include <unistd.h> +#include <poll.h> +#include <sys/cdefs.h> +#include <sys/types.h> +#include <linux/input.h> +#include <cutils/log.h> +#include "InputEventReader.h" + + + +struct input_event; + +InputEventCircularReader::InputEventCircularReader(size_t numEvents) + : mBuffer(new input_event[numEvents * 2]), + mBufferEnd(mBuffer + numEvents), + mHead(mBuffer), + mCurr(mBuffer), + mFreeSpace(numEvents) +{ + FUNC_LOG; + mLastFd = -1; +} + +InputEventCircularReader::~InputEventCircularReader() +{ + FUNC_LOG; + delete [] mBuffer; +} + +/* TODO: clear DEBUG flag on production builds, keep it during integration */ +#define INPUT_EVENT_DEBUG (1) +ssize_t InputEventCircularReader::fill(int fd) +{ + FUNC_LOG; + size_t numEventsRead = 0; + mLastFd = fd; + + LOGV_IF(INPUT_EVENT_DEBUG, + "DEBUG:%s enter, fd=%d\n", __PRETTY_FUNCTION__, fd); + if (mFreeSpace) { + const ssize_t nread = read(fd, mHead, mFreeSpace * sizeof(input_event)); + if (nread < 0 || nread % sizeof(input_event)) { + /* LOGE("Partial event received nread=%d, required=%d", + nread, sizeof(input_event)); + LOGE("FD trying to read is: %d"); */ + /* we got a partial event!! */ + if (INPUT_EVENT_DEBUG) { + LOGV_IF(nread < 0, "DEBUG:%s exit nread < 0\n", + __PRETTY_FUNCTION__); + LOGV_IF(nread % sizeof(input_event), + "DEBUG:%s exit nread %% sizeof(input_event)\n", + __PRETTY_FUNCTION__); + } + return (nread < 0 ? -errno : -EINVAL); + } + + numEventsRead = nread / sizeof(input_event); + if (numEventsRead) { + mHead += numEventsRead; + mFreeSpace -= numEventsRead; + if (mHead > mBufferEnd) { + size_t s = mHead - mBufferEnd; + memcpy(mBuffer, mBufferEnd, s * sizeof(input_event)); + mHead = mBuffer + s; + } + } + } + + LOGV_IF(INPUT_EVENT_DEBUG, "DEBUG:%s exit, numEventsRead:%d\n", + __PRETTY_FUNCTION__, numEventsRead); + return numEventsRead; +} + +ssize_t InputEventCircularReader::readEvent(input_event const** events) +{ + FUNC_LOG; + *events = mCurr; + ssize_t available = (mBufferEnd - mBuffer) - mFreeSpace; + LOGV_IF(INPUT_EVENT_DEBUG, "DEBUG:%s fd:%d, available:%d\n", + __PRETTY_FUNCTION__, mLastFd, (int)available); + return (available ? 1 : 0); +} + +void InputEventCircularReader::next() +{ + FUNC_LOG; + mCurr++; + mFreeSpace++; + if (mCurr >= mBufferEnd) + mCurr = mBuffer; + + ssize_t available = (mBufferEnd - mBuffer) - mFreeSpace; + LOGV_IF(INPUT_EVENT_DEBUG, "DEBUG:%s fd:%d, still available:%d\n", + __PRETTY_FUNCTION__, mLastFd, (int)available); +} + diff --git a/tilt/InputEventReader.h b/tilt/InputEventReader.h new file mode 100644 index 0000000..6e4350b --- /dev/null +++ b/tilt/InputEventReader.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2015 Intel Corp + * + * 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_INPUT_EVENT_READER_H +#define ANDROID_INPUT_EVENT_READER_H + +#include <stdint.h> +#include <errno.h> +#include <sys/cdefs.h> +#include <sys/types.h> + +#include "SensorBase.h" + + +struct input_event; + +class InputEventCircularReader +{ + struct input_event* const mBuffer; + struct input_event* const mBufferEnd; + struct input_event* mHead; + struct input_event* mCurr; + ssize_t mFreeSpace; + int mLastFd; + +public: + InputEventCircularReader(size_t numEvents); + ~InputEventCircularReader(); + ssize_t fill(int fd); + ssize_t readEvent(input_event const** events); + void next(); +}; +#endif // ANDROID_INPUT_EVENT_READER_H diff --git a/tilt/SensorBase.cpp b/tilt/SensorBase.cpp new file mode 100644 index 0000000..0106ec3 --- /dev/null +++ b/tilt/SensorBase.cpp @@ -0,0 +1,152 @@ +/* +* Copyright (C) 2015 Intel Corp +* +* 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 <fcntl.h> +#include <errno.h> +#include <math.h> +#include <poll.h> +#include <unistd.h> +#include <dirent.h> +#include <sys/select.h> +#include <cutils/log.h> +#include <linux/input.h> +#include "SensorBase.h" + + +SensorBase::SensorBase(const char* dev_name, + const char* data_name) : dev_name(dev_name), + data_name(data_name), + dev_fd(-1), + data_fd(-1) +{ + /* FUNC_LOG; */ + ALOGV("%s(): dev_name=%s, data_name=%s ", __func__, dev_name, data_name); + + if (data_name) + data_fd = openInput(data_name); + +} + +SensorBase::~SensorBase() { + FUNC_LOG; + if (data_fd >= 0) + close(data_fd); + + if (dev_fd >= 0) + close(dev_fd); + +} + +int SensorBase::open_device() { + FUNC_LOG; + if (dev_fd<0 && dev_name) { + dev_fd = open(dev_name, O_RDONLY); + LOGE_IF(dev_fd<0, "Couldn't open %s (%s)", dev_name, strerror(errno)); + } + return 0; +} + +int SensorBase::close_device() { + FUNC_LOG; + if (dev_fd >= 0) { + close(dev_fd); + dev_fd = -1; + } + return 0; +} + +int SensorBase::getFd() const { + FUNC_LOG; + if (!data_name) + return dev_fd; + + return data_fd; +} + +int SensorBase::setDelay(int32_t handle, int64_t ns) { + FUNC_LOG; + return 0; +} + +bool SensorBase::hasPendingEvents() const { + FUNC_LOG; + return false; +} + +int64_t SensorBase::getTimestamp() { + FUNC_LOG; + struct timespec t; + t.tv_sec = t.tv_nsec = 0; + clock_gettime(CLOCK_MONOTONIC, &t); + return int64_t(t.tv_sec) * 1000000000LL + t.tv_nsec; +} + +int SensorBase::openInput(const char* inputName) { + FUNC_LOG; + int fd = -1; + const char *dirname = "/dev/input"; + char devname[PATH_MAX]; + char *filename; + DIR *dir; + struct dirent *de; + dir = opendir(dirname); + if(dir == NULL) + return -1; + strcpy(devname, dirname); + filename = devname + strlen(devname); + *filename++ = '/'; + while((de = readdir(dir))) { + if(de->d_name[0] == '.' && + (de->d_name[1] == '\0' || + (de->d_name[1] == '.' && de->d_name[2] == '\0'))) + continue; + strcpy(filename, de->d_name); + fd = open(devname, O_RDONLY); + LOGV_IF(EXTRA_VERBOSE, "path open %s", devname); + LOGI("path open %s", devname); + if (fd >= 0) { + char name[80]; + if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) + name[0] = '\0'; + + LOGV_IF(EXTRA_VERBOSE, "name read %s", name); + if (!strcmp(name, inputName)) { + strcpy(input_name, filename); + break; + } else { + close(fd); + fd = -1; + } + } + } + closedir(dir); + LOGE_IF(fd < 0, "couldn't find '%s' input device", inputName); + return fd; +} + +int SensorBase::enable(int32_t handle, int enabled) +{ + FUNC_LOG; + return 0; +} + +#ifdef HAL_VERSION_GT_1_0 +int SensorBase::batch(int handle, int flags, int64_t period_ns, int64_t timeout) +{ + FUNC_LOG; + return 0; +} +#endif diff --git a/tilt/SensorBase.h b/tilt/SensorBase.h new file mode 100644 index 0000000..f9f98b8 --- /dev/null +++ b/tilt/SensorBase.h @@ -0,0 +1,97 @@ +/* +* Copyright (C) 2015 Intel Corp +* +* 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_SENSOR_BASE_H +#define ANDROID_SENSOR_BASE_H + +#include <stdint.h> +#include <errno.h> +#include <sys/cdefs.h> +#include <sys/types.h> + +#if defined ANDROID_L +/* #warning "build for Wear" */ +#define LOGV_IF ALOGV_IF +#define LOGE_IF ALOGE_IF +#define LOGI_IF ALOGI_IF +#define LOGI ALOGI +#define LOGE ALOGE +#define LOGV ALOGV +#define LOGW ALOGW +#else +#warning "build for ICS or earlier version" +#endif + +/* Log enablers, each of these independent */ + +/* TODO: clear all logging below on production build, keep it during integration */ +#define PROCESS_VERBOSE (1) /* process log messages */ +#define EXTRA_VERBOSE (1) /* verbose log messages */ +#define SYSFS_VERBOSE (1) /* log sysfs interactions as cat/echo for repro +purpose on a shell */ +#define FUNC_ENTRY (1) /* log entry in all one-time functions */ + +/* Note that enabling this logs may affect performance */ +#define HANDLER_ENTRY (1) /* log entry in all handler functions */ +#define ENG_VERBOSE (1) /* log some a lot more info about the internals */ +#define INPUT_DATA (1) /* log the data input from the events */ +#define HANDLER_DATA (1) /* log the data fetched from the handlers */ + +#define FUNC_LOG \ + LOGV("%s (hardware/intel/sensors/tilt)", __PRETTY_FUNCTION__) +#define VFUNC_LOG \ + LOGV_IF(FUNC_ENTRY, "Entering function '%s' (hardware/intel/sensors/tilt)", __PRETTY_FUNCTION__) +#define VHANDLER_LOG \ + LOGV_IF(HANDLER_ENTRY, "Entering handler '%s' (hardware/intel/sensors/tilt)", __PRETTY_FUNCTION__) +#define CALL_MEMBER_FN(pobject, ptrToMember) ((pobject)->*(ptrToMember)) + +#define MAX_SYSFS_NAME_LEN (100) +#define IIO_BUFFER_LENGTH (480) + + +struct sensors_event_t; + +class SensorBase { +protected: + const char *dev_name; + const char *data_name; + char input_name[PATH_MAX]; + int dev_fd; + int data_fd; + + int openInput(const char* inputName); + static int64_t getTimestamp(); + static int64_t timevalToNano(timeval const& t) { + return t.tv_sec * 1000000000LL + t.tv_usec * 1000; + } + + int open_device(); + int close_device(); + +public: + SensorBase(const char* dev_name, const char* data_name); + virtual ~SensorBase(); + virtual int readEvents(sensors_event_t* data, int count) = 0; + virtual bool hasPendingEvents() const; + virtual int getFd() const; + virtual int setDelay(int32_t handle, int64_t ns); + virtual int enable(int32_t handle, int enabled); +#ifdef HAL_VERSION_GT_1_0 + virtual int batch(int handle, int flags, int64_t period_ns, int64_t timeout); +#endif +}; + +#endif // ANDROID_SENSOR_BASE_H diff --git a/tilt/TiltSensor.cpp b/tilt/TiltSensor.cpp new file mode 100644 index 0000000..d57aa7c --- /dev/null +++ b/tilt/TiltSensor.cpp @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2015 Intel Corp + * + * 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 <fcntl.h> +#include <errno.h> +#include <math.h> +#include <stdlib.h> +#include <poll.h> +#include <unistd.h> +#include <dirent.h> +#include <sys/select.h> +#include <cutils/log.h> +#include <cutils/properties.h> + +#include "TiltSensor.h" + + + +TiltSensor::TiltSensor() + : SensorBase(NULL, "lis3dsh_acc"), + mEnabled(0), + mInputReader(4) +{ + mPendingEvent.version = sizeof(sensors_event_t); + mPendingEvent.sensor = ID_T; + mPendingEvent.type = SENSOR_TYPE_WRIST_TILT; + memset(mPendingEvent.data, 0, sizeof(mPendingEvent.data)); +} + +TiltSensor::~TiltSensor() { + if (mEnabled) { + enable(0, 0); + } +} + +int TiltSensor::setDelay(int32_t /* handle */, int64_t ns) +{ + int fd; + int n, len, ms, ret = 0; + char buf[6]; + char *sysfs_path = (char *)malloc(strlen(INPUT_SYSFS_BASE)+strlen(POLL_PERIOD_MS)+2); + + if(sysfs_path == NULL) + return -ENOMEM; + + ms = ns / 1000000; + + sprintf(sysfs_path, "%s/%s", INPUT_SYSFS_BASE, POLL_PERIOD_MS); + fd = open(sysfs_path, O_RDWR); + if (fd > 0) { + len = 6; + memset(buf, 0, len); + snprintf(buf, len, "%d", ms); + write(fd, buf, sizeof(buf)); + close(fd); + } else { + ret = -EIO; + ALOGE("file open failure\n"); + goto error_free; + } + +error_free: + free(sysfs_path); + return ret; +} +int TiltSensor::enable(int32_t /* handle */, int en) +{ + int ret = 0; + int flags = en ? 1 : 0; + + if (flags != mEnabled) { + int fd; + char buf[2]; + + char *sysfs_path = (char *)malloc(strlen(INPUT_SYSFS_BASE)+strlen(ENABLE_STATE_PROG)+2); + if (sysfs_path == NULL) + return -ENOMEM; + + sprintf(sysfs_path, "%s/%s", INPUT_SYSFS_BASE, ENABLE_STATE_PROG); + fd = open(sysfs_path, O_RDWR); + if (fd > 0) { + buf[1] = 0; + if (flags) + buf[0] = '2'; /* 3: enable SM1 and SM2; 2: enable SM1; 1: enable SM2; 0: disbale */ + else + buf[1] = '0'; + write(fd, buf, sizeof(buf)); + close(fd); + free(sysfs_path); + } else { + free(sysfs_path); + ret = -1; + goto out; + } + + sysfs_path = (char *)malloc(strlen(INPUT_SYSFS_BASE)+strlen(ENABLE_INTERRUPT_OUTPUT)+2); + if (sysfs_path == NULL) + return -ENOMEM; + + sprintf(sysfs_path, "%s/%s", INPUT_SYSFS_BASE, ENABLE_INTERRUPT_OUTPUT); + fd = open(sysfs_path, O_RDWR); + if (fd > 0) { + buf[1] = 0; + if (flags) + buf[0] = '2'; /* 3: enable int1 and int2; 2: enable int1; 1: enable int2; 0: disbale */ + else + buf[1] = '0'; + write(fd, buf, sizeof(buf)); + close(fd); + free(sysfs_path); + } else { + free(sysfs_path); + ret = -1; + goto out; + } + + sysfs_path = (char *)malloc(strlen(INPUT_SYSFS_BASE)+strlen(ENABLE_DEVICE)+2); + if (sysfs_path == NULL) + return -ENOMEM; + + sprintf(sysfs_path, "%s/%s", INPUT_SYSFS_BASE, ENABLE_DEVICE); + fd = open(sysfs_path, O_RDWR); + if(fd > 0) { + buf[1] = 0; + if (flags) + buf[0] = '1'; + else + buf[0] = '0'; + write(fd, buf, sizeof(buf)); + close(fd); + mEnabled = flags; + } else { + ret = -1; + } + free(sysfs_path); + } +out: + return ret; +} + +#ifdef HAL_VERSION_GT_1_0 +int TiltSensor::batch(int /* handle */, int /* flags */, int64_t period_ns, int64_t /* timeout */) +{ + int fd; + int n, len, ms, ret = 0; + char buf[6]; + char *sysfs_path = (char *)malloc(strlen(INPUT_SYSFS_BASE)+strlen(POLL_PERIOD_MS)+2); + + if(sysfs_path == NULL) + return -ENOMEM; + + ms = period_ns / 1000000; + + sprintf(sysfs_path, "%s/%s", INPUT_SYSFS_BASE, POLL_PERIOD_MS); + fd = open(sysfs_path, O_RDWR); + if (fd > 0) { + len = 6; + memset(buf, 0, len); + snprintf(buf, len, "%d", ms); + write(fd, buf, sizeof(buf)); + close(fd); + } else { + ret = -EIO; + ALOGE("file open failure\n"); + goto error_free; + } + +error_free: + free(sysfs_path); + return ret; +} +#endif + +int TiltSensor::readEvents(sensors_event_t* data, int count) +{ + if (count < 1) + return -EINVAL; + + ssize_t n = mInputReader.fill(data_fd); + if (n < 0) + return n; + + int numEventReceived = 0; + input_event const* event; + + while (count && mInputReader.readEvent(&event)) { + int type = event->type; + if (type == EV_ABS) { + mPendingEvent.data[0] = 1.0f; + /*mPendingEvent.data[event->code] = event->value;*/ + } else if (type == EV_SYN) { + mPendingEvent.timestamp = timevalToNano(event->time); + if (mEnabled) { + *data++ = mPendingEvent; + count--; + numEventReceived++; + } + } else { + ALOGE("TiltSensor: unknown event (type=%d, code=%d)", + type, event->code); + } + mInputReader.next(); + } + + return numEventReceived; +} diff --git a/tilt/TiltSensor.h b/tilt/TiltSensor.h new file mode 100644 index 0000000..e5a7058 --- /dev/null +++ b/tilt/TiltSensor.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2015 Intel Corp + * + * 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_TILT_SENSOR_H +#define ANDROID_TILT_SENSOR_H + +#include <stdint.h> +#include <errno.h> +#include <sys/cdefs.h> +#include <sys/types.h> + +#include "sensors.h" +#include "SensorBase.h" +#include "InputEventReader.h" + +#include "clockwork_sensor.h" + + +#define INPUT_SYSFS_BASE "/sys/class/i2c-adapter/i2c-4/4-001e" +#define POLL_PERIOD_MS "poll_period_ms" +#define RANGE "range" +#define ENABLE_DEVICE "enable_device" +#define ENABLE_INTERRUPT_OUTPUT "enable_interrupt_output" +#define ENABLE_STATE_PROG "enable_state_prog" +#ifdef TILT_DEBUG +#define REG_VALUE "reg_value" +#define REG_ADDR "reg_addr" +#endif + + +struct input_event; + +class TiltSensor : public SensorBase { +public: + TiltSensor(); + virtual ~TiltSensor(); + + virtual int readEvents(sensors_event_t* data, int count); + virtual int setDelay(int32_t handle, int64_t ns); + virtual int enable(int32_t handle, int enabled); +#ifdef HAL_VERSION_GT_1_0 + virtual int batch(int handle, int flags, int64_t period_ns, int64_t timeout); +#endif + +private: + int mEnabled; + InputEventCircularReader mInputReader; + sensors_event_t mPendingEvent; +}; +#endif // ANDROID_TILT_SENSOR_H diff --git a/tilt/clockwork_sensor.h b/tilt/clockwork_sensor.h new file mode 100644 index 0000000..150b741 --- /dev/null +++ b/tilt/clockwork_sensor.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 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_CLOCKWORK_SENSOR_INTERFACE_H +#define ANDROID_CLOCKWORK_SENSOR_INTERFACE_H + +#include <hardware/sensors.h> + +__BEGIN_DECLS + +/* + * SENSOR_TYPE_WRIST_TILT + * trigger-mode: special + * wake-up sensor: yes + * + * A sensor of this type triggers an event each time a tilt of the device + * is detected. + * + * Upon detecting a tilt event, a single event is returned containing the + * value of the 3 accelerometer axes when the tilt event was detected. + * + * All values are in SI units (m/s^2) and measure the acceleration of the + * device minus the force of gravity. + * + * x: Acceleration on the x-axis + * y: Acceleration on the y-axis + * z: Acceleration on the z-axis + * + * Note that the readings from the accelerometer include the acceleration + * due to gravity (which is opposite to the direction of the gravity vector). + * + * See "SENSOR_TYPE_ACCELEROMETER" for more detail on returned accelerometer + * data. + * + * setDelay() has no impact on this sensor type + * + * IMPORTANT NOTE: this sensor type is very different from other types + * in that it must work when the screen is off without the need of + * holding a partial wake-lock and MUST allow the SoC to go into suspend. + * When a tilt event is detected, the sensor must awaken the SoC and + * the event be reported. + * + * When the sensor is not activated, it must also be deactivated in the + * hardware: it must not wake up the SoC anymore, even in case of + * a tilt event. + */ +#define SENSOR_TYPE_WRIST_TILT (SENSOR_TYPE_DEVICE_PRIVATE_BASE) +#define SENSOR_STRING_TYPE_WRIST_TILT "com.google.android_wear.wrist.tilt" + +__END_DECLS + +#endif /* ANDROID_CLOCKWORK_SENSOR_INTERFACE_H */ diff --git a/tilt/sensors.cpp b/tilt/sensors.cpp new file mode 100644 index 0000000..2554755 --- /dev/null +++ b/tilt/sensors.cpp @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2015 Intel Corp + * + * 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 <hardware/sensors.h> +#include <fcntl.h> +#include <errno.h> +#include <dirent.h> +#include <math.h> +#include <poll.h> +#include <pthread.h> +#include <stdlib.h> +#include <linux/input.h> +#include <utils/Atomic.h> +#include <utils/Log.h> +#include "sensors.h" +#include "TiltSensor.h" + +#define DELAY_OUT_TIME 0x7FFFFFFF +#define LIGHT_SENSOR_POLLTIME 2000000000 + +#define SENSORS_LIGHT_HANDLE (ID_L) +#define SENSORS_TILT_HANDLE (ID_T) + + +/* The SENSORS Module */ +static struct sensor_t sSensorList[] = { + { "TILT sensor", + "STMicroelectronics", + 1, SENSORS_TILT_HANDLE, + SENSOR_TYPE_WRIST_TILT, 1.0f, 1.0f, 1.0f, 0, 0, 0, + #ifdef ANDROID_L + SENSOR_STRING_TYPE_WRIST_TILT, NULL, 0, SENSOR_FLAG_SPECIAL_REPORTING_MODE | SENSOR_FLAG_WAKE_UP, + #else + NULL, NULL, 0, 0, + #endif + { } }, +}; + +static int open_sensors(const struct hw_module_t* module, const char* id, + struct hw_device_t** device); + + + +static int sensors__get_sensors_list(struct sensors_module_t* module, + struct sensor_t const** list) +{ + *list = sSensorList; + return ARRAY_SIZE(sSensorList); +} + +static struct hw_module_methods_t sensors_module_methods = { + open: open_sensors +}; + +struct sensors_module_t HAL_MODULE_INFO_SYM = { + common: { + tag: HARDWARE_MODULE_TAG, + version_major: 1, + version_minor: 0, + id: SENSORS_HARDWARE_MODULE_ID, + name: "Intel MVN Sensor module", + author: "Intel MVN Company", + methods: &sensors_module_methods, + dso: 0, + reserved: {}, + }, + get_sensors_list: sensors__get_sensors_list, +}; + +struct sensors_poll_context_t { +#ifdef HAL_VERSION_GE_1_0 + struct sensors_poll_device_1 device; /* must be first */ +#else + struct sensors_poll_device_t device; /* must be first */ +#endif + sensors_poll_context_t(); + ~sensors_poll_context_t(); + int activate(int handle, int enabled); + int setDelay(int handle, int64_t ns); +#ifdef HAL_VERSION_GT_1_0 + int batch(int handle, int flags, int64_t period_ns, int64_t timeout); +#endif + int pollEvents(sensors_event_t* data, int count); + bool getInitialized() { return mInitialized; }; + +private: + bool mInitialized; + + enum { + TILT = 0, + numSensorDrivers, /* wake pipe goes here */ + numFds, + }; + + static const size_t wake = numFds - 1; + static const char WAKE_MESSAGE = 'W'; + struct pollfd mPollFds[numFds]; + int mWritePipeFd; + SensorBase* mSensors[numSensorDrivers]; + + int handleToDriver(int handle) const { + switch (handle) { + case ID_T: + return TILT; + } + return -EINVAL; + } +}; + + + +sensors_poll_context_t::sensors_poll_context_t() +{ + FUNC_LOG; + mInitialized = false; + /* Must clean this up early or else the destructor will make a mess */ + memset(mSensors, 0, sizeof(mSensors)); + + mSensors[TILT] = new TiltSensor(); + mPollFds[TILT].fd = mSensors[TILT]->getFd(); + mPollFds[TILT].events = POLLIN; + mPollFds[TILT].revents = 0; + + int wakeFds[2]; + int result = pipe(wakeFds); + ALOGE_IF(result<0, "error creating wake pipe (%s)", strerror(errno)); + fcntl(wakeFds[0], F_SETFL, O_NONBLOCK); + fcntl(wakeFds[1], F_SETFL, O_NONBLOCK); + mWritePipeFd = wakeFds[1]; + + mPollFds[wake].fd = wakeFds[0]; + mPollFds[wake].events = POLLIN; + mPollFds[wake].revents = 0; + mInitialized = true; +} + +sensors_poll_context_t::~sensors_poll_context_t() +{ + FUNC_LOG; + for (int i=0 ; i<numSensorDrivers ; i++) + delete mSensors[i]; + + close(mPollFds[wake].fd); + close(mWritePipeFd); + mInitialized = false; +} + +int sensors_poll_context_t::activate(int handle, int enabled) +{ + FUNC_LOG; + if (!mInitialized) + return -EINVAL; + + int index = handleToDriver(handle); + if (index < 0) + return index; + int err = mSensors[index]->enable(handle, enabled); + if (!err) { + const char wakeMessage(WAKE_MESSAGE); + int result = write(mWritePipeFd, &wakeMessage, 1); + ALOGE_IF(result<0, "error sending wake message (%s)", strerror(errno)); + } + return err; +} + +int sensors_poll_context_t::setDelay(int handle, int64_t ns) +{ + FUNC_LOG; + int index = handleToDriver(handle); + if (index < 0) + return index; + + return mSensors[index]->setDelay(handle, ns); +} + +#ifdef HAL_VERSION_GT_1_0 +int sensors_poll_context_t::batch(int handle, int flags, int64_t period_ns, int64_t timeout) +{ + FUNC_LOG; + int index = handleToDriver(handle); + if (index < 0) + return index; + + return mSensors[index]->batch(handle, flags, period_ns, timeout); +} +#endif + +int sensors_poll_context_t::pollEvents(sensors_event_t* data, int count) +{ + FUNC_LOG; + int nbEvents = 0; + int n = 0; + + do { + for (int i=0 ; count && i<numSensorDrivers; i++) { + SensorBase* const sensor(mSensors[i]); + /* See if we have some pending events from the last poll() */ + if ((mPollFds[i].revents & POLLIN) || (sensor->hasPendingEvents())) { + int nb = sensor->readEvents(data, count); + + /* no more data for this sensor */ + if (nb < count) + mPollFds[i].revents = 0; + + count -= nb; + nbEvents += nb; + data += nb; + } + } + + if (count) { + ALOGV("%s: start poll syscall to kernel", __func__); + n = poll(mPollFds, numFds, nbEvents ? 0 : -1); + if (n < 0) { + ALOGE("poll() failed (%s)", strerror(errno)); + return -errno; + } + if (mPollFds[wake].revents & POLLIN) { + char msg; + int result = read(mPollFds[wake].fd, &msg, 1); + ALOGE_IF(result<0, "error reading from wake pipe (%s)", strerror(errno)); + ALOGE_IF(msg != WAKE_MESSAGE, "unknown message on wake queue (0x%02x)", int(msg)); + mPollFds[wake].revents = 0; + } + } + /* if we have events and space, go read them */ + } while (n && count); + + return nbEvents; +} + +static int poll__close(struct hw_device_t *dev) +{ + FUNC_LOG; + sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev; + if (ctx) + delete ctx; + + return 0; +} + +static int poll__activate(struct sensors_poll_device_t *dev, + int handle, int enabled) +{ + FUNC_LOG; + sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev; + return ctx->activate(handle, enabled); +} + +static int poll__setDelay(struct sensors_poll_device_t *dev, + int handle, int64_t ns) +{ + FUNC_LOG; + sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev; + return ctx->setDelay(handle, ns); +} + +#ifdef HAL_VERSION_GT_1_0 +static int poll__batch(struct sensors_poll_device_1 *dev, + int handle, int flags, int64_t period_ns, int64_t timeout) +{ + FUNC_LOG; + sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev; + return ctx->batch(handle, flags, period_ns, timeout); +} +#endif + +static int poll__poll(struct sensors_poll_device_t *dev, + sensors_event_t* data, int count) +{ + FUNC_LOG; + sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev; + return ctx->pollEvents(data, count); +} + +/* Open a new instance of a sensor device using name */ +static int open_sensors(const struct hw_module_t* module, const char* id, + struct hw_device_t** device) +{ + FUNC_LOG; + int status = -EINVAL; + sensors_poll_context_t *dev = new sensors_poll_context_t(); + + if (!dev->getInitialized()) { + ALOGE("Failed to open the sensors (%s)", id); + return status; + } +#ifdef HAL_VERSION_GE_1_0 + memset(&dev->device, 0, sizeof(sensors_poll_device_1)); +#else + memset(&dev->device, 0, sizeof(sensors_poll_device_t)); +#endif + + dev->device.common.tag = HARDWARE_DEVICE_TAG; +#ifdef ANDROID_L + dev->device.common.version = SENSORS_DEVICE_API_VERSION_1_3; +#endif +#ifdef ANDROID_KK + dev->device.common.version = SENSORS_DEVICE_API_VERSION_1_1; +#endif +#ifdef ANDROID_JBMR2 + dev->device.common.version = SENSORS_DEVICE_API_VERSION_1_0; +#endif +#ifdef ANDROID_JB + dev->device.common.version = 0; +#endif + dev->device.common.module = const_cast<hw_module_t*>(module); + dev->device.common.close = poll__close; + dev->device.activate = poll__activate; + dev->device.setDelay = poll__setDelay; +#ifdef HAL_VERSION_GT_1_0 + dev->device.batch = poll__batch; +#endif + dev->device.poll = poll__poll; + + *device = &dev->device.common; + status = 0; + + return status; +} diff --git a/tilt/sensors.h b/tilt/sensors.h new file mode 100644 index 0000000..869c9a7 --- /dev/null +++ b/tilt/sensors.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2015 Intel Corp + * + * 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_INTELNDG_SENSORS_H +#define ANDROID_INTELNDG_SENSORS_H + +#include <stdint.h> +#include <errno.h> +#include <sys/cdefs.h> +#include <sys/types.h> + +#include <linux/input.h> + +#include <hardware/hardware.h> +#include <hardware/sensors.h> + +__BEGIN_DECLS + +/*****************************************************************************/ + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +#define ID_INTELNDG_BASE (0x1000) +/* light sensor ID */ +#define ID_L (ID_INTELNDG_BASE) +/* tilt sensor ID */ +#define ID_T (ID_L + 1) + +/*****************************************************************************/ + +/* + * The SENSORS Module + */ + +/*****************************************************************************/ +/* the GP2A is a binary proximity sensor that triggers around 5 cm on + * this hardware */ +#define PROXIMITY_THRESHOLD_GP2A 5.0f + +/* input event code for light sensor */ +#define EVENT_TYPE_LIGHT MSC_RAW +/*****************************************************************************/ + + + +__END_DECLS + +#endif /* ANDROID_INTELNDG_SENSORS_H */ |