improvement to sensor hal

Change-Id: I72a73535e052b1867c1968a15ae255382e323e27
diff --git a/libsensors/AkmSensor.cpp b/libsensors/AkmSensor.cpp
index 6f30744..ef49c31 100644
--- a/libsensors/AkmSensor.cpp
+++ b/libsensors/AkmSensor.cpp
@@ -32,10 +32,9 @@
 
 AkmSensor::AkmSensor()
 : SensorBase(AKM_DEVICE_NAME, "compass"),
-  mEnabled(0),
-  mInputReader(32),
-  mPendingMask(0),
-  mLastEventIndex(0)
+      mEnabled(0),
+      mPendingMask(0),
+      mInputReader(32)
 {
     memset(mPendingEvents, 0, sizeof(mPendingEvents));
 
@@ -60,7 +59,7 @@
 
     // read the actual value of all sensors if they're enabled already
     struct input_absinfo absinfo;
-    short flags;
+    short flags = 0;
     if (!ioctl(dev_fd, ECS_IOCTL_APP_GET_AFLAG, &flags)) {
         if (flags)  {
             mEnabled |= 1<<Accelerometer;
@@ -124,10 +123,10 @@
     if (uint32_t(what) >= numSensors)
         return -EINVAL;
 
-    int flags = en ? 1 : 0;
+    int newState  = en ? 1 : 0;
     int err = 0;
 
-    if ((uint32_t(flags)<<what) != (mEnabled & (1<<what))) {
+    if ((uint32_t(newState)<<what) != (mEnabled & (1<<what))) {
         int cmd;
         switch (what) {
             case Accelerometer: cmd = ECS_IOCTL_APP_SET_AFLAG;  break;
@@ -135,6 +134,7 @@
             case Orientation:   cmd = ECS_IOCTL_APP_SET_MFLAG;  break;
             case Temperature:   cmd = ECS_IOCTL_APP_SET_TFLAG;  break;
         }
+        short flags = newState;
         err = ioctl(dev_fd, cmd, &flags);
         err = err<0 ? -errno : 0;
         LOGE_IF(err, "ECS_IOCTL_APP_SET_XXX failed (%s)", strerror(-err));
@@ -186,9 +186,11 @@
                     if (mPendingMask & (1<<j)) {
                         mPendingMask &= ~(1<<j);
                         mPendingEvents[j].timestamp = time;
-                        *data++ = mPendingEvents[j];
-                        count--;
-                        numEventReceived++;
+                        if (mEnabled & (1<<j)) {
+                            *data++ = mPendingEvents[j];
+                            count--;
+                            numEventReceived++;
+                        }
                     }
                 }
                 if (!mPendingMask) {
@@ -232,15 +234,15 @@
 
         case EVENT_TYPE_YAW:
             mPendingMask |= 1<<Orientation;
-            mPendingEvents[Orientation].orientation.azimuth = value;
+            mPendingEvents[Orientation].orientation.azimuth = value * CONVERT_O_Y;
             break;
         case EVENT_TYPE_PITCH:
             mPendingMask |= 1<<Orientation;
-            mPendingEvents[Orientation].orientation.pitch = value;
+            mPendingEvents[Orientation].orientation.pitch = value * CONVERT_O_P;
             break;
         case EVENT_TYPE_ROLL:
             mPendingMask |= 1<<Orientation;
-            mPendingEvents[Orientation].orientation.roll = -value;
+            mPendingEvents[Orientation].orientation.roll = value * CONVERT_O_R;
             break;
         case EVENT_TYPE_ORIENT_STATUS:
             mPendingMask |= 1<<Orientation;
diff --git a/libsensors/AkmSensor.h b/libsensors/AkmSensor.h
index b1833c4..adaa854 100644
--- a/libsensors/AkmSensor.h
+++ b/libsensors/AkmSensor.h
@@ -51,10 +51,9 @@
 
 private:
     uint32_t mEnabled;
-    InputEventCircularReader mInputReader;
     uint32_t mPendingMask;
+    InputEventCircularReader mInputReader;
     sensors_event_t mPendingEvents[numSensors];
-    int mLastEventIndex;
 
 };
 
diff --git a/libsensors/InputEventReader.cpp b/libsensors/InputEventReader.cpp
index b69a1ef..1014f29 100644
--- a/libsensors/InputEventReader.cpp
+++ b/libsensors/InputEventReader.cpp
@@ -17,6 +17,7 @@
 #include <stdint.h>
 #include <errno.h>
 #include <unistd.h>
+#include <poll.h>
 
 #include <sys/cdefs.h>
 #include <sys/types.h>
diff --git a/libsensors/LightSensor.cpp b/libsensors/LightSensor.cpp
index 86d1e0b..6d8ba1d 100644
--- a/libsensors/LightSensor.cpp
+++ b/libsensors/LightSensor.cpp
@@ -32,22 +32,19 @@
 
 LightSensor::LightSensor()
     : SensorBase(LS_DEVICE_NAME, "lightsensor-level"),
-      mHasInitialValue(0),
       mEnabled(0),
-      mInputReader(4)
+      mInputReader(4),
+      mHasPendingEvent(false)
 {
     mPendingEvent.version = sizeof(sensors_event_t);
     mPendingEvent.sensor = ID_L;
     mPendingEvent.type = SENSOR_TYPE_LIGHT;
-    mPendingEvent.reserved0 = 0;
-    mPendingEvent.reserved1[0] = 0;
-    mPendingEvent.reserved1[1] = 0;
-    mPendingEvent.reserved1[2] = 0;
-    mPendingEvent.reserved1[3] = 0;
+    memset(mPendingEvent.data, 0, sizeof(mPendingEvent.data));
 
     int flags = 0;
     if (!ioctl(dev_fd, LIGHTSENSOR_IOCTL_GET_ENABLED, &flags)) {
         if (flags) {
+            mEnabled = 1;
             setInitialState();
         }
     }
@@ -60,7 +57,7 @@
     struct input_absinfo absinfo;
     if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_LIGHT), &absinfo)) {
         mPendingEvent.light = indexToValue(absinfo.value);
-        mHasInitialValue = 1;
+        mHasPendingEvent = true;
     }
     return 0;
 }
@@ -82,23 +79,23 @@
     return err;
 }
 
+bool LightSensor::hasPendingEvents() const {
+    return mHasPendingEvent;
+}
+
 int LightSensor::readEvents(sensors_event_t* data, int count)
 {
     if (count < 1)
         return -EINVAL;
 
-    if (mHasInitialValue) {
-        struct timespec t;
-        t.tv_sec = t.tv_nsec = 0;
-        clock_gettime(CLOCK_MONOTONIC, &t);
-        mHasInitialValue = 0;
-        mPendingEvent.timestamp = int64_t(t.tv_sec)*1000000000LL + t.tv_nsec;
+    if (mHasPendingEvent) {
+        mHasPendingEvent = false;
+        mPendingEvent.timestamp = getTimestamp();
         *data = mPendingEvent;
-        return 1;
+        return mEnabled ? 1 : 0;
     }
 
     ssize_t n = mInputReader.fill(data_fd);
-
     if (n < 0)
         return n;
 
@@ -116,9 +113,11 @@
             }
         } else if (type == EV_SYN) {
             mPendingEvent.timestamp = timevalToNano(event->time);
-            *data++ = mPendingEvent;
-            count--;
-            numEventReceived++;
+            if (mEnabled) {
+                *data++ = mPendingEvent;
+                count--;
+                numEventReceived++;
+            }
         }
         mInputReader.next();
     }
diff --git a/libsensors/LightSensor.h b/libsensors/LightSensor.h
index 16e7f30..b417853 100644
--- a/libsensors/LightSensor.h
+++ b/libsensors/LightSensor.h
@@ -31,20 +31,21 @@
 struct input_event;
 
 class LightSensor : public SensorBase {
-    int mHasInitialValue;
     int mEnabled;
     InputEventCircularReader mInputReader;
     sensors_event_t mPendingEvent;
+    bool mHasPendingEvent;
 
-    int setInitialState();
     float indexToValue(size_t index) const;
+    int setInitialState();
 
 public:
-    LightSensor();
-    ~LightSensor();
+            LightSensor();
+    virtual ~LightSensor();
+    virtual int readEvents(sensors_event_t* data, int count);
+    virtual bool hasPendingEvents() const;
 
     int enable(int enabled);
-    int readEvents(sensors_event_t* data, int count);
 };
 
 /*****************************************************************************/
diff --git a/libsensors/ProximitySensor.cpp b/libsensors/ProximitySensor.cpp
index 89a6de4..2499915 100644
--- a/libsensors/ProximitySensor.cpp
+++ b/libsensors/ProximitySensor.cpp
@@ -32,21 +32,18 @@
 
 ProximitySensor::ProximitySensor()
     : SensorBase(CM_DEVICE_NAME, "proximity"),
-      mHasInitialValue(0),
       mEnabled(0),
-      mInputReader(4)
+      mInputReader(4),
+      mHasPendingEvent(false)
 {
     mPendingEvent.version = sizeof(sensors_event_t);
     mPendingEvent.sensor = ID_P;
     mPendingEvent.type = SENSOR_TYPE_PROXIMITY;
-    mPendingEvent.reserved0 = 0;
-    mPendingEvent.reserved1[0] = 0;
-    mPendingEvent.reserved1[1] = 0;
-    mPendingEvent.reserved1[2] = 0;
-    mPendingEvent.reserved1[3] = 0;
+    memset(mPendingEvent.data, 0, sizeof(mPendingEvent.data));
 
     int flags = 0;
     if (!ioctl(dev_fd, CAPELLA_CM3602_IOCTL_GET_ENABLED, &flags)) {
+        mEnabled = 1;
         if (flags) {
             setInitialState();
         }
@@ -59,21 +56,23 @@
 int ProximitySensor::setInitialState() {
     struct input_absinfo absinfo;
     if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_PROXIMITY), &absinfo)) {
+        // make sure to report an event immediately
+        mHasPendingEvent = true;
         mPendingEvent.distance = indexToValue(absinfo.value);
-        mHasInitialValue = 1;
     }
     return 0;
 }
 
 int ProximitySensor::enable(int en) {
-    int flags = en ? 1 : 0;
+    int newState = en ? 1 : 0;
     int err = 0;
-    if (flags != mEnabled) {
+    if (newState != mEnabled) {
+        int flags = newState;
         err = ioctl(dev_fd, CAPELLA_CM3602_IOCTL_ENABLE, &flags);
         err = err<0 ? -errno : 0;
         LOGE_IF(err, "CAPELLA_CM3602_IOCTL_ENABLE failed (%s)", strerror(-err));
         if (!err) {
-            mEnabled = en ? 1 : 0;
+            mEnabled = newState;
             if (en) {
                 setInitialState();
             }
@@ -82,19 +81,20 @@
     return err;
 }
 
+bool ProximitySensor::hasPendingEvents() const {
+    return mHasPendingEvent;
+}
+
 int ProximitySensor::readEvents(sensors_event_t* data, int count)
 {
     if (count < 1)
         return -EINVAL;
 
-    if (mHasInitialValue) {
-        struct timespec t;
-        t.tv_sec = t.tv_nsec = 0;
-        clock_gettime(CLOCK_MONOTONIC, &t);
-        mHasInitialValue = 0;
-        mPendingEvent.timestamp = int64_t(t.tv_sec)*1000000000LL + t.tv_nsec;
+    if (mHasPendingEvent) {
+        mHasPendingEvent = false;
+        mPendingEvent.timestamp = getTimestamp();
         *data = mPendingEvent;
-        return 1;
+        return mEnabled ? 1 : 0;
     }
 
     ssize_t n = mInputReader.fill(data_fd);
@@ -112,9 +112,11 @@
             }
         } else if (type == EV_SYN) {
             mPendingEvent.timestamp = timevalToNano(event->time);
-            *data++ = mPendingEvent;
-            count--;
-            numEventReceived++;
+            if (mEnabled) {
+                *data++ = mPendingEvent;
+                count--;
+                numEventReceived++;
+            }
         }
         mInputReader.next();
     }
diff --git a/libsensors/ProximitySensor.h b/libsensors/ProximitySensor.h
index 5dcabf5..d9d74a9 100644
--- a/libsensors/ProximitySensor.h
+++ b/libsensors/ProximitySensor.h
@@ -31,20 +31,21 @@
 struct input_event;
 
 class ProximitySensor : public SensorBase {
-    int mHasInitialValue;
     int mEnabled;
     InputEventCircularReader mInputReader;
     sensors_event_t mPendingEvent;
+    bool mHasPendingEvent;
 
     int setInitialState();
     float indexToValue(size_t index) const;
 
 public:
-    ProximitySensor();
-    ~ProximitySensor();
+            ProximitySensor();
+    virtual ~ProximitySensor();
+    virtual int readEvents(sensors_event_t* data, int count);
+    virtual bool hasPendingEvents() const;
 
     int enable(int enabled);
-    int readEvents(sensors_event_t* data, int count);
 };
 
 /*****************************************************************************/
diff --git a/libsensors/SensorBase.cpp b/libsensors/SensorBase.cpp
index 8df1f8c..55dae06 100644
--- a/libsensors/SensorBase.cpp
+++ b/libsensors/SensorBase.cpp
@@ -38,8 +38,10 @@
 {
     data_fd = openInput(data_name);
 
-    dev_fd = open(dev_name, O_RDONLY);
-    LOGE_IF(dev_fd<0, "Couldn't open %s (%s)", dev_name, strerror(errno));
+    if (dev_name) {
+        dev_fd = open(dev_name, O_RDONLY);
+        LOGE_IF(dev_fd<0, "Couldn't open %s (%s)", dev_name, strerror(errno));
+    }
 }
 
 SensorBase::~SensorBase() {
@@ -60,6 +62,17 @@
     return 0;
 }
 
+bool SensorBase::hasPendingEvents() const {
+    return false;
+}
+
+int64_t SensorBase::getTimestamp() {
+    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) {
     int fd = -1;
     const char *dirname = "/dev/input";
diff --git a/libsensors/SensorBase.h b/libsensors/SensorBase.h
index 9bdb522..c0c4d15 100644
--- a/libsensors/SensorBase.h
+++ b/libsensors/SensorBase.h
@@ -25,6 +25,8 @@
 
 /*****************************************************************************/
 
+struct sensors_event_t;
+
 class SensorBase {
 protected:
     const char* dev_name;
@@ -33,20 +35,24 @@
     int         data_fd;
 
     static 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;
     }
 
-    ~SensorBase();
-
 public:
-    SensorBase(
-            const char* dev_name,
-            const char* data_name);
+            SensorBase(
+                    const char* dev_name,
+                    const char* data_name);
 
-    int getFd() const;
-    int setDelay(int64_t ns);
+    virtual ~SensorBase();
+
+    virtual int readEvents(sensors_event_t* data, int count) = 0;
+    virtual bool hasPendingEvents() const;
+    virtual int getFd() const;
+    virtual int setDelay(int64_t ns);
 };
 
 /*****************************************************************************/
diff --git a/libsensors/nusensors.cpp b/libsensors/nusensors.cpp
index 0dc1d83..f94ad85 100644
--- a/libsensors/nusensors.cpp
+++ b/libsensors/nusensors.cpp
@@ -22,7 +22,6 @@
 
 #include <poll.h>
 #include <pthread.h>
-#include <sys/select.h>
 
 #include <linux/input.h>
 
@@ -46,88 +45,116 @@
     int pollEvents(sensors_event_t* data, int count);
 
 private:
-    struct pollfd mPollFds[3];
-    LightSensor mLightSensor;
-    ProximitySensor mProximitySensor;
-    AkmSensor mAkmSensor;
+    enum {
+        light           = 0,
+        proximity       = 1,
+        akm             = 2,
+        numSensorDrivers,
+        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_A:
+            case ID_M:
+            case ID_O:
+            case ID_T:
+                return akm;
+            case ID_P:
+                return proximity;
+            case ID_L:
+                return light;
+        }
+        return -EINVAL;
+    }
 };
 
 /*****************************************************************************/
 
 sensors_poll_context_t::sensors_poll_context_t()
 {
-    mPollFds[0].fd = mLightSensor.getFd();
-    mPollFds[0].events = POLLIN;
-    mPollFds[0].revents = 0;
+    mSensors[light] = new LightSensor();
+    mPollFds[light].fd = mSensors[light]->getFd();
+    mPollFds[light].events = POLLIN;
+    mPollFds[light].revents = 0;
 
-    mPollFds[1].fd = mProximitySensor.getFd();
-    mPollFds[1].events = POLLIN;
-    mPollFds[1].revents = 0;
+    mSensors[proximity] = new ProximitySensor();
+    mPollFds[proximity].fd = mSensors[proximity]->getFd();
+    mPollFds[proximity].events = POLLIN;
+    mPollFds[proximity].revents = 0;
 
-    mPollFds[2].fd = mAkmSensor.getFd();
-    mPollFds[2].events = POLLIN;
-    mPollFds[2].revents = 0;
+    mSensors[akm] = new AkmSensor();
+    mPollFds[akm].fd = mSensors[akm]->getFd();
+    mPollFds[akm].events = POLLIN;
+    mPollFds[akm].revents = 0;
+
+    int wakeFds[2];
+    int result = pipe(wakeFds);
+    LOGE_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;
 }
 
 sensors_poll_context_t::~sensors_poll_context_t() {
+    for (int i=0 ; i<numSensorDrivers ; i++) {
+        delete mSensors[i];
+    }
+    close(mPollFds[wake].fd);
+    close(mWritePipeFd);
 }
 
 int sensors_poll_context_t::activate(int handle, int enabled) {
     int err = -EINVAL;
-    int idx = -1;
     switch (handle) {
         case ID_A:
-            err = mAkmSensor.enable(AkmSensor::Accelerometer, enabled);
-            idx = 2;
+            err = static_cast<AkmSensor*>(
+                    mSensors[akm])->enable(AkmSensor::Accelerometer, enabled);
             break;
         case ID_M:
-            err = mAkmSensor.enable(AkmSensor::MagneticField, enabled);
-            idx = 2;
+            err = static_cast<AkmSensor*>(
+                    mSensors[akm])->enable(AkmSensor::MagneticField, enabled);
             break;
         case ID_O:
-            err = mAkmSensor.enable(AkmSensor::Orientation, enabled);
-            idx = 2;
+            err = static_cast<AkmSensor*>(
+                    mSensors[akm])->enable(AkmSensor::Orientation, enabled);
             break;
         case ID_T:
-            err = mAkmSensor.enable(AkmSensor::Temperature, enabled);
-            idx = 2;
+            err = static_cast<AkmSensor*>(
+                    mSensors[akm])->enable(AkmSensor::Temperature, enabled);
             break;
         case ID_P:
-            err = mProximitySensor.enable(enabled);
-            idx = 1;
+            err = static_cast<ProximitySensor*>(
+                    mSensors[proximity])->enable(enabled);
             break;
         case ID_L:
-            err = mLightSensor.enable(enabled);
-            idx = 0;
+            err = static_cast<LightSensor*>(
+                    mSensors[light])->enable(enabled);
             break;
     }
-
-    if (!err && enabled && idx>=0) {
-        // pretend there is an event, so we return "something" asap.
-        mPollFds[idx].revents = POLLIN;
+    if (enabled && !err) {
+        const char wakeMessage(WAKE_MESSAGE);
+        int result = write(mWritePipeFd, &wakeMessage, 1);
+        LOGE_IF(result<0, "error sending wake message (%s)", strerror(errno));
     }
-
     return err;
 }
 
 int sensors_poll_context_t::setDelay(int handle, int64_t ns) {
-    switch (handle) {
-        case ID_A:
-        case ID_M:
-        case ID_O:
-        case ID_T:
-            mAkmSensor.setDelay(ns);
-            break;
-        case ID_P:
-            mProximitySensor.setDelay(ns);
-            break;
-        case ID_L:
-            mLightSensor.setDelay(ns);
-            break;
-        default:
-            return -EINVAL;
-    }
-    return 0;
+
+    int index = handleToDriver(handle);
+    if (index < 0) return index;
+    return mSensors[index]->setDelay(ns);
 }
 
 int sensors_poll_context_t::pollEvents(sensors_event_t* data, int count)
@@ -137,17 +164,10 @@
 
     do {
         // see if we have some leftover from the last poll()
-        for (int i=0 ; count && i<3 ; i++) {
-            if (mPollFds[i].revents & POLLIN) {
-                int nb = 0;
-                if (i == 0) {
-                    nb = mLightSensor.readEvents(data, count);
-                } else if (i == 1) {
-                    nb = mProximitySensor.readEvents(data, count);
-                } else if (i == 2) {
-                    nb = mAkmSensor.readEvents(data, count);
-                }
-
+        for (int i=0 ; count && i<numSensorDrivers ; i++) {
+            SensorBase* const sensor(mSensors[i]);
+            if ((mPollFds[i].revents & POLLIN) || (sensor->hasPendingEvents())) {
+                int nb = sensor->readEvents(data, count);
                 if (nb < count) {
                     // no more data for this sensor
                     mPollFds[i].revents = 0;
@@ -160,13 +180,20 @@
 
         if (count) {
             // we still have some room, so try to see if we can get
-            // some events immediately or just wait we we don't have
+            // some events immediately or just wait if we don't have
             // anything to return
-            n = poll(mPollFds, 3, nbEvents ? 0 : -1);
+            n = poll(mPollFds, numFds, nbEvents ? 0 : -1);
             if (n<0) {
                 LOGE("poll() failed (%s)", strerror(errno));
                 return -errno;
             }
+            if (mPollFds[wake].revents & POLLIN) {
+                char msg;
+                int result = read(mPollFds[wake].fd, &msg, 1);
+                LOGE_IF(result<0, "error reading from wake pipe (%s)", strerror(errno));
+                LOGE_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);
diff --git a/libsensors/nusensors.h b/libsensors/nusensors.h
index 1023cf1..60e819a 100644
--- a/libsensors/nusensors.h
+++ b/libsensors/nusensors.h
@@ -60,9 +60,6 @@
 #define CM_DEVICE_NAME      "/dev/cm3602"
 #define LS_DEVICE_NAME      "/dev/lightsensor"
 
-
-// sensor IDs must be a power of two and
-// must match values in SensorManager.java
 #define EVENT_TYPE_ACCEL_X          ABS_X
 #define EVENT_TYPE_ACCEL_Y          ABS_Z
 #define EVENT_TYPE_ACCEL_Z          ABS_Y
@@ -98,6 +95,11 @@
 #define CONVERT_M_Y                 (-CONVERT_M)
 #define CONVERT_M_Z                 (CONVERT_M)
 
+#define CONVERT_O                   (1.0f)
+#define CONVERT_O_Y                 (CONVERT_M)
+#define CONVERT_O_P                 (CONVERT_M)
+#define CONVERT_O_R                 (-CONVERT_M)
+
 #define SENSOR_STATE_MASK           (0x7FFF)
 
 /*****************************************************************************/