OSDN Git Service

IRDA-2056: Minor rework to the trigger switching code
[android-x86/hardware-intel-libsensors.git] / control.c
index c8377b2..e1a68e6 100644 (file)
--- a/control.c
+++ b/control.c
@@ -29,8 +29,9 @@ static int poll_fd; /* epoll instance covering all enabled sensors */
 static int active_poll_sensors; /* Number of enabled poll-mode sensors */
 
 /* We use pthread condition variables to get worker threads out of sleep */
-static pthread_cond_t  thread_release_cond     [MAX_SENSORS];
-static pthread_mutex_t thread_release_mutex    [MAX_SENSORS];
+static pthread_condattr_t thread_cond_attr     [MAX_SENSORS];
+static pthread_cond_t     thread_release_cond  [MAX_SENSORS];
+static pthread_mutex_t    thread_release_mutex [MAX_SENSORS];
 
 /*
  * We associate tags to each of our poll set entries. These tags have the
@@ -41,10 +42,6 @@ static pthread_mutex_t thread_release_mutex  [MAX_SENSORS];
  *  */
 #define THREAD_REPORT_TAG_BASE 0x00010000
 
-/* When polling try to compensate for the iio overhead in
- * order to try to get a frequency closer to the advertised one
- */
-#define OVERHEAD_THRESHOLD 0.97
 #define ENABLE_BUFFER_RETRIES 10
 #define ENABLE_BUFFER_RETRY_DELAY_MS 10
 
@@ -80,9 +77,10 @@ static int enable_buffer(int dev_num, int enabled)
 }
 
 
-static void setup_trigger (int s, const char* trigger_val)
+static int setup_trigger (int s, const char* trigger_val)
 {
        char sysfs_path[PATH_MAX];
+       int ret = -1, attempts = 5;
 
        sprintf(sysfs_path, TRIGGER_PATH, sensor_info[s].dev_num);
 
@@ -90,9 +88,17 @@ static void setup_trigger (int s, const char* trigger_val)
                ALOGI("Setting S%d (%s) trigger to %s\n", s,
                        sensor_info[s].friendly_name, trigger_val);
 
-       sysfs_write_str(sysfs_path, trigger_val);
+       while (ret == -1 && attempts) {
+               ret = sysfs_write_str(sysfs_path, trigger_val);
+               attempts--;
+       }
 
-       sensor_info[s].selected_trigger = trigger_val;
+       if (ret != -1)
+               sensor_info[s].selected_trigger = trigger_val;
+       else
+               ALOGE("Setting S%d (%s) trigger to %s FAILED.\n", s,
+                       sensor_info[s].friendly_name, trigger_val);
+       return ret;
 }
 
 
@@ -348,14 +354,6 @@ static int get_field_count (int s)
 }
 
 
-static void time_add(struct timespec *out, struct timespec *in, int64_t ns)
-{
-       int64_t target_ts = 1000000000LL * in->tv_sec + in->tv_nsec + ns;
-
-       out->tv_sec = target_ts / 1000000000;
-       out->tv_nsec = target_ts % 1000000000;
-}
-
 
 static void* acquisition_routine (void* param)
 {
@@ -369,27 +367,29 @@ static void* acquisition_routine (void* param)
         */
 
        int s = (int) (size_t) param;
-       int num_fields;
+       int num_fields, sample_size;
        struct sensors_event_t data = {0};
        int c;
        int ret;
-       struct timespec entry_time;
        struct timespec target_time;
-       int64_t period;
-
-       ALOGV("Entering data acquisition thread for sensor %d\n", s);
+       int64_t timestamp, period;
 
        if (s < 0 || s >= sensor_count) {
                ALOGE("Invalid sensor handle!\n");
                return NULL;
        }
 
-       if (!sensor_info[s].sampling_rate) {
-               ALOGE("Zero rate in acquisition routine for sensor %d\n", s);
+       ALOGI("Entering data acquisition thread S%d (%s): rate(%f), ts(%lld)\n", s,
+               sensor_info[s].friendly_name, sensor_info[s].sampling_rate, sensor_info[s].report_ts);
+
+       if (sensor_info[s].sampling_rate <= 0) {
+               ALOGE("Non-positive rate in acquisition routine for sensor %d: %f\n",
+                       s, sensor_info[s].sampling_rate);
                return NULL;
        }
 
        num_fields = get_field_count(s);
+       sample_size = num_fields * sizeof(float);
 
        /*
         * Each condition variable is associated to a mutex that has to be
@@ -399,22 +399,18 @@ static void* acquisition_routine (void* param)
         */
        pthread_mutex_lock(&thread_release_mutex[s]);
 
-       while (1) {
-               /* Pinpoint the moment we start sampling */
-               clock_gettime(CLOCK_REALTIME, &entry_time);
+       /* Pinpoint the moment we start sampling */
+       timestamp = get_timestamp();
 
-               ALOGV("Acquiring sample data for sensor %d through sysfs\n", s);
+       /* Check and honor termination requests */
+       while (sensor_info[s].thread_data_fd[1] != -1) {
 
                /* Read values through sysfs */
                for (c=0; c<num_fields; c++) {
                        data.data[c] = acquire_immediate_value(s, c);
-
                        /* Check and honor termination requests */
                        if (sensor_info[s].thread_data_fd[1] == -1)
                                goto exit;
-
-                       ALOGV("\tfield %d: %f\n", c, data.data[c]);
-
                }
 
                /* If the sample looks good */
@@ -422,18 +418,27 @@ static void* acquisition_routine (void* param)
 
                        /* Pipe it for transmission to poll loop */
                        ret = write(    sensor_info[s].thread_data_fd[1],
-                                       data.data,
-                                       num_fields * sizeof(float));
+                                       data.data, sample_size);
+                       if (ret != sample_size)
+                               ALOGE("S%d acquisition thread: tried to write %d, ret: %d\n",
+                                       s, sample_size, ret);
                }
 
                /* Check and honor termination requests */
                if (sensor_info[s].thread_data_fd[1] == -1)
                        goto exit;
 
+               /* Recalculate period asumming sensor_info[s].sampling_rate
+                * can be changed dynamically during the thread run */
+               if (sensor_info[s].sampling_rate <= 0) {
+                       ALOGE("Non-positive rate in acquisition routine for sensor %d: %f\n",
+                               s, sensor_info[s].sampling_rate);
+                       goto exit;
+               }
 
-               period = (int64_t) (1000000000.0/ sensor_info[s].sampling_rate);
-               period = period * OVERHEAD_THRESHOLD;
-               time_add(&target_time, &entry_time, period);
+               period = (int64_t) (1000000000LL / sensor_info[s].sampling_rate);
+               timestamp += period;
+               set_timestamp(&target_time, timestamp);
 
                /*
                 * Wait until the sampling time elapses, or a rate change is
@@ -442,10 +447,6 @@ static void* acquisition_routine (void* param)
                ret = pthread_cond_timedwait(   &thread_release_cond[s],
                                                &thread_release_mutex[s],
                                                &target_time);
-
-               /* Check and honor termination requests */
-               if (sensor_info[s].thread_data_fd[1] == -1)
-                               goto exit;
        }
 
 exit:
@@ -466,7 +467,9 @@ static void start_acquisition_thread (int s)
        ALOGV("Initializing acquisition context for sensor %d\n", s);
 
        /* Create condition variable and mutex for quick thread release */
-       ret = pthread_cond_init(&thread_release_cond[s], NULL);
+       ret = pthread_condattr_init(&thread_cond_attr[s]);
+       ret = pthread_condattr_setclock(&thread_cond_attr[s], POLLING_CLOCK);
+       ret = pthread_cond_init(&thread_release_cond[s], &thread_cond_attr[s]);
        ret = pthread_mutex_init(&thread_release_mutex[s], NULL);
 
        /* Create a pipe for inter thread communication */
@@ -601,6 +604,10 @@ int sensor_activate(int s, int enabled)
                        free(sensor_info[s].history);
                        sensor_info[s].history = NULL;
                        sensor_info[s].history_size = 0;
+                       if (sensor_info[s].history_sum) {
+                               free(sensor_info[s].history_sum);
+                               sensor_info[s].history_sum = NULL;
+                       }
                }
 
                return 0;
@@ -735,9 +742,16 @@ static void enable_motion_trigger (int dev_num)
        enable_buffer(dev_num, 1);
 }
 
+/* CTS acceptable thresholds:
+ *     EventGapVerification.java: (th <= 1.8)
+ *     FrequencyVerification.java: (0.9)*(expected freq) => (th <= 1.1111)
+ */
+#define THRESHOLD 1.10
 void set_report_ts(int s, int64_t ts)
 {
        int64_t maxTs, period;
+       int catalog_index = sensor_info[s].catalog_index;
+       int is_accel      = (sensor_catalog[catalog_index].type == SENSOR_TYPE_ACCELEROMETER);
 
        /*
        *  A bit of a hack to please a bunch of cts tests. They
@@ -746,10 +760,11 @@ void set_report_ts(int s, int64_t ts)
        *  this may not be the case. Perhaps we'll get rid of this when
        *  we'll be reading the timestamp from the iio channel for all sensors
        */
-       if (sensor_info[s].report_ts &&
-               sensor_info[s].sampling_rate && !sensor_desc[s].flags) {
+       if (sensor_info[s].report_ts && sensor_info[s].sampling_rate &&
+               REPORTING_MODE(sensor_desc[s].flags) == SENSOR_FLAG_CONTINUOUS_MODE)
+       {
                period = (int64_t) (1000000000LL / sensor_info[s].sampling_rate);
-               maxTs = sensor_info[s].report_ts + period;
+               maxTs = sensor_info[s].report_ts + (is_accel ? 1 : THRESHOLD) * period;
                sensor_info[s].report_ts = (ts < maxTs ? ts : maxTs);
        } else {
                sensor_info[s].report_ts = ts;
@@ -765,7 +780,6 @@ static int integrate_device_report(int dev_num)
        unsigned char *target;
        unsigned char *source;
        int size;
-       int64_t ts;
 
        /* There's an incoming report on the specified iio device char dev fd */
 
@@ -779,8 +793,6 @@ static int integrate_device_report(int dev_num)
                return -1;
        }
 
-       ts = get_timestamp();
-
        len = read(device_fd[dev_num], buf, MAX_SENSOR_REPORT_SIZE);
 
        if (len == -1) {
@@ -817,7 +829,7 @@ static int integrate_device_report(int dev_num)
                        ALOGV("Sensor %d report available (%d bytes)\n", s,
                              sr_offset);
 
-                       set_report_ts(s, ts);
+                       set_report_ts(s, get_timestamp());
                        sensor_info[s].report_pending = 1;
                        sensor_info[s].report_initialized = 1;
                }
@@ -907,10 +919,9 @@ static void synthetize_duplicate_samples (void)
                if (!sensor_info[s].enable_count)
                        continue;
 
-               /* If the sensor can generate duplicates, leave it alone */
-               if (!(sensor_info[s].quirks & QUIRK_TERSE_DRIVER) &&
-                       sensor_info[s].selected_trigger !=
-                       sensor_info[s].motion_trigger_name)
+               /* If the sensor is continuously firing, leave it alone */
+               if (sensor_info[s].selected_trigger !=
+                   sensor_info[s].motion_trigger_name)
                        continue;
 
                /* If we haven't seen a sample, there's nothing to duplicate */
@@ -972,17 +983,16 @@ static int get_poll_wait_timeout (void)
        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.
+        * Check if we're dealing with a driver 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].selected_trigger ==
-                     sensor_info[s].motion_trigger_name) &&
-                    sensor_info[s].sampling_rate) {
+                   sensor_info[s].selected_trigger ==
+                   sensor_info[s].motion_trigger_name &&
+                   sensor_info[s].sampling_rate) {
                        period = (int64_t) (1000000000.0 /
                                                sensor_info[s].sampling_rate);
 
@@ -1024,7 +1034,7 @@ return_available_sensor_reports:
        returned_events = 0;
 
        /* Check our sensor collection for available reports */
-       for (s=0; s<sensor_count && returned_events < count; s++)
+       for (s=0; s<sensor_count && returned_events < count; s++) {
                if (sensor_info[s].report_pending) {
                        event_count = 0;
                        /* Lower flag */
@@ -1064,7 +1074,19 @@ return_available_sensor_reports:
                         * value for a 'on change' sensor, silently drop it.
                         */
                }
-
+               while (sensor_info[s].meta_data_pending) {
+                       /* See sensors.h on these */
+                       data[returned_events].version = META_DATA_VERSION;
+                       data[returned_events].sensor = 0;
+                       data[returned_events].type = SENSOR_TYPE_META_DATA;
+                       data[returned_events].reserved0 = 0;
+                       data[returned_events].timestamp = 0;
+                       data[returned_events].meta_data.sensor = s;
+                       data[returned_events].meta_data.what = META_DATA_FLUSH_COMPLETE;
+                       returned_events++;
+                       sensor_info[s].meta_data_pending--;
+               }
+       }
        if (returned_events)
                return returned_events;
 
@@ -1105,6 +1127,25 @@ await_event:
 }
 
 
+static void tentative_switch_trigger (int s)
+{
+       /*
+        * Under certain situations it may be beneficial to use an alternate
+        * trigger:
+        *
+        * - for applications using the accelerometer with high sampling rates,
+        *   prefer the continuous trigger over the any-motion one, to avoid
+        *   jumps related to motion thresholds
+        */
+
+       if (is_fast_accelerometer(s) &&
+               !(sensor_info[s].quirks & QUIRK_TERSE_DRIVER) &&
+                       sensor_info[s].selected_trigger ==
+                               sensor_info[s].motion_trigger_name)
+               setup_trigger(s, sensor_info[s].init_trigger_name);
+}
+
+
 int sensor_set_delay(int s, int64_t ns)
 {
        /* Set the rate at which a specific sensor should report events */
@@ -1130,13 +1171,17 @@ int sensor_set_delay(int s, int64_t ns)
        int n;
        float sr;
 
-       if (!ns) {
-               ALOGE("Rejecting zero delay request on sensor %d\n", s);
+       if (ns <= 0) {
+               ALOGE("Rejecting non-positive delay request on sensor %d, required delay: %lld\n", s, ns);
                return -EINVAL;
        }
 
        new_sampling_rate = 1000000000LL/ns;
 
+       ALOGV("Entering set delay S%d (%s): old rate(%f), new rate(%f)\n",
+               s, sensor_info[s].friendly_name, sensor_info[s].sampling_rate,
+               new_sampling_rate);
+
        /*
         * Artificially limit ourselves to 1 Hz or higher. This is mostly to
         * avoid setting up the stage for divisions by zero.
@@ -1229,13 +1274,11 @@ int sensor_set_delay(int s, int64_t ns)
                }
        }
 
-
        if (max_supported_rate &&
                new_sampling_rate > max_supported_rate) {
                new_sampling_rate = max_supported_rate;
        }
 
-
        /* If the desired rate is already active we're all set */
        if (new_sampling_rate == cur_sampling_rate)
                return 0;
@@ -1247,10 +1290,8 @@ int sensor_set_delay(int s, int64_t ns)
 
        sysfs_write_float(sysfs_path, new_sampling_rate);
 
-       /* Switch back to continuous sampling for accelerometer based games */
-       if (is_fast_accelerometer(s) && sensor_info[s].selected_trigger !=
-                                       sensor_info[s].init_trigger_name)
-               setup_trigger(s, sensor_info[s].init_trigger_name);
+       /* Check if it makes sense to use an alternate trigger */
+       tentative_switch_trigger(s);
 
        if (trig_sensors_per_dev[dev_num])
                enable_buffer(dev_num, 1);
@@ -1258,6 +1299,16 @@ int sensor_set_delay(int s, int64_t ns)
        return 0;
 }
 
+int sensor_flush (int s)
+{
+       /* If one shot or not enabled return -EINVAL */
+       if (sensor_desc[s].flags & SENSOR_FLAG_ONE_SHOT_MODE ||
+               sensor_info[s].enable_count == 0)
+               return -EINVAL;
+
+       sensor_info[s].meta_data_pending++;
+       return 0;
+}
 
 int allocate_control_data (void)
 {