OSDN Git Service

GMIN-3044: Fix a few edge cases in filtering code
[android-x86/hardware-intel-libsensors.git] / control.c
index 029c876..3a827ae 100644 (file)
--- a/control.c
+++ b/control.c
@@ -15,6 +15,7 @@
 #include "utils.h"
 #include "transform.h"
 #include "calibration.h"
+#include "description.h"
 
 /* Currently active sensors count, per device */
 static int poll_sensors_per_dev[MAX_DEVICES];  /* poll-mode sensors */
@@ -334,11 +335,9 @@ static void* acquisition_routine (void* param)
         */
 
        int s = (int) param;
-       int report_fd;
        int num_fields;
        struct sensors_event_t data = {0};
        int c;
-       int sampling_rate;
        int ret;
        struct timespec entry_time;
        struct timespec target_time;
@@ -398,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);
 
@@ -489,13 +488,10 @@ static void stop_acquisition_thread (int s)
 int sensor_activate(int s, int enabled)
 {
        char device_name[PATH_MAX];
-       char trigger_name[MAX_NAME_SIZE + 16];
-       int c;
        struct epoll_event ev = {0};
        int dev_fd;
        int ret;
        int dev_num = sensor_info[s].dev_num;
-       int i = sensor_info[s].catalog_index;
        int is_poll_sensor = !sensor_info[s].num_channels;
 
        /* If we want to activate gyro calibrated and gyro uncalibrated is activated
@@ -532,11 +528,9 @@ int sensor_activate(int s, int enabled)
 
                /* If there's at least one sensor enabled on this iio device */
                if (trig_sensors_per_dev[dev_num]) {
-                       sprintf(trigger_name, "%s-dev%d",
-                                       sensor_info[s].internal_name, dev_num);
 
                        /* Start sampling */
-                       setup_trigger(dev_num, trigger_name);
+                       setup_trigger(dev_num, sensor_info[s].trigger_name);
                        enable_buffer(dev_num, 1);
                }
        }
@@ -564,6 +558,13 @@ int sensor_activate(int s, int enabled)
                                close(dev_fd);
                                device_fd[dev_num] = -1;
                        }
+
+               /* If we recorded a trail of samples for filtering, delete it */
+               if (sensor_info[s].history) {
+                       free(sensor_info[s].history);
+                       sensor_info[s].history = NULL;
+                       sensor_info[s].history_size = 0;
+               }
                return 0;
        }
 
@@ -620,7 +621,7 @@ static int integrate_device_report(int dev_num)
        unsigned char *target;
        unsigned char *source;
        int size;
-       int ts;
+       int64_t ts;
 
        /* There's an incoming report on the specified iio device char dev fd */
 
@@ -646,6 +647,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) {
@@ -672,6 +675,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;
@@ -735,6 +739,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;
@@ -754,13 +809,61 @@ 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 very close or already behind us, wait
+        * nonetheless for a millisecond in order to a) avoid busy loops, and
+        * b) give a chance for the driver to report data before we repeat the
+        * last received sample.
+        */
+       if (ms_to_wait <= 0)
+               return 1;
+
+       return ms_to_wait;
+}
+
+
 int sensor_poll(struct sensors_event_t* data, int count)
 {
        int s;
        int i;
        int nfds;
        struct epoll_event ev[MAX_DEVICES];
-       int64_t target_ts;
        int returned_events;
        int event_count;
 
@@ -817,13 +920,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 */
@@ -996,7 +1102,6 @@ int sensor_set_delay(int s, int64_t ns)
 int allocate_control_data (void)
 {
        int i;
-       struct epoll_event ev = {0};
 
        for (i=0; i<MAX_DEVICES; i++)
                device_fd[i] = -1;