OSDN Git Service

GMIN-675: Add the ability to repeatedly send samples to Android
authorPatrick Porlan <patrick.porlan@intel.com>
Fri, 1 Aug 2014 16:01:46 +0000 (18:01 +0200)
committerAdriana Reus <adriana.reus@intel.com>
Mon, 4 Aug 2014 15:39:31 +0000 (18:39 +0300)
This allows supporting sensors that are defined as continuously
firing by Android with underlying iio drivers that don't generate
events unless something has changed.

This will allow using Srinivas's latest gyro driver properly, as
well as fix issues with the XPS 12 sensors.

Issue: GMIN-675

Change-Id: I8c69b538646b915d3185ecef2d31939a2eb6aef4
Signed-off-by: Patrick Porlan <patrick.porlan@intel.com>
common.h
control.c
description.c
description.h

index 470fef9..4778e4f 100644 (file)
--- a/common.h
+++ b/common.h
@@ -139,8 +139,12 @@ struct sensor_info_t
         */
        int64_t report_ts;
 
+       /* Buffer containing the last generated sensor report for this sensor */
        unsigned char report_buffer[MAX_SENSOR_REPORT_SIZE];
 
+       /* Whether or not the above buffer contains data from a device report */
+       int report_initialized;
+
        struct sample_ops_t ops;
 
        int calibrated;
index 149e761..e7eaf83 100644 (file)
--- a/control.c
+++ b/control.c
@@ -397,7 +397,7 @@ static void* acquisition_routine (void* param)
                        goto exit;
 
 
-               period = 1000000000LL / sensor_info[s].sampling_rate;
+               period = (int64_t) (1000000000.0/ sensor_info[s].sampling_rate);
 
                time_add(&target_time, &entry_time, period);
 
@@ -610,6 +610,7 @@ static int integrate_device_report(int dev_num)
        int len;
        int s,c;
        unsigned char buf[MAX_SENSOR_REPORT_SIZE] = { 0 };
+       unsigned char previous_report[MAX_SENSOR_REPORT_SIZE];
        int sr_offset;
        unsigned char *target;
        unsigned char *source;
@@ -640,6 +641,8 @@ static int integrate_device_report(int dev_num)
 
        ALOGV("Read %d bytes from iio device %d\n", len, dev_num);
 
+       /* Map device report to sensor reports */
+
        for (s=0; s<MAX_SENSORS; s++)
                if (sensor_info[s].dev_num == dev_num &&
                    sensor_info[s].enable_count) {
@@ -666,6 +669,7 @@ static int integrate_device_report(int dev_num)
 
                        sensor_info[s].report_ts = ts;
                        sensor_info[s].report_pending = 1;
+                       sensor_info[s].report_initialized = 1;
                }
 
        return 0;
@@ -729,6 +733,57 @@ static int propagate_sensor_report(int s, struct sensors_event_t  *data)
 }
 
 
+static void synthetize_duplicate_samples (void)
+{
+       /*
+        * Some sensor types (ex: gyroscope) are defined as continuously firing
+        * by Android, despite the fact that we can be dealing with iio drivers
+        * that only report events for new samples. For these we generate
+        * reports periodically, duplicating the last data we got from the
+        * driver. This is not necessary for polling sensors.
+        */
+
+       int s;
+       int64_t current_ts;
+       int64_t target_ts;
+       int64_t period;
+
+       for (s=0; s<sensor_count; s++) {
+
+               /* Ignore disabled sensors */
+               if (!sensor_info[s].enable_count)
+                       continue;
+
+               /* If the sensor can generate duplicates, leave it alone */
+               if (!(sensor_info[s].quirks &  QUIRK_TERSE_DRIVER))
+                       continue;
+
+               /* If we haven't seen a sample, there's nothing to duplicate */
+               if (!sensor_info[s].report_initialized)
+                       continue;
+
+               /* If a sample was recently buffered, leave it alone too */
+               if (sensor_info[s].report_pending)
+                       continue;
+
+               /* We also need a valid sampling rate to be configured */
+               if (!sensor_info[s].sampling_rate)
+                       continue;
+
+               period = (int64_t) (1000000000.0/ sensor_info[s].sampling_rate);
+
+               current_ts = get_timestamp();
+               target_ts = sensor_info[s].report_ts + period;
+
+               if (target_ts <= current_ts) {
+                       /* Mark the sensor for event generation */
+                       sensor_info[s].report_ts = current_ts;
+                       sensor_info[s].report_pending = 1;
+               }
+       }
+}
+
+
 static void integrate_thread_report (uint32_t tag)
 {
        int s = tag - THREAD_REPORT_TAG_BASE;
@@ -748,6 +803,50 @@ static void integrate_thread_report (uint32_t tag)
 }
 
 
+static int get_poll_wait_timeout (void)
+{
+       /*
+        * Compute an appropriate timeout value, in ms, for the epoll_wait
+        * call that's going to await for iio device reports and incoming
+        * reports from our sensor sysfs data reader threads.
+        */
+
+       int s;
+       int64_t target_ts = INT64_MAX;
+       int64_t ms_to_wait;
+       int64_t period;
+
+       /*
+        * Check if have have to deal with "terse" drivers that only send events
+        * when there is motion, despite the fact that the associated Android
+        * sensor type is continuous rather than on-change. In that case we have
+        * to duplicate events. Check deadline for the nearest upcoming event.
+        */
+       for (s=0; s<sensor_count; s++)
+               if (sensor_info[s].enable_count &&
+                   (sensor_info[s].quirks & QUIRK_TERSE_DRIVER) &&
+                   sensor_info[s].sampling_rate) {
+                       period = (int64_t) (1000000000.0 /
+                                               sensor_info[s].sampling_rate);
+
+                       if (sensor_info[s].report_ts + period < target_ts)
+                               target_ts = sensor_info[s].report_ts + period;
+               }
+
+       /* If we don't have such a driver to deal with */
+       if (target_ts == INT64_MAX)
+               return -1; /* Infinite wait */
+
+       ms_to_wait = (target_ts - get_timestamp()) / 1000000;
+
+       /* If the target timestamp is already behind us, don't wait */
+       if (ms_to_wait < 1)
+               return 0;
+
+       return ms_to_wait;
+}
+
+
 int sensor_poll(struct sensors_event_t* data, int count)
 {
        int s;
@@ -810,13 +909,16 @@ await_event:
 
        ALOGV("Awaiting sensor data\n");
 
-       nfds = epoll_wait(poll_fd, ev, MAX_DEVICES, -1);
+       nfds = epoll_wait(poll_fd, ev, MAX_DEVICES, get_poll_wait_timeout());
 
        if (nfds == -1) {
-               ALOGI("epoll_wait returned -1 (%s)\n", strerror(errno));
+               ALOGE("epoll_wait returned -1 (%s)\n", strerror(errno));
                goto await_event;
        }
 
+       /* Synthetize duplicate samples if needed */
+       synthetize_duplicate_samples();
+
        ALOGV("%d fds signalled\n", nfds);
 
        /* For each of the signalled sources */
index b03c911..486ac31 100644 (file)
  * ro.iio.anglvel.transform = ISH
  * ro.iio.anglvel.quirks = init-rate
  *
+ * The "terse" quirk indicates that the underlying driver only sends events
+ * when the sensor reports a change. The HAL then periodically generates
+ * duplicate events so the sensor behaves as a continously firing one.
+ *
  * This one is used specifically to pass a calibration scale to ALS drivers:
  *
  * ro.iio.illuminance.name = CPLM3218x Ambient Light Sensor
@@ -214,6 +218,10 @@ uint32_t sensor_get_quirks (int s)
                if (strstr(quirks_buf, "init-rate"))
                        sensor_info[s].quirks |= QUIRKS_INITIAL_RATE;
 
+               if (strstr(quirks_buf, "terse"))
+                       sensor_info[s].quirks |= QUIRK_TERSE_DRIVER;
+               ;
+
                sensor_info[s].quirks |= QUIRKS_ALREADY_DECODED;
        }
 
index c1dfbc8..8856a74 100644 (file)
@@ -9,6 +9,7 @@
 
 #define QUIRKS_ALREADY_DECODED 0x1  /* Sensor quirks have been read */
 #define QUIRKS_INITIAL_RATE    0x2  /* Force initial sensor sampling rate */
+#define QUIRK_TERSE_DRIVER     0x8  /* Force duplicate events generation */
 
 char*  sensor_get_name         (int handle);
 char*  sensor_get_vendor       (int handle);