/*
- * Copyright (C) 2014 Intel Corporation.
+ * Copyright (C) 2014-2015 Intel Corporation.
*/
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <sys/epoll.h>
+#include <sys/ioctl.h>
#include <sys/socket.h>
#include <utils/Log.h>
#include <hardware/sensors.h>
+#include <linux/ioctl.h>
#include "control.h"
#include "enumeration.h"
#include "utils.h"
#include "calibration.h"
#include "description.h"
#include "filtering.h"
-
+#include <linux/iio/events.h>
/* Currently active sensors count, per device */
-static int poll_sensors_per_dev[MAX_DEVICES]; /* poll-mode sensors */
-static int trig_sensors_per_dev[MAX_DEVICES]; /* trigger, event based */
+static int poll_sensors_per_dev[MAX_DEVICES]; /* poll-mode sensors */
+static int trig_sensors_per_dev[MAX_DEVICES]; /* trigger, event based */
static int device_fd[MAX_DEVICES]; /* fd on the /dev/iio:deviceX file */
+static int events_fd[MAX_DEVICES]; /* fd on the /sys/bus/iio/devices/iio:deviceX/events/<event_name> file */
static int has_iio_ts[MAX_DEVICES]; /* ts channel available on this iio dev */
static int expected_dev_report_size[MAX_DEVICES]; /* expected iio scan len */
static int poll_fd; /* epoll instance covering all enabled sensors */
-static int active_poll_sensors; /* Number of enabled poll-mode sensors */
+static int active_poll_sensors; /* Number of enabled poll-mode sensors */
+
+static int flush_event_fd[2]; /* Pipe used for flush signaling */
/* We use pthread condition variables to get worker threads out of sleep */
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];
+#define FLUSH_REPORT_TAG 900
/*
- * We associate tags to each of our poll set entries. These tags have the
- * following values:
+ * We associate tags to each of our poll set entries. These tags have the following values:
* - a iio device number if the fd is a iio character device fd
* - THREAD_REPORT_TAG_BASE + sensor handle if the fd is the receiving end of a pipe used by a sysfs data acquisition thread
*/
-#define THREAD_REPORT_TAG_BASE 0x00010000
+#define THREAD_REPORT_TAG_BASE 1000
-#define ENABLE_BUFFER_RETRIES 10
-#define ENABLE_BUFFER_RETRY_DELAY_MS 10
+/* If buffer enable fails, we may want to retry a few times before giving up */
+#define ENABLE_BUFFER_RETRIES 3
+#define ENABLE_BUFFER_RETRY_DELAY_MS 10
inline int is_enabled (int s)
}
-static int enable_buffer(int dev_num, int enabled)
+static int enable_buffer (int dev_num, int enabled)
{
char sysfs_path[PATH_MAX];
- int ret, retries, millisec;
- struct timespec req = {0};
-
- retries = ENABLE_BUFFER_RETRIES;
- millisec = ENABLE_BUFFER_RETRY_DELAY_MS;
- req.tv_sec = 0;
- req.tv_nsec = millisec * 1000000L;
+ int retries = ENABLE_BUFFER_RETRIES;
sprintf(sysfs_path, ENABLE_PATH, dev_num);
- while (retries--) {
+ while (retries) {
/* Low level, non-multiplexed, enable/disable routine */
- ret = sysfs_write_int(sysfs_path, enabled);
- if (ret > 0)
- break;
-
- ALOGE("Failed enabling buffer, retrying");
- nanosleep(&req, (struct timespec *)NULL);
- }
+ if (sysfs_write_int(sysfs_path, enabled) > 0)
+ return 0;
- if (ret < 0) {
- ALOGE("Could not enable buffer\n");
- return -EIO;
+ ALOGE("Failed enabling buffer on dev%d, retrying", dev_num);
+ usleep(ENABLE_BUFFER_RETRY_DELAY_MS*1000);
+ retries--;
}
- return 0;
+ ALOGE("Could not enable buffer\n");
+ return -EIO;
}
return ret;
}
+static int enable_event(int dev_num, const char *name, int enabled)
+{
+ char sysfs_path[PATH_MAX];
+
+ sprintf(sysfs_path, EVENTS_PATH "%s", dev_num, name);
+ return sysfs_write_int(sysfs_path, enabled);
+}
+
+static int enable_sensor(int dev_num, const char *tag, int enabled)
+{
+ char sysfs_path[PATH_MAX];
+
+ sprintf(sysfs_path, SENSOR_ENABLE_PATH, dev_num, tag);
+ return sysfs_write_int(sysfs_path, enabled);
+}
static void enable_iio_timestamp (int dev_num, int known_channels)
{
}
-static int decode_type_spec (const char type_buf[MAX_TYPE_SPEC_LEN],
- datum_info_t *type_info)
+static int decode_type_spec (const char type_buf[MAX_TYPE_SPEC_LEN], datum_info_t *type_info)
{
/* Return size in bytes for this type specification, or -1 in error */
char sign;
tokens = sscanf(type_buf, "%ce:%c%u/%u>>%u", &endianness, &sign, &realbits, &storagebits, &shift);
- if (tokens != 5 || (endianness != 'b' && endianness != 'l') || (sign != 'u' && sign != 's') ||
- realbits > storagebits || (storagebits != 16 && storagebits != 32 && storagebits != 64)) {
+ if (tokens != 5 || (endianness != 'b' && endianness != 'l') || (sign != 'u' && sign != 's') ||
+ realbits > storagebits || (storagebits != 16 && storagebits != 32 && storagebits != 64)) {
ALOGE("Invalid iio channel type spec: %s\n", type_buf);
return -1;
}
known_channels++;
}
+ sensor_update_max_range(s);
+
/* Stop sampling - if we are recovering from hal restart */
enable_buffer(dev_num, 0);
setup_trigger(s, "\n");
* the sequence of indices, so it is dependent on discovery of all sensors.
*/
offset = 0;
+
for (i=0; i<MAX_SENSORS * MAX_CHANNELS; i++) {
s = sensor_handle_from_index[i];
c = channel_number_from_index[i];
* Adjust counters based on sensor enable action. Return values are:
* 0 if the operation was completed and we're all set
* 1 if we toggled the state of the sensor and there's work left
+ * -1 in case of an error
*/
int dev_num = sensor[s].dev_num;
ALOGI("Enabling sensor %d (iio device %d: %s)\n", s, dev_num, sensor[s].friendly_name);
switch (sensor[s].type) {
+ case SENSOR_TYPE_ACCELEROMETER:
+ accel_cal_init(s);
+ break;
+
case SENSOR_TYPE_MAGNETIC_FIELD:
- compass_read_data(&sensor[s]);
+ compass_read_data(s);
break;
case SENSOR_TYPE_GYROSCOPE:
- gyro_cal_init(&sensor[s]);
+ gyro_cal_init(s);
break;
}
} else {
/* Sensor disabled, lower report available flag */
sensor[s].report_pending = 0;
- if (sensor[s].type == SENSOR_TYPE_MAGNETIC_FIELD)
- compass_store_data(&sensor[s]);
+ /* Save calibration data to persistent storage */
+ switch (sensor[s].type) {
+ case SENSOR_TYPE_ACCELEROMETER:
+ accel_cal_store(s);
+ break;
+
+ case SENSOR_TYPE_MAGNETIC_FIELD:
+ compass_store_data(s);
+ break;
- if (sensor[s].type == SENSOR_TYPE_GYROSCOPE)
- gyro_store_data(&sensor[s]);
+ case SENSOR_TYPE_GYROSCOPE:
+ gyro_store_data(s);
+ break;
+ }
}
/* We changed the state of a sensor: adjust device ref counts */
- if (sensor[s].num_channels) {
-
- if (enabled)
- trig_sensors_per_dev[dev_num]++;
- else
- trig_sensors_per_dev[dev_num]--;
+ switch(sensor[s].mode) {
+ case MODE_TRIGGER:
+ if (enabled)
+ trig_sensors_per_dev[dev_num]++;
+ else
+ trig_sensors_per_dev[dev_num]--;
+ return 1;
+ case MODE_POLL:
+ if (enabled) {
+ active_poll_sensors++;
+ poll_sensors_per_dev[dev_num]++;
return 1;
- }
-
- if (enabled) {
- active_poll_sensors++;
- poll_sensors_per_dev[dev_num]++;
+ } else {
+ active_poll_sensors--;
+ poll_sensors_per_dev[dev_num]--;
+ return 1;
+ }
+ case MODE_EVENT:
return 1;
+ default:
+ /* Invalid sensor mode */
+ return -1;
}
-
- active_poll_sensors--;
- poll_sensors_per_dev[dev_num]--;
- return 1;
}
-static int get_field_count (int s)
+static int get_field_count (int s, size_t *field_size)
{
+ *field_size = sizeof(float);
+
switch (sensor[s].type) {
case SENSOR_TYPE_ACCELEROMETER: /* m/s^2 */
case SENSOR_TYPE_MAGNETIC_FIELD: /* micro-tesla */
case SENSOR_TYPE_GYROSCOPE: /* radians/s */
return 3;
+ case SENSOR_TYPE_INTERNAL_INTENSITY:
+ case SENSOR_TYPE_INTERNAL_ILLUMINANCE:
case SENSOR_TYPE_LIGHT: /* SI lux units */
case SENSOR_TYPE_AMBIENT_TEMPERATURE: /* °C */
case SENSOR_TYPE_TEMPERATURE: /* °C */
case SENSOR_TYPE_PROXIMITY: /* centimeters */
case SENSOR_TYPE_PRESSURE: /* hecto-pascal */
case SENSOR_TYPE_RELATIVE_HUMIDITY: /* percent */
+ case SENSOR_TYPE_STEP_DETECTOR: /* event: always 1 */
return 1;
case SENSOR_TYPE_ROTATION_VECTOR:
return 4;
+ case SENSOR_TYPE_STEP_COUNTER: /* number of steps */
+ *field_size = sizeof(uint64_t);
+ return 1;
default:
ALOGE("Unknown sensor type!\n");
return 0; /* Drop sample */
}
}
+/*
+ * CTS acceptable thresholds:
+ * EventGapVerification.java: (th <= 1.8)
+ * FrequencyVerification.java: (0.9)*(expected freq) => (th <= 1.1111)
+ */
+#define THRESHOLD 1.10
+#define MAX_DELAY 500000000 /* 500 ms */
+
+void set_report_ts(int s, int64_t ts)
+{
+ int64_t maxTs, period;
+
+ /*
+ * A bit of a hack to please a bunch of cts tests. They
+ * expect the timestamp to be exacly according to the set-up
+ * frequency but if we're simply getting the timestamp at hal level
+ * 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[s].report_ts && sensor[s].sampling_rate &&
+ REPORTING_MODE(sensor_desc[s].flags) == SENSOR_FLAG_CONTINUOUS_MODE)
+ {
+ period = (int64_t) (1000000000.0 / sensor[s].sampling_rate);
+ maxTs = sensor[s].report_ts + THRESHOLD * period;
+ /* If we're too far behind get back on track */
+ if (ts - maxTs >= MAX_DELAY)
+ maxTs = ts;
+ sensor[s].report_ts = (ts < maxTs ? ts : maxTs);
+ } else {
+ sensor[s].report_ts = ts;
+ }
+}
static void* acquisition_routine (void* param)
{
*/
int s = (int) (size_t) param;
- int num_fields, sample_size;
+ int num_fields;
sensors_event_t data = {0};
int c;
int ret;
struct timespec target_time;
int64_t timestamp, period, start, stop;
+ size_t field_size;
if (s < 0 || s >= sensor_count) {
ALOGE("Invalid sensor handle!\n");
return NULL;
}
- ALOGI("Entering data acquisition thread S%d (%s), rate:%g\n", s, sensor[s].friendly_name, sensor[s].sampling_rate);
+ ALOGI("Entering S%d (%s) data acquisition thread: rate:%g\n", s, sensor[s].friendly_name, sensor[s].sampling_rate);
if (sensor[s].sampling_rate <= 0) {
ALOGE("Invalid rate in acquisition routine for sensor %d: %g\n", s, sensor[s].sampling_rate);
return NULL;
}
- num_fields = get_field_count(s);
- sample_size = sizeof(int64_t) + num_fields * sizeof(float);
+ /* Initialize data fields that will be shared by all sensor reports */
+ data.version = sizeof(sensors_event_t);
+ data.sensor = s;
+ data.type = sensor_desc[s].type;
+
+ num_fields = get_field_count(s, &field_size);
/*
* Each condition variable is associated to a mutex that has to be locked by the thread that's waiting on it. We use these condition
/* Check and honor termination requests */
while (sensor[s].thread_data_fd[1] != -1) {
start = get_timestamp_boot();
+
/* Read values through sysfs */
for (c=0; c<num_fields; c++) {
- data.data[c] = acquire_immediate_value(s, c);
+ if (field_size == sizeof(uint64_t))
+ data.u64.data[c] = acquire_immediate_uint64_value(s, c);
+ else
+ data.data[c] = acquire_immediate_float_value(s, c);
+
/* Check and honor termination requests */
if (sensor[s].thread_data_fd[1] == -1)
goto exit;
}
stop = get_timestamp_boot();
- data.timestamp = start/2 + stop/2;
-
+ set_report_ts(s, start/2 + stop/2);
+ data.timestamp = sensor[s].report_ts;
/* If the sample looks good */
if (sensor[s].ops.finalize(s, &data)) {
/* Pipe it for transmission to poll loop */
- ret = write(sensor[s].thread_data_fd[1], &data.timestamp, sample_size);
+ ret = write(sensor[s].thread_data_fd[1], &data, sizeof(sensors_event_t));
- if (ret != sample_size)
- ALOGE("S%d write failure: wrote %d, got %d\n", s, sample_size, ret);
+ if (ret != sizeof(sensors_event_t))
+ ALOGE("S%d write failure: wrote %d, got %d\n", s, sizeof(sensors_event_t), ret);
}
/* Check and honor termination requests */
timestamp += period;
set_timestamp(&target_time, timestamp);
- /* Wait until the sampling time elapses, or a rate change is signaled, or a thread exit is requested.
- */
+ /* Wait until the sampling time elapses, or a rate change is signaled, or a thread exit is requested */
ret = pthread_cond_timedwait(&thread_release_cond[s], &thread_release_mutex[s], &target_time);
}
/* Add incoming side of pipe to our poll set, with a suitable tag */
ret = epoll_ctl(poll_fd, EPOLL_CTL_ADD, incoming_data_fd , &ev);
+ if (ret == -1) {
+ ALOGE("Failed adding %d to poll set (%s)\n",
+ incoming_data_fd, strerror(errno));
+ }
/* Create and start worker thread */
- ret = pthread_create( &sensor[s].acquisition_thread, NULL, acquisition_routine, (void*) (size_t) s);
+ ret = pthread_create(&sensor[s].acquisition_thread, NULL, acquisition_routine, (void*) (size_t) s);
}
static int is_fast_accelerometer (int s)
{
/*
- * Some games don't react well to accelerometers using any-motion
- * triggers. Even very low thresholds seem to trip them, and they tend
- * to request fairly high event rates. Favor continuous triggers if the
- * sensor is an accelerometer and uses a sampling rate of at least 25.
+ * Some games don't react well to accelerometers using any-motion triggers. Even very low thresholds seem to trip them, and they tend to
+ * request fairly high event rates. Favor continuous triggers if the sensor is an accelerometer and uses a sampling rate of at least 25.
*/
if (sensor[s].type != SENSOR_TYPE_ACCELEROMETER)
return arbitrated_rate;
}
+extern float sensor_get_max_freq (int s);
+
+static float select_closest_available_rate(int s, float requested_rate)
+{
+ float sr;
+ int j;
+ float selected_rate = 0;
+ float max_rate_from_prop = sensor_get_max_freq(s);
+ int dev_num = sensor[s].dev_num;
+
+ if (!sensor[s].avail_freqs_count)
+ return requested_rate;
+
+ for (j = 0; j < sensor[s].avail_freqs_count; j++) {
+
+ sr = sensor[s].avail_freqs[j];
+
+ /* If this matches the selected rate, we're happy. Have some tolerance for rounding errors and avoid needless jumps to higher rates */
+ if ((fabs(requested_rate - sr) <= 0.01) && (sr <= max_rate_from_prop)) {
+ return sr;
+ }
+
+ /* Select rate if it's less than max freq */
+ if ((sr > selected_rate) && (sr <= max_rate_from_prop)) {
+ selected_rate = sr;
+ }
+
+ /*
+ * If we reached a higher value than the desired rate, adjust selected rate so it matches the first higher available one and
+ * stop parsing - this makes the assumption that rates are sorted by increasing value in the allowed frequencies string.
+ */
+ if (sr > requested_rate) {
+ return selected_rate;
+ }
+ }
+
+ /* Check for wrong values */
+ if (selected_rate < 0.1) {
+ return requested_rate;
+ } else {
+ return selected_rate;
+ }
+}
static int sensor_set_rate (int s, float requested_rate)
{
/* Set the rate at which a specific sensor should report events. See Android sensors.h for indication on sensor trigger modes */
char sysfs_path[PATH_MAX];
- char avail_sysfs_path[PATH_MAX];
int dev_num = sensor[s].dev_num;
int i = sensor[s].catalog_index;
const char *prefix = sensor_catalog[i].tag;
int per_sensor_sampling_rate;
int per_device_sampling_rate;
- int32_t min_delay_us = sensor_desc[s].minDelay;
- max_delay_t max_delay_us = sensor_desc[s].maxDelay;
- float min_supported_rate = max_delay_us ? 1000000.0/max_delay_us : 1;
- float max_supported_rate = min_delay_us && min_delay_us != -1 ? 1000000.0/min_delay_us : 0;
- char freqs_buf[100];
- char* cursor;
int n;
float sr;
float group_max_sampling_rate;
float cur_sampling_rate; /* Currently used sampling rate */
float arb_sampling_rate; /* Granted sampling rate after arbitration */
+ char hrtimer_sampling_path[PATH_MAX];
+ char trigger_path[PATH_MAX];
ALOGV("Sampling rate %g requested on sensor %d (%s)\n", requested_rate, s, sensor[s].friendly_name);
arb_sampling_rate = requested_rate;
- if (arb_sampling_rate < min_supported_rate) {
- ALOGV("Sampling rate %g too low for %s, using %g instead\n", arb_sampling_rate, sensor[s].friendly_name, min_supported_rate);
- arb_sampling_rate = min_supported_rate;
+ if (arb_sampling_rate < sensor[s].min_supported_rate) {
+ ALOGV("Sampling rate %g too low for %s, using %g instead\n", arb_sampling_rate, sensor[s].friendly_name, sensor[s].min_supported_rate);
+ arb_sampling_rate = sensor[s].min_supported_rate;
}
/* If one of the linked sensors uses a higher rate, adopt it */
arb_sampling_rate = group_max_sampling_rate;
}
- if (max_supported_rate && arb_sampling_rate > max_supported_rate) {
- ALOGV("Sampling rate %g too high for %s, using %g instead\n", arb_sampling_rate, sensor[s].friendly_name, max_supported_rate);
- arb_sampling_rate = max_supported_rate;
+ if (sensor[s].max_supported_rate && arb_sampling_rate > sensor[s].max_supported_rate) {
+ ALOGV("Sampling rate %g too high for %s, using %g instead\n", arb_sampling_rate, sensor[s].friendly_name, sensor[s].max_supported_rate);
+ arb_sampling_rate = sensor[s].max_supported_rate;
}
sensor[s].sampling_rate = arb_sampling_rate;
return 0;
/* If we're dealing with a poll-mode sensor */
- if (!sensor[s].num_channels) {
+ if (sensor[s].mode == MODE_POLL) {
if (is_enabled(s))
pthread_cond_signal(&thread_release_cond[s]); /* Wake up thread so the new sampling rate gets used */
return 0;
return -ENOSYS;
}
- /* Check if we have contraints on allowed sampling rates */
-
- sprintf(avail_sysfs_path, DEVICE_AVAIL_FREQ_PATH, dev_num);
-
- if (sysfs_read_str(avail_sysfs_path, freqs_buf, sizeof(freqs_buf)) > 0){
- cursor = freqs_buf;
-
- /* Decode allowed sampling rates string, ex: "10 20 50 100" */
-
- /* While we're not at the end of the string */
- while (*cursor && cursor[0]) {
-
- /* Decode a single value */
- sr = strtod(cursor, NULL);
-
- /* If this matches the selected rate, we're happy. Have some tolerance for rounding errors and avoid needless jumps to higher rates */
- if (fabs(arb_sampling_rate - sr) <= 0.001) {
- arb_sampling_rate = sr;
- break;
- }
-
- /*
- * If we reached a higher value than the desired rate, adjust selected rate so it matches the first higher
- * available one and stop parsing - this makes the assumption that rates are sorted by increasing value
- * in the allowed frequencies string.
- */
- if (sr > arb_sampling_rate) {
- arb_sampling_rate = sr;
- break;
- }
-
- /* Skip digits */
- while (cursor[0] && !isspace(cursor[0]))
- cursor++;
-
- /* Skip spaces */
- while (cursor[0] && isspace(cursor[0]))
- cursor++;
- }
- }
-
- if (max_supported_rate &&
- arb_sampling_rate > max_supported_rate) {
- arb_sampling_rate = max_supported_rate;
+ if (sensor[s].hrtimer_trigger_name[0] != '\0') {
+ snprintf(trigger_path, PATH_MAX, "%s%s%d/", IIO_DEVICES, "trigger", sensor[s].trigger_nr);
+ snprintf(hrtimer_sampling_path, PATH_MAX, "%s%s", trigger_path, "sampling_frequency");
+ /* Enforce frequency update when software trigger
+ * frequency and current sampling rate are different */
+ if (sysfs_read_float(hrtimer_sampling_path, &sr) != -1 && sr != cur_sampling_rate)
+ cur_sampling_rate = -1;
+ } else {
+ arb_sampling_rate = select_closest_available_rate(s, arb_sampling_rate);
}
+ /* Record the rate that was agreed upon with the sensor taken in isolation ; this avoid uncontrolled ripple effects between colocated sensor rates */
+ sensor[s].semi_arbitrated_rate = arb_sampling_rate;
/* Coordinate with others active sensors on the same device, if any */
if (per_device_sampling_rate)
for (n=0; n<sensor_count; n++)
- if (n != s && sensor[n].dev_num == dev_num && sensor[n].num_channels && is_enabled(n) && sensor[n].sampling_rate > arb_sampling_rate) {
+ if (n != s && sensor[n].dev_num == dev_num && sensor[n].num_channels && is_enabled(n) &&
+ sensor[n].semi_arbitrated_rate > arb_sampling_rate) {
ALOGV("Sampling rate shared between %s and %s, using %g instead of %g\n", sensor[s].friendly_name, sensor[n].friendly_name,
- sensor[n].sampling_rate, arb_sampling_rate);
- arb_sampling_rate = sensor[n].sampling_rate;
+ sensor[n].semi_arbitrated_rate, arb_sampling_rate);
+ arb_sampling_rate = sensor[n].semi_arbitrated_rate;
}
sensor[s].sampling_rate = arb_sampling_rate;
if (arb_sampling_rate == cur_sampling_rate)
return 0;
- ALOGI("Sensor %d (%s) sampling rate set to %g\n",
- s, sensor[s].friendly_name, arb_sampling_rate);
+ ALOGI("Sensor %d (%s) sampling rate set to %g\n", s, sensor[s].friendly_name, arb_sampling_rate);
+
+ if (sensor[s].hrtimer_trigger_name[0] != '\0')
+ sysfs_write_float(hrtimer_sampling_path, ceilf(arb_sampling_rate));
if (trig_sensors_per_dev[dev_num])
enable_buffer(dev_num, 0);
- sysfs_write_float(sysfs_path, arb_sampling_rate);
+ if (sensor[s].hrtimer_trigger_name[0] != '\0') {
+ sysfs_write_float(sysfs_path, select_closest_available_rate(s, arb_sampling_rate));
+ } else {
+ sysfs_write_float(sysfs_path, arb_sampling_rate);
+ }
/* Check if it makes sense to use an alternate trigger */
tentative_switch_trigger(s);
* that ended up being used after arbitration.
*/
- int i, j, base, user;
+ int i, j, base;
if (sensor[s].is_virtual) {
/* Take care of downwards dependencies */
{
char device_name[PATH_MAX];
struct epoll_event ev = {0};
- int dev_fd;
- int ret;
+ int dev_fd, event_fd;
+ int ret, c, d;
int dev_num = sensor[s].dev_num;
- int is_poll_sensor = !sensor[s].num_channels;
+ size_t field_size;
+ int catalog_index = sensor[s].catalog_index;
if (sensor[s].is_virtual)
return sensor_activate_virtual(s, enabled, from_virtual);
sensor[s].event_count = 0;
sensor[s].meta_data_pending = 0;
- if (enabled && (sensor[s].quirks & QUIRK_NOISY))
+ if (enabled)
setup_noise_filtering(s); /* Initialize filtering data if required */
- if (!is_poll_sensor) {
+ if (sensor[s].mode == MODE_TRIGGER) {
/* Stop sampling */
enable_buffer(dev_num, 0);
if (trig_sensors_per_dev[dev_num]) {
/* Start sampling */
- setup_trigger(s, sensor[s].init_trigger_name);
+ if (sensor[s].hrtimer_trigger_name[0] != '\0')
+ setup_trigger(s, sensor[s].hrtimer_trigger_name);
+ else
+ setup_trigger(s, sensor[s].init_trigger_name);
+
enable_buffer(dev_num, 1);
}
+ } else if (sensor[s].mode == MODE_POLL) {
+ if (sensor[s].needs_enable) {
+ enable_sensor(dev_num, sensor_catalog[catalog_index].tag, enabled);
+ }
}
/*
dev_fd = device_fd[dev_num];
if (!enabled) {
- if (is_poll_sensor)
+ if (sensor[s].mode == MODE_POLL)
stop_acquisition_thread(s);
if (dev_fd != -1 && !poll_sensors_per_dev[dev_num] && !trig_sensors_per_dev[dev_num]) {
device_fd[dev_num] = -1;
}
+ if (sensor[s].mode == MODE_EVENT) {
+ event_fd = events_fd[dev_num];
+
+ for (c = 0; c < sensor_catalog[catalog_index].num_channels; c++) {
+ for (d = 0; d < sensor_catalog[catalog_index].channel[c].num_events; d++)
+ enable_event(dev_num, sensor_catalog[catalog_index].channel[c].event[d].ev_en_path, enabled);
+ }
+
+ epoll_ctl(poll_fd, EPOLL_CTL_DEL, event_fd, NULL);
+ close(event_fd);
+ events_fd[dev_num] = -1;
+
+ }
+
/* Release any filtering data we may have accumulated */
release_noise_filtering_data(s);
ALOGV("Opened %s: fd=%d\n", device_name, dev_fd);
- if (!is_poll_sensor) {
+ if (sensor[s].mode == MODE_TRIGGER) {
/* Add this iio device fd to the set of watched fds */
ev.events = EPOLLIN;
}
/* Note: poll-mode fds are not readable */
+ } else if (sensor[s].mode == MODE_EVENT) {
+ event_fd = events_fd[dev_num];
+
+ ret = ioctl(dev_fd, IIO_GET_EVENT_FD_IOCTL, &event_fd);
+ if (ret == -1 || event_fd == -1) {
+ ALOGE("Failed to retrieve event_fd from %d (%s)\n", dev_fd, strerror(errno));
+ return -1;
+ }
+ events_fd[dev_num] = event_fd;
+ ALOGV("Opened fd=%d to receive events\n", event_fd);
+
+ /* Add this event fd to the set of watched fds */
+ ev.events = EPOLLIN;
+ ev.data.u32 = dev_num;
+
+ ret = epoll_ctl(poll_fd, EPOLL_CTL_ADD, event_fd, &ev);
+ if (ret == -1) {
+ ALOGE("Failed adding %d to poll set (%s)\n", event_fd, strerror(errno));
+ return -1;
+ }
+ for (c = 0; c < sensor_catalog[catalog_index].num_channels; c++) {
+ int d;
+ for (d = 0; d < sensor_catalog[catalog_index].channel[c].num_events; d++)
+ enable_event(dev_num, sensor_catalog[catalog_index].channel[c].event[d].ev_en_path, enabled);
+ }
+
+ if (!poll_sensors_per_dev[dev_num] && !trig_sensors_per_dev[dev_num]) {
+ close(dev_fd);
+ device_fd[dev_num] = -1;
+ }
}
}
/* Ensure that on-change sensors send at least one event after enable */
- sensor[s].prev_val = -1;
+ get_field_count(s, &field_size);
+ if (field_size == sizeof(uint64_t))
+ sensor[s].prev_val.data64 = -1;
+ else
+ sensor[s].prev_val.data = -1;
- if (is_poll_sensor)
+ if (sensor[s].mode == MODE_POLL)
start_acquisition_thread(s);
/* Reevaluate sampling rates of linked sensors */
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
-#define MAX_DELAY 500000000 /* 500 ms */
-
-void set_report_ts(int s, int64_t ts)
-{
- int64_t maxTs, period;
-
- /*
- * A bit of a hack to please a bunch of cts tests. They
- * expect the timestamp to be exacly according to the set-up
- * frequency but if we're simply getting the timestamp at hal level
- * 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[s].report_ts && sensor[s].sampling_rate &&
- REPORTING_MODE(sensor_desc[s].flags) == SENSOR_FLAG_CONTINUOUS_MODE)
- {
- period = (int64_t) (1000000000.0 / sensor[s].sampling_rate);
- maxTs = sensor[s].report_ts + THRESHOLD * period;
- /* If we're too far behind get back on track */
- if (ts - maxTs >= MAX_DELAY)
- maxTs = ts;
- sensor[s].report_ts = (ts < maxTs ? ts : maxTs);
- } else {
- sensor[s].report_ts = ts;
- }
-}
-
-
static void stamp_reports (int dev_num, int64_t ts)
{
int s;
for (s=0; s<MAX_SENSORS; s++)
- if (sensor[s].dev_num == dev_num &&
- is_enabled(s))
- set_report_ts(s, ts);
+ if (sensor[s].dev_num == dev_num && is_enabled(s) && sensor[s].mode != MODE_POLL) {
+ if (sensor[s].quirks & QUIRK_SPOTTY)
+ set_report_ts(s, ts);
+ else
+ sensor[s].report_ts = ts;
+ }
}
-static int integrate_device_report (int dev_num)
+static int integrate_device_report_from_dev(int dev_num, int fd)
{
int len;
int s,c;
int64_t boot_to_rt_delta;
/* There's an incoming report on the specified iio device char dev fd */
-
- if (dev_num < 0 || dev_num >= MAX_DEVICES) {
- ALOGE("Event reported on unexpected iio device %d\n", dev_num);
- return -1;
- }
-
- if (device_fd[dev_num] == -1) {
+ if (fd == -1) {
ALOGE("Ignoring stale report on iio device %d\n", dev_num);
return -1;
}
- len = read(device_fd[dev_num], buf, expected_dev_report_size[dev_num]);
+ len = read(fd, buf, expected_dev_report_size[dev_num]);
if (len == -1) {
ALOGE("Could not read report from iio device %d (%s)\n", dev_num, strerror(errno));
sensor[s].report_pending = DATA_TRIGGER;
sensor[s].report_initialized = 1;
- ts_offset += sr_offset;
}
/* Tentatively switch to an any-motion trigger if conditions are met */
}
/* Align on a 64 bits boundary */
- ts_offset = (ts_offset + 7)/8*8;
+ ts_offset = expected_dev_report_size[dev_num] - sizeof(int64_t);
/* If we read an amount of data consistent with timestamp presence */
if (len == expected_dev_report_size[dev_num])
return 0;
}
+static int integrate_device_report_from_event(int dev_num, int fd)
+{
+ int len, s;
+ int64_t ts;
+ struct iio_event_data event;
+ int64_t boot_to_rt_delta = get_timestamp_boot() - get_timestamp_realtime();
+
+ /* There's an incoming report on the specified iio device char dev fd */
+ if (fd == -1) {
+ ALOGE("Ignoring stale report on event fd %d of device %d\n",
+ fd, dev_num);
+ return -1;
+ }
+
+ len = read(fd, &event, sizeof(event));
+
+ if (len == -1) {
+ ALOGE("Could not read event from fd %d of device %d (%s)\n",
+ fd, dev_num, strerror(errno));
+ return -1;
+ }
+
+ ts = event.timestamp + boot_to_rt_delta;
+
+ ALOGV("Read event %lld from fd %d of iio device %d - ts %lld\n", event.id, fd, dev_num, ts);
+
+ /* Map device report to sensor reports */
+ for (s = 0; s < MAX_SENSORS; s++)
+ if (sensor[s].dev_num == dev_num &&
+ is_enabled(s)) {
+ sensor[s].event_id = event.id;
+ sensor[s].report_ts = ts;
+ sensor[s].report_pending = 1;
+ sensor[s].report_initialized = 1;
+ ALOGV("Sensor %d report available (1 byte)\n", s);
+ }
+ return 0;
+}
+
+static int integrate_device_report(int dev_num)
+{
+ int ret = 0;
+
+ if (dev_num < 0 || dev_num >= MAX_DEVICES) {
+ ALOGE("Event reported on unexpected iio device %d\n", dev_num);
+ return -1;
+ }
+
+ if (events_fd[dev_num] != -1) {
+ ret = integrate_device_report_from_event(dev_num, events_fd[dev_num]);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (device_fd[dev_num] != -1)
+ ret = integrate_device_report_from_dev(dev_num, device_fd[dev_num]);
+
+ return ret;
+}
static int propagate_vsensor_report (int s, sensors_event_t *data)
{
memcpy(data, &sensor[s].sample, sizeof(sensors_event_t));
data->sensor = s;
- data->type = sensor[s].type;
+ data->type = sensor_desc[s].type; /* sensor_desc[s].type can differ from sensor[s].type ; internal types are remapped */
return 1;
}
{
/* There's a sensor report pending for this sensor ; transmit it */
- int num_fields = get_field_count(s);
+ size_t field_size;
+ int num_fields = get_field_count(s, &field_size);
int c;
unsigned char* current_sample;
+ int ret;
/* If there's nothing to return... we're done */
if (!num_fields)
return 0;
+ ALOGV("Sample on sensor %d (type %d):\n", s, sensor[s].type);
+
+ if (sensor[s].mode == MODE_POLL) {
+ /* We received a good sample but we're not directly enabled so we'll drop */
+ if (!sensor[s].directly_enabled)
+ return 0;
+ /* Use the data provided by the acquisition thread */
+ ALOGV("Reporting data from worker thread for S%d\n", s);
+ memcpy(data, &sensor[s].sample, sizeof(sensors_event_t));
+ data->timestamp = sensor[s].report_ts;
+ return 1;
+ }
+
memset(data, 0, sizeof(sensors_event_t));
data->version = sizeof(sensors_event_t);
data->sensor = s;
- data->type = sensor[s].type;
+ data->type = sensor_desc[s].type; /* sensor_desc[s].type can differ from sensor[s].type ; internal types are remapped */
data->timestamp = sensor[s].report_ts;
- ALOGV("Sample on sensor %d (type %d):\n", s, sensor[s].type);
-
- current_sample = sensor[s].report_buffer;
+ if (sensor[s].mode == MODE_EVENT) {
+ ALOGV("Reporting event\n");
+ /* Android requires events to return 1.0 */
+ int dir = IIO_EVENT_CODE_EXTRACT_DIR(sensor[s].event_id);
+ switch (sensor[s].type) {
+ case SENSOR_TYPE_PROXIMITY:
+ if (dir == IIO_EV_DIR_FALLING)
+ data->data[0] = 0.0;
+ else
+ data->data[0] = 1.0;
+ break;
+ default:
+ data->data[0] = 1.0;
+ break;
- /* If this is a poll sensor */
- if (!sensor[s].num_channels) {
- /* Use the data provided by the acquisition thread */
- ALOGV("Reporting data from worker thread for S%d\n", s);
- memcpy(data->data, current_sample, num_fields * sizeof(float));
+ }
+ data->data[1] = 0.0;
+ data->data[2] = 0.0;
return 1;
}
/* Convert the data into the expected Android-level format */
+
+ current_sample = sensor[s].report_buffer;
+
for (c=0; c<num_fields; c++) {
data->data[c] = sensor[s].ops.transform (s, c, current_sample);
current_sample += sensor[s].channel[c].size;
}
+ ret = sensor[s].ops.finalize(s, data);
+
+ /* We will drop samples if the sensor is not directly enabled */
+ if (!sensor[s].directly_enabled)
+ return 0;
+
/* The finalize routine, in addition to its late sample processing duty, has the final say on whether or not the sample gets sent to Android */
- return sensor[s].ops.finalize(s, data);
+ return ret;
}
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.
+ * 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;
{
int s = tag - THREAD_REPORT_TAG_BASE;
int len;
- int expected_len;
- int64_t timestamp;
- unsigned char current_sample[MAX_SENSOR_REPORT_SIZE];
-
- expected_len = sizeof(int64_t) + get_field_count(s) * sizeof(float);
- len = read(sensor[s].thread_data_fd[0],
- current_sample,
- expected_len);
+ len = read(sensor[s].thread_data_fd[0], &sensor[s].sample, sizeof(sensors_event_t));
- memcpy(×tamp, current_sample, sizeof(int64_t));
- memcpy(sensor[s].report_buffer, sizeof(int64_t) + current_sample, expected_len - sizeof(int64_t));
-
- if (len == expected_len) {
- set_report_ts(s, timestamp);
+ if (len == sizeof(sensors_event_t))
sensor[s].report_pending = DATA_SYSFS;
- }
}
struct epoll_event ev[MAX_DEVICES];
int returned_events;
int event_count;
- int uncal_start;
/* Get one or more events from our collection of sensors */
return_available_sensor_reports:
synthetize_duplicate_samples();
returned_events = 0;
+
/* Check our sensor collection for available reports */
for (s=0; s<sensor_count && returned_events < count; s++) {
+
if (sensor[s].report_pending) {
event_count = 0;
/* Get report from acquisition thread */
integrate_thread_report(ev[i].data.u32);
break;
+ case FLUSH_REPORT_TAG:
+ {
+ char flush_event_content;
+ read(flush_event_fd[0], &flush_event_content, sizeof(flush_event_content));
+ break;
+ }
default:
ALOGW("Unexpected event source!\n");
int sensor_flush (int s)
{
+ char flush_event_content = 0;
/* If one shot or not enabled return -EINVAL */
if (sensor_desc[s].flags & SENSOR_FLAG_ONE_SHOT_MODE || !is_enabled(s))
return -EINVAL;
sensor[s].meta_data_pending++;
+ write(flush_event_fd[1], &flush_event_content, sizeof(flush_event_content));
return 0;
}
int allocate_control_data (void)
{
- int i;
+ int i, ret;
+ struct epoll_event ev = {0};
- for (i=0; i<MAX_DEVICES; i++)
+ for (i=0; i<MAX_DEVICES; i++) {
device_fd[i] = -1;
+ events_fd[i] = -1;
+ }
poll_fd = epoll_create(MAX_DEVICES);
return -1;
}
+ ret = pipe(flush_event_fd);
+ if (ret) {
+ ALOGE("Cannot create flush_event_fd");
+ return -1;
+ }
+
+ ev.events = EPOLLIN;
+ ev.data.u32 = FLUSH_REPORT_TAG;
+ ret = epoll_ctl(poll_fd, EPOLL_CTL_ADD, flush_event_fd[0] , &ev);
+ if (ret == -1) {
+ ALOGE("Failed adding %d to poll set (%s)\n",
+ flush_event_fd[0], strerror(errno));
+ return -1;
+ }
+
return poll_fd;
}