X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=description.c;h=302121fc05b4c4aed8a200ed1eb148484fafbf39;hb=378432a4f0cb62a7189340ee1424a529fcf2085a;hp=4d00d63af8cbcec720c244c62e22db7b5df98e0a;hpb=345931b294daa55f0ffdcd7332a69bdf9775a466;p=android-x86%2Fhardware-intel-libsensors.git diff --git a/description.c b/description.c index 4d00d63..302121f 100644 --- a/description.c +++ b/description.c @@ -1,24 +1,125 @@ /* - * Copyright (C) 2014 Intel Corporation. + * Copyright (C) 2014-2015 Intel Corporation. */ #include +#include #include #include #include +#include "common.h" #include "enumeration.h" +#include "description.h" +#include "utils.h" #define IIO_SENSOR_HAL_VERSION 1 +#define MIN_ON_CHANGE_SAMPLING_PERIOD_US 200000 /* For on change sensors (temperature, proximity, ALS, etc.) report we support 5 Hz max (0.2 s min period) */ +#define MAX_ON_CHANGE_SAMPLING_PERIOD_US 10000000 /* 0.1 Hz min (10 s max period)*/ +#define ANDROID_MAX_FREQ 1000 /* 1000 Hz - This is how much Android requests for the fastest frequency */ -static int sensor_get_st_prop (int s, const char* sel, char val[MAX_NAME_SIZE]) +/* + * About properties + * + * We acquire a number of parameters about sensors by reading properties. + * The idea here is that someone (either a script, or daemon, sets them + * depending on the set of sensors present on the machine. + * + * There are fallback paths in case the properties are not defined, but it is + * highly desirable to at least have the following for each sensor: + * + * ro.iio.anglvel.name = Gyroscope + * ro.iio.anglvel.vendor = Intel + * ro.iio.anglvel.max_range = 35 + * ro.iio.anglvel.resolution = 0.002 + * ro.iio.anglvel.power = 6.1 + * + * Besides these, we have a couple of knobs initially used to cope with Intel + * Sensor Hub oddities, such as HID inspired units or firmware bugs: + * + * 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. + * + * The "noisy" quirk indicates that the underlying driver has a unusually high + * level of noise in its readings, and that the HAL has to accomodate it + * somehow, e.g. in the magnetometer calibration code path. + * + * This one is used specifically to pass a calibration scale to ALS drivers: + * + * ro.iio.illuminance.name = CPLM3218x Ambient Light Sensor + * ro.iio.illuminance.vendor = Capella Microsystems + * ro.iio.illuminance.max_range = 167000 + * ro.iio.illuminance.resolution = 1 + * ro.iio.illuminance.power = .001 + * ro.iio.illuminance.illumincalib = 7400 + * + * There's a 'opt_scale' specifier, documented as follows: + * + * This adds support for a scaling factor that can be expressed + * using properties, for all sensors, on a channel basis. That + * scaling factor is applied after all other transforms have been + * applied, and is intended as a way to compensate for problems + * such as an incorrect axis polarity for a given sensor. + * + * The syntax is ..opt_scale, e.g. + * ro.iio.accel.y.opt_scale = -1 to negate the sign of the y readings + * for the accelerometer. + * + * For sensors using a single channel - and only those - the channel + * name is implicitly void and a syntax such as ro.iio.illuminance. + * opt_scale = 3 has to be used. + * + * 'panel' and 'rotation' specifiers can be used to express ACPI PLD placement + * information ; if found they will be used in priority over the actual ACPI + * data. That is intended as a way to verify values during development. + * + * It's possible to use the contents of the iio device name as a way to + * discriminate between sensors. Several sensors of the same type can coexist: + * e.g. ro.iio.temp.bmg160.name = BMG160 Thermometer will be used in priority + * over ro.iio.temp.name = BMC150 Thermometer if the sensor for which we query + * properties values happen to have its iio device name set to bmg160. + */ + +int sensor_get_st_prop (int s, const char* sel, char val[MAX_NAME_SIZE]) { char prop_name[PROP_NAME_MAX]; char prop_val[PROP_VALUE_MAX]; - int i = sensor_info[s].catalog_index; + char extended_sel[PROP_VALUE_MAX]; + + int i = sensor[s].catalog_index; const char *prefix = sensor_catalog[i].tag; + const char *shorthand = sensor_catalog[i].shorthand; - sprintf(prop_name, PROP_BASE, prefix, sel); + /* First try most specialized form, like ro.iio.anglvel.bmg160.name */ + + snprintf(extended_sel, PROP_NAME_MAX, "%s.%s", + sensor[s].internal_name, sel); + + snprintf(prop_name, PROP_NAME_MAX, PROP_BASE, prefix, extended_sel); + + if (property_get(prop_name, prop_val, "")) { + strncpy(val, prop_val, MAX_NAME_SIZE-1); + val[MAX_NAME_SIZE-1] = '\0'; + return 0; + } + + if (shorthand[0] != '\0') { + /* Try with shorthand instead of prefix */ + snprintf(prop_name, PROP_NAME_MAX, PROP_BASE, shorthand, extended_sel); + + if (property_get(prop_name, prop_val, "")) { + strncpy(val, prop_val, MAX_NAME_SIZE-1); + val[MAX_NAME_SIZE-1] = '\0'; + return 0; + } + } + /* Fall back to simple form, like ro.iio.anglvel.name */ + + snprintf(prop_name, PROP_NAME_MAX, PROP_BASE, prefix, sel); if (property_get(prop_name, prop_val, "")) { strncpy(val, prop_val, MAX_NAME_SIZE-1); @@ -30,6 +131,18 @@ static int sensor_get_st_prop (int s, const char* sel, char val[MAX_NAME_SIZE]) } +int sensor_get_prop (int s, const char* sel, int* val) +{ + char buf[MAX_NAME_SIZE]; + + if (sensor_get_st_prop(s, sel, buf)) + return -1; + + *val = atoi(buf); + return 0; +} + + int sensor_get_fl_prop (int s, const char* sel, float* val) { char buf[MAX_NAME_SIZE]; @@ -44,33 +157,63 @@ int sensor_get_fl_prop (int s, const char* sel, float* val) char* sensor_get_name (int s) { - if (sensor_info[s].friendly_name[0] != '\0' || - !sensor_get_st_prop(s, "name", sensor_info[s].friendly_name)) - return sensor_info[s].friendly_name; + char buf[MAX_NAME_SIZE]; + + if (sensor[s].is_virtual) { + switch (sensor[s].type) { + case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED: + case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED: + strcpy(buf, sensor[sensor[s].base[0]].friendly_name); + snprintf(sensor[s].friendly_name, + MAX_NAME_SIZE, + "%s %s", "Uncalibrated", buf); + return sensor[s].friendly_name; + + default: + return ""; + } + } + + if (sensor[s].friendly_name[0] != '\0' || + !sensor_get_st_prop(s, "name", sensor[s].friendly_name)) + return sensor[s].friendly_name; /* If we got a iio device name from sysfs, use it */ - if (sensor_info[s].internal_name[0]) { - snprintf(sensor_info[s].friendly_name, MAX_NAME_SIZE, "S%d-%s", - s, sensor_info[s].internal_name); + if (sensor[s].internal_name[0]) { + snprintf(sensor[s].friendly_name, MAX_NAME_SIZE, "S%d-%s", + s, sensor[s].internal_name); } else { - sprintf(sensor_info[s].friendly_name, "S%d", s); + sprintf(sensor[s].friendly_name, "S%d", s); } - return sensor_info[s].friendly_name; + return sensor[s].friendly_name; } char* sensor_get_vendor (int s) { - if (sensor_info[s].vendor_name[0] || - !sensor_get_st_prop(s, "vendor", sensor_info[s].vendor_name)) - return sensor_info[s].vendor_name; + if (sensor[s].is_virtual) { + switch (sensor[s].type) { + case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED: + case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED: + return sensor[sensor[s].base[0]].vendor_name; + break; + + default: + return ""; + + } + } + + if (sensor[s].vendor_name[0] || + !sensor_get_st_prop(s, "vendor", sensor[s].vendor_name)) + return sensor[s].vendor_name; return ""; } -int sensor_get_version (int s) +int sensor_get_version (__attribute__((unused)) int s) { return IIO_SENSOR_HAL_VERSION; } @@ -78,21 +221,26 @@ int sensor_get_version (int s) float sensor_get_max_range (int s) { - int catalog_index; - int sensor_type; + if (sensor[s].is_virtual) { + switch (sensor[s].type) { + case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED: + case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED: + return sensor[sensor[s].base[0]].max_range; + + default: + return 0.0; + } + } - if (sensor_info[s].max_range != 0.0 || - !sensor_get_fl_prop(s, "max_range", &sensor_info[s].max_range)) - return sensor_info[s].max_range; + if (sensor[s].max_range != 0.0 || + !sensor_get_fl_prop(s, "max_range", &sensor[s].max_range)) + return sensor[s].max_range; /* Try returning a sensible value given the sensor type */ /* We should cap returned samples accordingly... */ - catalog_index = sensor_info[s].catalog_index; - sensor_type = sensor_catalog[catalog_index].type; - - switch (sensor_type) { + switch (sensor_desc[s].type) { case SENSOR_TYPE_ACCELEROMETER: /* m/s^2 */ return 50; @@ -116,16 +264,63 @@ float sensor_get_max_range (int s) return 100; default: - return 0.0; + return 0; } } +static float sensor_get_min_freq (int s) +{ + /* + * Check if a low cap has been specified for this sensor sampling rate. + * In some case, even when the driver supports lower rate, we still + * wish to receive a certain number of samples per seconds for various + * reasons (calibration, filtering, no change in power consumption...). + */ + + float min_freq; + + if (!sensor_get_fl_prop(s, "min_freq", &min_freq)) + return min_freq; + + return 0; +} + + +static float sensor_get_max_freq (int s) +{ + float max_freq; + + if (!sensor_get_fl_prop(s, "max_freq", &max_freq)) + return max_freq; + + return ANDROID_MAX_FREQ; +} + +int sensor_get_cal_steps (int s) +{ + int cal_steps; + if (!sensor_get_prop(s, "cal_steps", &cal_steps)) + return cal_steps; + + return 0; +} float sensor_get_resolution (int s) { - if (sensor_info[s].resolution != 0.0 || - !sensor_get_fl_prop(s, "resolution", &sensor_info[s].resolution)) - return sensor_info[s].resolution; + if (sensor[s].is_virtual) { + switch (sensor[s].type) { + case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED: + case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED: + return sensor[sensor[s].base[0]].resolution; + + default: + return 0; + } + } + + if (sensor[s].resolution != 0.0 || + !sensor_get_fl_prop(s, "resolution", &sensor[s].resolution)) + return sensor[s].resolution; return 0; } @@ -133,10 +328,22 @@ float sensor_get_resolution (int s) float sensor_get_power (int s) { + + if (sensor[s].is_virtual) { + switch (sensor[s].type) { + case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED: + case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED: + return sensor[sensor[s].base[0]].power; + + default: + return 0; + } + } + /* mA used while sensor is in use ; not sure about volts :) */ - if (sensor_info[s].power != 0.0 || - !sensor_get_fl_prop(s, "power", &sensor_info[s].power)) - return sensor_info[s].power; + if (sensor[s].power != 0.0 || + !sensor_get_fl_prop(s, "power", &sensor[s].power)) + return sensor[s].power; return 0; } @@ -145,37 +352,382 @@ float sensor_get_power (int s) float sensor_get_illumincalib (int s) { /* calibrating the ALS Sensor*/ - if (sensor_info[s].illumincalib != 0.0 || - !sensor_get_fl_prop(s, "illumincalib", &sensor_info[s].illumincalib)) { - return sensor_info[s].illumincalib; + if (sensor[s].illumincalib != 0.0 || + !sensor_get_fl_prop(s, "illumincalib", &sensor[s].illumincalib)) { + return sensor[s].illumincalib; } return 0; } +uint32_t sensor_get_quirks (int s) +{ + char quirks_buf[MAX_NAME_SIZE]; + + /* Read and decode quirks property on first reference */ + if (!(sensor[s].quirks & QUIRK_ALREADY_DECODED)) { + quirks_buf[0] = '\0'; + sensor_get_st_prop(s, "quirks", quirks_buf); + + if (strstr(quirks_buf, "init-rate")) + sensor[s].quirks |= QUIRK_INITIAL_RATE; + + if (strstr(quirks_buf, "continuous")) + sensor[s].quirks |= QUIRK_FORCE_CONTINUOUS; + + if (strstr(quirks_buf, "terse")) + sensor[s].quirks |= QUIRK_TERSE_DRIVER; + + if (strstr(quirks_buf, "noisy")) + sensor[s].quirks |= QUIRK_NOISY; + + if (strstr(quirks_buf, "biased")) + sensor[s].quirks |= QUIRK_BIASED; + + if (strstr(quirks_buf, "spotty")) + sensor[s].quirks |= QUIRK_SPOTTY; + + if (strstr(quirks_buf, "no-event")) + sensor[s].quirks |= QUIRK_NO_EVENT_MODE; + + if (strstr(quirks_buf, "no-trig")) + sensor[s].quirks |= QUIRK_NO_TRIG_MODE; + + if (strstr(quirks_buf, "no-poll")) + sensor[s].quirks |= QUIRK_NO_POLL_MODE; + + if (strstr(quirks_buf, "hrtimer")) + sensor[s].quirks |= QUIRK_HRTIMER; + + sensor[s].quirks |= QUIRK_ALREADY_DECODED; + } + + return sensor[s].quirks; +} + + int sensor_get_order (int s, unsigned char map[MAX_CHANNELS]) { char buf[MAX_NAME_SIZE]; int i; - int count = sensor_catalog[sensor_info[s].catalog_index].num_channels; + int count = sensor_catalog[sensor[s].catalog_index].num_channels; - memset(map, 0, MAX_CHANNELS); - - if (sensor_get_st_prop(s, "order", buf)) + if (sensor_get_st_prop(s, "order", buf)) return 0; /* No order property */ /* Assume ASCII characters, in the '0'..'9' range */ for (i=0; i= count) { + if (buf[i] - '0' >= count) { ALOGE("Order index out of range for sensor %d\n", s); return 0; } + for (i=0; i 0) { + + min_supported_rate = 1000; + cursor = freqs_buf; + + while (*cursor && cursor[0]) { + + /* Decode a single value */ + sr = strtod(cursor, NULL); + + if (sr < min_supported_rate) + min_supported_rate = sr; + + /* Skip digits */ + while (cursor[0] && !isspace(cursor[0])) + cursor++; + + /* Skip spaces */ + while (cursor[0] && isspace(cursor[0])) + cursor++; + } + + break; + } + + /* Fall through ... */ + + default: + /* Report 1 Hz */ + min_supported_rate = 1; + break; + } + + /* Check if a minimum rate was specified for this sensor */ + rate_cap = sensor_get_min_freq(s); + + if (min_supported_rate < rate_cap) + min_supported_rate = rate_cap; + + /* return 0 for wrong values */ + if (min_supported_rate < 0.1) + return 0; + + /* Return microseconds */ + return (max_delay_t) (1000000.0 / min_supported_rate); +} + + +int32_t sensor_get_min_delay (int s) +{ + char avail_sysfs_path[PATH_MAX]; + int dev_num = sensor[s].dev_num; + char freqs_buf[100]; + char* cursor; + float max_supported_rate = 0; + float max_from_prop = sensor_get_max_freq(s); + float sr; + + /* continuous, on change: minimum sampling period allowed in microseconds. + * special : 0, unless otherwise noted + * one-shot:-1 + */ + switch (REPORTING_MODE(sensor_desc[s].flags)) { + case SENSOR_FLAG_ON_CHANGE_MODE: + return MIN_ON_CHANGE_SAMPLING_PERIOD_US; + + case SENSOR_FLAG_SPECIAL_REPORTING_MODE: + return 0; + + case SENSOR_FLAG_ONE_SHOT_MODE: + return -1; + + default: + break; + } + + if (sensor[s].is_virtual) { + switch (sensor[s].type) { + case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED: + case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED: + return sensor_desc[sensor[s].base[0]].minDelay; + default: + return 0; + } + } + + sprintf(avail_sysfs_path, DEVICE_AVAIL_FREQ_PATH, dev_num); + + if (sysfs_read_str(avail_sysfs_path, freqs_buf, sizeof(freqs_buf)) < 0) { + if (sensor[s].mode == MODE_POLL) { + /* If we have max specified via a property use it */ + if (max_from_prop != ANDROID_MAX_FREQ) + max_supported_rate = max_from_prop; + else + /* The should rate */ + max_supported_rate = get_cdd_freq(s, 0); + } + } else { + cursor = freqs_buf; + while (*cursor && cursor[0]) { + + /* Decode a single value */ + sr = strtod(cursor, NULL); + + if (sr > max_supported_rate && sr <= max_from_prop) + max_supported_rate = sr; + + /* Skip digits */ + while (cursor[0] && !isspace(cursor[0])) + cursor++; + + /* Skip spaces */ + while (cursor[0] && isspace(cursor[0])) + cursor++; + } + } + + /* return 0 for wrong values */ + if (max_supported_rate < 0.1) + return 0; + + /* Return microseconds */ + return (int32_t) (1000000.0 / max_supported_rate); +}