summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBaixing Tan <baixingx.tan@intel.com>2015-04-20 08:49:23 +0800
committerZhengyin Qian <qianzy@google.com>2015-07-28 12:19:35 -0700
commit1f9b03c781b338aebf792ed68050eed76ee14868 (patch)
tree543266cedb904d6dca6e442f18daf8ad698b02c7
parent91428d81475957f9fb79ecf63a6afd796cb175e7 (diff)
downloadsensors-1f9b03c781b338aebf792ed68050eed76ee14868.tar.gz
Add ambient light sensor HAL
Add ambient light sensor HAL for tsl258x sensor base input subsys. Change-Id: I16999c6d54ddb9889d2769a0a372029f4abe2fd1 Tracked-On: https://jira01.devtools.intel.com/browse/MARVIN-551 Signed-off-by: Baixing Tan <baixingx.tan@intel.com> Reviewed-on: https://android.intel.com:443/356619
-rw-r--r--als/AlsSensor.cpp184
-rw-r--r--als/AlsSensor.h65
-rw-r--r--als/Android.mk78
-rw-r--r--als/InputEventReader.cpp110
-rw-r--r--als/InputEventReader.h50
-rw-r--r--als/SensorBase.cpp153
-rw-r--r--als/SensorBase.h101
-rw-r--r--als/sensors.cpp317
-rw-r--r--als/sensors.h57
9 files changed, 1115 insertions, 0 deletions
diff --git a/als/AlsSensor.cpp b/als/AlsSensor.cpp
new file mode 100644
index 0000000..61afd66
--- /dev/null
+++ b/als/AlsSensor.cpp
@@ -0,0 +1,184 @@
+/*
+* 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 "AlsSensor.h"
+
+#define ALS_DATA_NAME "tsl2584 ambient light sensor"
+#define SYSFS_ENABLE_FILE "/sys/class/i2c-adapter/i2c-6/6-0029/als_enable"
+#define SYSFS_POLL_FILE "/sys/class/i2c-adapter/i2c-6/6-0029/als_delay"
+
+/*****************************************************************************/
+
+#define FIRST_GOOD_EVENT 1
+
+LightSensor::LightSensor()
+ : SensorBase(NULL, ALS_DATA_NAME),
+ mEnabled(0),
+ mEventsSinceEnable(0),
+ mInputReader(4),
+ mHasPendingEvent(false)
+{
+ mPendingEvent.version = sizeof(sensors_event_t);
+ mPendingEvent.sensor = ID_L;
+ mPendingEvent.type = SENSOR_TYPE_LIGHT;
+ memset(mPendingEvent.data, 0, sizeof(mPendingEvent.data));
+}
+
+LightSensor::~LightSensor() {
+ if (mEnabled) {
+ enable(0, 0);
+ }
+}
+
+int LightSensor::setDelay(int32_t /* handle */, int64_t ns)
+{
+ int fd;
+ int len, ms, ret = -1;
+ char buf[6];
+
+ ms = ns / 1000000;
+
+ fd = open(SYSFS_POLL_FILE, O_RDWR);
+ if (fd) {
+ len = 6;
+ memset(buf, 0, len);
+ snprintf(buf, len, "%d", ms);
+ write(fd, buf, sizeof(buf));
+ close(fd);
+ ret = 0;
+ } else
+ ALOGE("file open failure\n");
+
+ return ret;
+}
+int LightSensor::enable(int32_t /* handle */, int en)
+{
+ int flags = en ? 1 : 0;
+
+ mEventsSinceEnable = 0;
+ mPreviousLight = -1;
+ if (flags != mEnabled) {
+ int fd;
+ fd = open(SYSFS_ENABLE_FILE, O_RDWR);
+ if (fd >= 0) {
+ char buf[2];
+ buf[1] = 0;
+ if (flags) {
+ buf[0] = '1';
+ } else {
+ buf[0] = '0';
+ }
+ write(fd, buf, sizeof(buf));
+ close(fd);
+ mEnabled = flags;
+ return 0;
+ }
+ return -1;
+ }
+
+ if (en)
+ mEnabled=1;
+ else
+ mEnabled=0;
+
+ return 0;
+}
+
+#ifdef HAL_VERSION_GT_1_0
+int LightSensor::batch(int /* handle */, int /* flags */, int64_t period_ns, int64_t /* timeout */)
+{
+ int fd;
+ int len, ms, ret = -1;
+ char buf[6];
+
+ ms = period_ns / 1000000;
+
+ fd = open(SYSFS_POLL_FILE, O_RDWR);
+ if (fd) {
+ len = 6;
+ memset(buf, 0, len);
+ snprintf(buf, len, "%d", ms);
+ write(fd, buf, sizeof(buf));
+ close(fd);
+ ret = 0;
+ }
+ else
+ ALOGE("file open failure\n");
+
+ return ret;
+}
+#endif
+
+bool LightSensor::hasPendingEvents() const {
+ return mHasPendingEvent;
+}
+
+int LightSensor::readEvents(sensors_event_t* data, int count)
+{
+ if (count < 1)
+ return -EINVAL;
+
+ if (mHasPendingEvent) {
+ mHasPendingEvent = false;
+ mPendingEvent.timestamp = getTimestamp();
+ *data = mPendingEvent;
+ return mEnabled ? 1 : 0;
+ }
+
+ 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_MSC) {
+ if (event->code == EVENT_TYPE_LIGHT) {
+ mPendingEvent.light = event->value;
+ if (mEventsSinceEnable < FIRST_GOOD_EVENT)
+ mEventsSinceEnable++;
+ }
+ } else if (type == EV_SYN) {
+ mPendingEvent.timestamp = timevalToNano(event->time);
+ if (mEnabled && (mPendingEvent.light != mPreviousLight) &&
+ mEventsSinceEnable >= FIRST_GOOD_EVENT) {
+ *data++ = mPendingEvent;
+ count--;
+ numEventReceived++;
+ mPreviousLight = mPendingEvent.light;
+ }
+ } else {
+ ALOGE("LightSensor: unknown event (type=%d, code=%d)",
+ type, event->code);
+ }
+ mInputReader.next();
+ }
+
+ return numEventReceived;
+}
diff --git a/als/AlsSensor.h b/als/AlsSensor.h
new file mode 100644
index 0000000..a393b0b
--- /dev/null
+++ b/als/AlsSensor.h
@@ -0,0 +1,65 @@
+/*
+* 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_LIGHT_SENSOR_H
+#define ANDROID_LIGHT_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"
+
+/*****************************************************************************/
+/* the GP2A is a binary proximity sensor that triggers around 5 cm on
+ * this hardware */
+#define PROXIMITY_THRESHOLD_GP2A 5.0f
+
+struct input_event;
+
+class LightSensor : public SensorBase {
+ int mEnabled;
+ int mEventsSinceEnable;
+ InputEventCircularReader mInputReader;
+ sensors_event_t mPendingEvent;
+ bool mHasPendingEvent;
+ char input_sysfs_path[PATH_MAX];
+ int input_sysfs_path_len;
+
+ int setInitialState();
+ float mPreviousLight;
+ float indexToValue(size_t index) const;
+
+public:
+ LightSensor();
+ virtual ~LightSensor();
+ virtual int readEvents(sensors_event_t* data, int count);
+ virtual bool hasPendingEvents() 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_LIGHT_SENSOR_H
diff --git a/als/Android.mk b/als/Android.mk
new file mode 100644
index 0000000..f824d5e
--- /dev/null
+++ b/als/Android.mk
@@ -0,0 +1,78 @@
+# 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_als.$(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 \
+ AlsSensor.cpp \
+ SensorBase.cpp
+
+LOCAL_SHARED_LIBRARIES := liblog libutils libdl
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/als/InputEventReader.cpp b/als/InputEventReader.cpp
new file mode 100644
index 0000000..b747b6f
--- /dev/null
+++ b/als/InputEventReader.cpp
@@ -0,0 +1,110 @@
+/*
+* 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)) {
+ 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/als/InputEventReader.h b/als/InputEventReader.h
new file mode 100644
index 0000000..ab09458
--- /dev/null
+++ b/als/InputEventReader.h
@@ -0,0 +1,50 @@
+/*
+* 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/als/SensorBase.cpp b/als/SensorBase.cpp
new file mode 100644
index 0000000..5cdf7cf
--- /dev/null
+++ b/als/SensorBase.cpp
@@ -0,0 +1,153 @@
+/*
+* 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_BOOTTIME, &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 (!strncmp(name, inputName, strlen(inputName))) {
+ 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/als/SensorBase.h b/als/SensorBase.h
new file mode 100644
index 0000000..2eaa872
--- /dev/null
+++ b/als/SensorBase.h
@@ -0,0 +1,101 @@
+/*
+* 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/als)", __PRETTY_FUNCTION__)
+#define VFUNC_LOG \
+ LOGV_IF(FUNC_ENTRY, "Entering function '%s' (hardware/intel/sensors/als)", __PRETTY_FUNCTION__)
+#define VHANDLER_LOG \
+ LOGV_IF(HANDLER_ENTRY, "Entering handler '%s' (hardware/intel/sensors/als)", __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;
+ 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/als/sensors.cpp b/als/sensors.cpp
new file mode 100644
index 0000000..513e5e8
--- /dev/null
+++ b/als/sensors.cpp
@@ -0,0 +1,317 @@
+/*
+ * 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 "AlsSensor.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[] = {
+ { "TSL2584 Ambient light sensor",
+ "ams, ltd.",
+ 1, SENSORS_LIGHT_HANDLE,
+ SENSOR_TYPE_LIGHT, 65535.0f, 1.0f, 0.015f,
+ 0, 0, 0, SENSOR_STRING_TYPE_LIGHT, NULL,
+ 5000000, SENSOR_FLAG_ON_CHANGE_MODE, { } },
+};
+
+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 {
+ light = 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_L:
+ return light;
+ }
+ 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[light] = new LightSensor();
+ mPollFds[light].fd = mSensors[light]->getFd();
+ mPollFds[light].events = POLLIN;
+ mPollFds[light].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]);
+ if ((mPollFds[i].revents & POLLIN) || (sensor->hasPendingEvents())) {
+ int nb;
+ nb = sensor->readEvents(data, count);
+ if (nb < count) {
+ mPollFds[i].revents = 0;
+ }
+ count -= nb;
+ nbEvents += nb;
+ data += nb;
+ }
+ }
+ if (count) {
+ 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;
+ }
+ }
+ } 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_KK
+ dev->device.common.version = SENSORS_DEVICE_API_VERSION_1_1;
+#elif defined(ANDROID_JBMR2)
+ dev->device.common.version = SENSORS_DEVICE_API_VERSION_1_0;
+#else
+ dev->device.common.version = SENSORS_DEVICE_API_VERSION_1_3;
+#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/als/sensors.h b/als/sensors.h
new file mode 100644
index 0000000..2e8685a
--- /dev/null
+++ b/als/sensors.h
@@ -0,0 +1,57 @@
+/*
+ * 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 */