X-Git-Url: http://git.osdn.net/view?p=android-x86%2Fhardware-intel-libsensors.git;a=blobdiff_plain;f=description.c;h=28a3533bf8966adf3ae099b192ef14111607d923;hp=4d00d63af8cbcec720c244c62e22db7b5df98e0a;hb=e35fc5677585eb789efb5c02e2de084fbedcd67d;hpb=e83ffb3a4aff2babc81d1d6dc45379e0ce2247a3 diff --git a/description.c b/description.c index 4d00d63..28a3533 100644 --- a/description.c +++ b/description.c @@ -1,24 +1,126 @@ /* - * 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" +#include "transform.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 +132,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,99 +158,226 @@ 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; } - -float sensor_get_max_range (int s) +void sensor_update_max_range(int s) { - int catalog_index; - int sensor_type; - - 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; - - /* 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; + if (sensor[s].max_range) + return; + + if (sensor[s].num_channels && sensor[s].channel[0].type_info.realbits) { + switch (sensor[s].type) { + case SENSOR_TYPE_MAGNETIC_FIELD: + sensor[s].max_range = (1ULL << sensor[s].channel[0].type_info.realbits) * + CONVERT_MICROTESLA_TO_GAUSS(sensor[s].resolution) + + (sensor[s].offset || sensor[s].channel[0].offset); + sensor[s].max_range = CONVERT_GAUSS_TO_MICROTESLA(sensor[s].max_range); + break; + case SENSOR_TYPE_PROXIMITY: + break; + default: + sensor[s].max_range = (1ULL << sensor[s].channel[0].type_info.realbits) * + sensor[s].resolution + (sensor[s].offset || sensor[s].channel[0].offset); + break; + } + } - switch (sensor_type) { + if (!sensor[s].max_range) { + /* Try returning a sensible value given the sensor type */ + /* We should cap returned samples accordingly... */ + switch (sensor[s].type) { case SENSOR_TYPE_ACCELEROMETER: /* m/s^2 */ - return 50; - + sensor[s].max_range = 50; + break; case SENSOR_TYPE_MAGNETIC_FIELD: /* micro-tesla */ - return 500; - + sensor[s].max_range = 500; + break; case SENSOR_TYPE_ORIENTATION: /* degrees */ - return 360; - + sensor[s].max_range = 360; + break; case SENSOR_TYPE_GYROSCOPE: /* radians/s */ - return 10; - + sensor[s].max_range = 10; + break; case SENSOR_TYPE_LIGHT: /* SI lux units */ - return 50000; - + sensor[s].max_range = 50000; + break; 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 */ - return 100; + sensor[s].max_range = 100; + break; + } + } - default: - return 0.0; + if (sensor[s].max_range) + sensor_desc[s].maxRange = sensor[s].max_range; +} + +float sensor_get_max_range (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]].max_range; + + default: + return 0.0; } + } + + if (sensor[s].max_range != 0.0 || + !sensor_get_fl_prop(s, "max_range", &sensor[s].max_range)) + return sensor[s].max_range; + + return 0; } +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; -float sensor_get_resolution (int s) + if (!sensor_get_fl_prop(s, "min_freq", &min_freq)) + return min_freq; + + return 0; +} + + +float sensor_get_max_freq (int s) { - if (sensor_info[s].resolution != 0.0 || - !sensor_get_fl_prop(s, "resolution", &sensor_info[s].resolution)) - return sensor_info[s].resolution; + 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[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; + } + + sensor[s].resolution = sensor[s].scale; + if (!sensor[s].resolution && sensor[s].num_channels) + sensor[s].resolution = sensor[s].channel[0].scale; + + if (sensor[s].type == SENSOR_TYPE_MAGNETIC_FIELD) + sensor[s].resolution = CONVERT_GAUSS_TO_MICROTESLA(sensor[s].resolution); + + return sensor[s].resolution ? : 1; +} + 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 +386,400 @@ 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; + + if (strstr(quirks_buf, "secondary")) + sensor[s].quirks |= QUIRK_SECONDARY; + + 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; - - memset(map, 0, MAX_CHANNELS); + int count = sensor_catalog[sensor[s].catalog_index].num_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 max_supported_rate && + sensor[s].avail_freqs[i] <= max_from_prop) { + max_supported_rate = sensor[s].avail_freqs[i]; + } + } + } + + /* return 0 for wrong values */ + if (max_supported_rate < 0.1) + return 0; + + /* Return microseconds */ + return (int32_t) (1000000.0 / max_supported_rate); +}