X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=control.c;h=b7ed570e2646420bb03f50a14f3a1a75d04a0800;hb=f4cb7dc91324cc194d1503743027e8937cd712e8;hp=6e961a2cd3bcb49347235e6a542d93f89fbf8ee5;hpb=f9635becefaca6e9e062be9a58e0ef2fdd3cf993;p=android-x86%2Fhardware-intel-libsensors.git diff --git a/control.c b/control.c index 6e961a2..b7ed570 100644 --- a/control.c +++ b/control.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -15,6 +16,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 */ @@ -26,9 +28,12 @@ static int poll_fd; /* epoll instance covering all enabled sensors */ static int active_poll_sensors; /* Number of enabled poll-mode sensors */ +int64_t ts_delta; /* delta between SystemClock.getNanos and our timestamp */ + /* 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 @@ -39,25 +44,63 @@ static pthread_mutex_t thread_release_mutex [MAX_SENSORS]; * */ #define THREAD_REPORT_TAG_BASE 0x00010000 +#define ENABLE_BUFFER_RETRIES 10 +#define ENABLE_BUFFER_RETRY_DELAY_MS 10 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; sprintf(sysfs_path, ENABLE_PATH, dev_num); - /* Low level, non-multiplexed, enable/disable routine */ - return sysfs_write_int(sysfs_path, enabled); + 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 (ret < 0) { + ALOGE("Could not enable buffer\n"); + return -EIO; + } + + return 0; } -static int setup_trigger(int dev_num, 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); - sprintf(sysfs_path, TRIGGER_PATH, dev_num); + if (trigger_val[0] != '\n') + ALOGI("Setting S%d (%s) trigger to %s\n", s, + sensor_info[s].friendly_name, trigger_val); - return sysfs_write_str(sysfs_path, trigger_val); + while (ret == -1 && attempts) { + ret = sysfs_write_str(sysfs_path, trigger_val); + attempts--; + } + + 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; } @@ -156,7 +199,7 @@ void build_sensor_report_maps(int dev_num) /* Stop sampling - if we are recovering from hal restart */ enable_buffer(dev_num, 0); - setup_trigger(dev_num, "\n"); + setup_trigger(s, "\n"); /* Turn on channels we're aware of */ for (c=0;c 1) return 0; /* The sensor was, and remains, in use */ - switch (sensor_type) { + switch (sensor_info[s].type) { case SENSOR_TYPE_MAGNETIC_FIELD: compass_read_data(&sensor_info[s]); break; case SENSOR_TYPE_GYROSCOPE: + case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED: gyro_cal_init(&sensor_info[s]); break; } @@ -246,10 +288,20 @@ int adjust_counters (int s, int enabled) /* Sensor disabled, lower report available flag */ sensor_info[s].report_pending = 0; - if (sensor_type == SENSOR_TYPE_MAGNETIC_FIELD) + if (sensor_info[s].type == SENSOR_TYPE_MAGNETIC_FIELD) compass_store_data(&sensor_info[s]); + + if(sensor_info[s].type == SENSOR_TYPE_GYROSCOPE || + sensor_info[s].type == SENSOR_TYPE_GYROSCOPE_UNCALIBRATED) + gyro_store_data(&sensor_info[s]); } + + /* If uncalibrated type and pair is already active don't adjust counters */ + if (sensor_info[s].type == SENSOR_TYPE_GYROSCOPE_UNCALIBRATED && + sensor_info[sensor_info[s].pair_idx].enable_count != 0) + return 0; + /* We changed the state of a sensor - adjust per iio device counters */ /* If this is a regular event-driven sensor */ @@ -277,13 +329,11 @@ int adjust_counters (int s, int enabled) static int get_field_count (int s) { - int catalog_index = sensor_info[s].catalog_index; - int sensor_type = sensor_catalog[catalog_index].type; - - switch (sensor_type) { + switch (sensor_info[s].type) { case SENSOR_TYPE_ACCELEROMETER: /* m/s^2 */ case SENSOR_TYPE_MAGNETIC_FIELD: /* micro-tesla */ case SENSOR_TYPE_ORIENTATION: /* degrees */ + case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED: case SENSOR_TYPE_GYROSCOPE: /* radians/s */ return 3; @@ -305,15 +355,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) { /* @@ -325,30 +366,30 @@ static void* acquisition_routine (void* param) * Bionic does not provide pthread_cancel / pthread_testcancel... */ - int s = (int) param; - int report_fd; - int num_fields; + int s = (int) (size_t) param; + int num_fields, sample_size; struct sensors_event_t data = {0}; int c; - int sampling_rate; 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 @@ -358,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_monotonic(); - 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 (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 + * 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_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 + (is_accel ? 1 : THRESHOLD) * period; + sensor_info[s].report_ts = (ts < maxTs ? ts : maxTs); + } else { + sensor_info[s].report_ts = ts; + } +} + +static int integrate_device_report (int dev_num) { int len; int s,c; @@ -592,7 +781,6 @@ static int integrate_device_report(int dev_num) unsigned char *target; unsigned char *source; int size; - int ts; /* There's an incoming report on the specified iio device char dev fd */ @@ -606,7 +794,7 @@ static int integrate_device_report(int dev_num) return -1; } - ts = get_timestamp(); + len = read(device_fd[dev_num], buf, MAX_SENSOR_REPORT_SIZE); @@ -618,6 +806,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; sversion = sizeof(sensors_event_t); data->sensor = s; - data->type = sensor_type; + data->type = sensor_info[s].type; data->timestamp = sensor_info[s].report_ts; - ALOGV("Sample on sensor %d (type %d):\n", s, sensor_type); + ALOGV("Sample on sensor %d (type %d):\n", s, sensor_info[s].type); current_sample = sensor_info[s].report_buffer; @@ -701,6 +899,58 @@ 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; sbias_x; + data[uncal_start + i].data[1] = data[returned_events + i].data[1] + gyro_data->bias_y; + data[uncal_start + i].data[2] = data[returned_events + i].data[2] + gyro_data->bias_z; + data[uncal_start + i].uncalibrated_gyro.bias[0] = gyro_data->bias_x; + data[uncal_start + i].uncalibrated_gyro.bias[1] = gyro_data->bias_y; + data[uncal_start + i].uncalibrated_gyro.bias[2] = gyro_data->bias_z; + } + event_count <<= 1; + } + sensor_info[sensor_info[s].pair_idx].report_pending = 0; + returned_events += event_count; /* * If the sample was deemed invalid or unreportable, * e.g. had the same value as the previously reported * 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; @@ -760,10 +1096,10 @@ 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; } @@ -793,6 +1129,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 */ @@ -808,25 +1163,38 @@ int sensor_set_delay(int s, int64_t ns) float cur_sampling_rate; /* Currently used sampling rate */ int per_sensor_sampling_rate; int per_device_sampling_rate; - float max_supported_rate = 0; + 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.0f / max_delay_us) : 1; + float max_supported_rate = + (min_delay_us && min_delay_us != -1) ? (1000000.0f / min_delay_us) : 0; char freqs_buf[100]; char* cursor; 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. */ - if (new_sampling_rate < 1) - new_sampling_rate = 1; + if (new_sampling_rate < min_supported_rate) + new_sampling_rate = min_supported_rate; + + if (max_supported_rate && + new_sampling_rate > max_supported_rate) { + new_sampling_rate = max_supported_rate; + } sensor_info[s].sampling_rate = new_sampling_rate; @@ -882,9 +1250,6 @@ int sensor_set_delay(int s, int64_t ns) /* Decode a single value */ sr = strtod(cursor, NULL); - if (sr > max_supported_rate) - max_supported_rate = sr; - /* If this matches the selected rate, we're happy */ if (new_sampling_rate == sr) break; @@ -911,13 +1276,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; @@ -929,17 +1292,29 @@ int sensor_set_delay(int s, int64_t ns) sysfs_write_float(sysfs_path, new_sampling_rate); + /* 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); 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) { int i; - struct epoll_event ev = {0}; for (i=0; i