| /* Copyright (C) 2009 The Android Open Source Project |
| ** |
| ** This software is licensed under the terms of the GNU General Public |
| ** License version 2, as published by the Free Software Foundation, and |
| ** may be copied, distributed, and modified under those terms. |
| ** |
| ** This program is distributed in the hope that it will be useful, |
| ** but WITHOUT ANY WARRANTY; without even the implied warranty of |
| ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| ** GNU General Public License for more details. |
| */ |
| |
| #include "android/hw-sensors.h" |
| |
| #include "android/emulation/android_qemud.h" |
| #include "android/globals.h" |
| #include "android/sensors-port.h" |
| #include "android/utils/debug.h" |
| #include "android/utils/misc.h" |
| #include "android/utils/stream.h" |
| #include "android/utils/system.h" |
| #include "android/utils/looper.h" |
| |
| #include <assert.h> |
| #include <errno.h> |
| #include <stdbool.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <math.h> |
| |
| #define E(...) derror(__VA_ARGS__) |
| #define W(...) dwarning(__VA_ARGS__) |
| #define D(...) VERBOSE_PRINT(sensors, __VA_ARGS__) |
| #define V(...) VERBOSE_PRINT(init, __VA_ARGS__) |
| |
| /* define T_ACTIVE to 1 to debug transport communications */ |
| #define T_ACTIVE 0 |
| |
| #if T_ACTIVE |
| #define T(...) VERBOSE_PRINT(sensors, __VA_ARGS__) |
| #else |
| #define T(...) ((void)0) |
| #endif |
| |
| /* this code supports emulated sensor hardware |
| * |
| * Note that currently, only the accelerometer is really emulated, and only |
| * for the purpose of allowing auto-rotating the screen in keyboard-less |
| * configurations. |
| * |
| * |
| */ |
| |
| static const struct { |
| const char* name; |
| int id; |
| } _sSensors[MAX_SENSORS] = { |
| #define SENSOR_(x, y) {y, ANDROID_SENSOR_##x}, |
| SENSORS_LIST |
| #undef SENSOR_ |
| }; |
| |
| static int _sensorIdFromName(const char* name) { |
| int nn; |
| for (nn = 0; nn < MAX_SENSORS; nn++) |
| if (!strcmp(_sSensors[nn].name, name)) |
| return _sSensors[nn].id; |
| return -1; |
| } |
| |
| static const char* _sensorNameFromId(int id) { |
| int nn; |
| for (nn = 0; nn < MAX_SENSORS; nn++) |
| if (id == _sSensors[nn].id) |
| return _sSensors[nn].name; |
| return NULL; |
| } |
| |
| /* For common Sensor Value struct */ |
| typedef struct { float a, b, c; } SensorValues; |
| |
| typedef struct { float x, y, z; } Acceleration; |
| |
| typedef struct { float x, y, z; } MagneticField; |
| |
| typedef struct { |
| float azimuth; |
| float pitch; |
| float roll; |
| } Orientation; |
| |
| typedef struct { float celsius; } Temperature; |
| |
| typedef struct { float value; } Proximity; |
| |
| typedef struct { float value; } Light; |
| |
| typedef struct { float value; } Pressure; |
| |
| typedef struct { float value; } Humidity; |
| |
| typedef struct { |
| bool valid; |
| int length; |
| char value[128]; |
| } SerializedSensor; |
| |
| typedef struct { |
| bool enabled; |
| union { |
| SensorValues value; |
| Acceleration acceleration; |
| MagneticField magnetic; |
| Orientation orientation; |
| Temperature temperature; |
| Proximity proximity; |
| Light light; |
| Pressure pressure; |
| Humidity humidity; |
| } u; |
| SerializedSensor serialized; |
| } Sensor; |
| |
| /* |
| * - when the qemu-specific sensors HAL module starts, it sends |
| * "list-sensors" |
| * |
| * - this code replies with a string containing an integer corresponding |
| * to a bitmap of available hardware sensors in the current AVD |
| * configuration (e.g. "1" a.k.a (1 << ANDROID_SENSOR_ACCELERATION)) |
| * |
| * - the HAL module sends "set:<sensor>:<flag>" to enable or disable |
| * the report of a given sensor state. <sensor> must be the name of |
| * a given sensor (e.g. "accelerometer"), and <flag> must be either |
| * "1" (to enable) or "0" (to disable). |
| * |
| * - Once at least one sensor is "enabled", this code should periodically |
| * send information about the corresponding enabled sensors. The default |
| * period is 200ms. |
| * |
| * - the HAL module sends "set-delay:<delay>", where <delay> is an integer |
| * corresponding to a time delay in milli-seconds. This corresponds to |
| * a new interval between sensor events sent by this code to the HAL |
| * module. |
| * |
| * - the HAL module can also send a "wake" command. This code should simply |
| * send the "wake" back to the module. This is used internally to wake a |
| * blocking read that happens in a different thread. This ping-pong makes |
| * the code in the HAL module very simple. |
| * |
| * - each timer tick, this code sends sensor reports in the following |
| * format (each line corresponds to a different line sent to the module): |
| * |
| * acceleration:<x>:<y>:<z> |
| * magnetic-field:<x>:<y>:<z> |
| * orientation:<azimuth>:<pitch>:<roll> |
| * temperature:<celsius> |
| * light:<lux> |
| * pressure:<hpa> |
| * humidity:<percent> |
| * sync:<time_us> |
| * |
| * Where each line before the sync:<time_us> is optional and will only |
| * appear if the corresponding sensor has been enabled by the HAL module. |
| * |
| * Note that <time_us> is the VM time in micro-seconds when the report |
| * was "taken" by this code. This is adjusted by the HAL module to |
| * emulated system time (using the first sync: to compute an adjustment |
| * offset). |
| */ |
| #define HEADER_SIZE 4 |
| #define BUFFER_SIZE 512 |
| |
| typedef struct HwSensorClient HwSensorClient; |
| |
| typedef struct { |
| QemudService* service; |
| Sensor sensors[MAX_SENSORS]; |
| HwSensorClient* clients; |
| AndroidSensorsPort* sensors_port; |
| } HwSensors; |
| |
| struct HwSensorClient { |
| HwSensorClient* next; |
| HwSensors* sensors; |
| QemudClient* client; |
| LoopTimer* timer; |
| uint32_t enabledMask; |
| int32_t delay_ms; |
| }; |
| |
| static void _hwSensorClient_free(HwSensorClient* cl) { |
| /* remove from sensors's list */ |
| if (cl->sensors) { |
| HwSensorClient** pnode = &cl->sensors->clients; |
| for (;;) { |
| HwSensorClient* node = *pnode; |
| if (node == NULL) |
| break; |
| if (node == cl) { |
| *pnode = cl->next; |
| break; |
| } |
| pnode = &node->next; |
| } |
| cl->next = NULL; |
| cl->sensors = NULL; |
| } |
| |
| /* close QEMUD client, if any */ |
| if (cl->client) { |
| qemud_client_close(cl->client); |
| cl->client = NULL; |
| } |
| /* remove timer, if any */ |
| if (cl->timer) { |
| loopTimer_stop(cl->timer); |
| loopTimer_free(cl->timer); |
| cl->timer = NULL; |
| } |
| AFREE(cl); |
| } |
| |
| /* forward */ |
| static void _hwSensorClient_tick(void* opaque, LoopTimer* timer); |
| |
| static HwSensorClient* _hwSensorClient_new(HwSensors* sensors) { |
| HwSensorClient* cl; |
| |
| ANEW0(cl); |
| |
| cl->sensors = sensors; |
| cl->enabledMask = 0; |
| cl->delay_ms = 800; |
| cl->timer = |
| loopTimer_newWithClock(looper_getForThread(), _hwSensorClient_tick, |
| cl, LOOPER_CLOCK_VIRTUAL); |
| |
| cl->next = sensors->clients; |
| sensors->clients = cl; |
| |
| return cl; |
| } |
| |
| /* forward */ |
| |
| static void _hwSensorClient_receive(HwSensorClient* cl, |
| uint8_t* query, |
| int querylen); |
| |
| /* Qemud service management */ |
| |
| static void _hwSensorClient_recv(void* opaque, |
| uint8_t* msg, |
| int msglen, |
| QemudClient* client) { |
| HwSensorClient* cl = opaque; |
| |
| _hwSensorClient_receive(cl, msg, msglen); |
| } |
| |
| static void _hwSensorClient_close(void* opaque) { |
| HwSensorClient* cl = opaque; |
| |
| /* the client is already closed here */ |
| cl->client = NULL; |
| _hwSensorClient_free(cl); |
| } |
| |
| /* send a one-line message to the HAL module through a qemud channel */ |
| static void _hwSensorClient_send(HwSensorClient* cl, |
| const uint8_t* msg, |
| int msglen) { |
| D("%s: '%s'", __FUNCTION__, quote_bytes((const void*)msg, msglen)); |
| qemud_client_send(cl->client, msg, msglen); |
| } |
| |
| static int _hwSensorClient_enabled(HwSensorClient* cl, int sensorId) { |
| return (cl->enabledMask & (1 << sensorId)) != 0; |
| } |
| |
| /* a helper function that replaces commas (,) with points (.). |
| * Each sensor string must be processed this way before being |
| * sent into the guest. This is because the system locale may |
| * cause decimal values to be formatted with a comma instead of |
| * a decimal point, but that would not be parsed correctly |
| * within the guest. |
| */ |
| static void _hwSensorClient_sanitizeSensorString(char* string, int maxlen) { |
| int i; |
| for (i = 0; i < maxlen && string[i] != '\0'; i++) { |
| if (string[i] == ',') { |
| string[i] = '.'; |
| } |
| } |
| } |
| |
| // a function to serialize the sensor value based on its ID |
| static void serializeSensorValue(Sensor* sensor, AndroidSensor sensor_id) { |
| switch (sensor_id) { |
| case ANDROID_SENSOR_ACCELERATION: { |
| sensor->serialized.length = snprintf( |
| sensor->serialized.value, sizeof(sensor->serialized.value), |
| "acceleration:%g:%g:%g", sensor->u.acceleration.x, |
| sensor->u.acceleration.y, sensor->u.acceleration.z); |
| |
| // TODO(grigoryj): debug output for investigating rotation bug |
| static float prev_acceleration[] = {0.0f, 0.0f, 0.0f}; |
| if (VERBOSE_CHECK(rotation) && |
| (prev_acceleration[0] != sensor->u.acceleration.x || |
| prev_acceleration[1] != sensor->u.acceleration.y || |
| prev_acceleration[2] != sensor->u.acceleration.z)) { |
| fprintf(stderr, "Sent %s to sensors HAL\n", |
| sensor->serialized.value); |
| prev_acceleration[0] = sensor->u.acceleration.x; |
| prev_acceleration[1] = sensor->u.acceleration.y; |
| prev_acceleration[2] = sensor->u.acceleration.z; |
| } |
| break; |
| } |
| case ANDROID_SENSOR_MAGNETIC_FIELD: |
| /* NOTE: sensors HAL expects "magnetic", not * "magnetic-field" |
| * name here. |
| */ |
| sensor->serialized.length = snprintf( |
| sensor->serialized.value, sizeof(sensor->serialized.value), |
| "magnetic:%g:%g:%g", sensor->u.magnetic.x, |
| sensor->u.magnetic.y, sensor->u.magnetic.z); |
| break; |
| case ANDROID_SENSOR_ORIENTATION: |
| sensor->serialized.length = snprintf( |
| sensor->serialized.value, sizeof(sensor->serialized.value), |
| "orientation:%g:%g:%g", sensor->u.orientation.azimuth, |
| sensor->u.orientation.pitch, sensor->u.orientation.roll); |
| break; |
| case ANDROID_SENSOR_TEMPERATURE: |
| sensor->serialized.length = snprintf( |
| sensor->serialized.value, sizeof(sensor->serialized.value), |
| "temperature:%g", sensor->u.temperature.celsius); |
| break; |
| case ANDROID_SENSOR_PROXIMITY: |
| sensor->serialized.length = snprintf( |
| sensor->serialized.value, sizeof(sensor->serialized.value), |
| "proximity:%g", sensor->u.proximity.value); |
| break; |
| case ANDROID_SENSOR_LIGHT: |
| sensor->serialized.length = snprintf( |
| sensor->serialized.value, sizeof(sensor->serialized.value), |
| "light:%g", sensor->u.light.value); |
| break; |
| case ANDROID_SENSOR_PRESSURE: |
| sensor->serialized.length = snprintf( |
| sensor->serialized.value, sizeof(sensor->serialized.value), |
| "pressure:%g", sensor->u.pressure.value); |
| break; |
| case ANDROID_SENSOR_HUMIDITY: |
| sensor->serialized.length = snprintf( |
| sensor->serialized.value, sizeof(sensor->serialized.value), |
| "humidity:%g", sensor->u.humidity.value); |
| break; |
| default: |
| assert(false); // should never happen |
| return; |
| } |
| assert(sensor->serialized.length < sizeof(sensor->serialized.value)); |
| sensor->serialized.valid = true; |
| |
| _hwSensorClient_sanitizeSensorString(sensor->serialized.value, |
| sensor->serialized.length); |
| } |
| |
| /* this function is called periodically to send sensor reports |
| * to the HAL module, and re-arm the timer if necessary |
| */ |
| static void _hwSensorClient_tick(void* opaque, LoopTimer* unused) { |
| HwSensorClient* cl = opaque; |
| int64_t delay_ms = cl->delay_ms; |
| const uint32_t mask = cl->enabledMask; |
| |
| // Grab the guest time before sending any sensor data: |
| // the android.hardware CTS requires sync times to be no greater than the |
| // time of the sensor event arrival. Since the CTS enforces this property, |
| // other code may also rely on it. |
| const DurationNs now_ns = |
| looper_nowNsWithClock(looper_getForThread(), LOOPER_CLOCK_VIRTUAL); |
| |
| AndroidSensor sensor_id; |
| for (sensor_id = 0; sensor_id < MAX_SENSORS; ++sensor_id) { |
| if (!_hwSensorClient_enabled(cl, sensor_id)) { |
| continue; |
| } |
| Sensor* sensor = &cl->sensors->sensors[sensor_id]; |
| if (!sensor->serialized.valid) { |
| serializeSensorValue(sensor, sensor_id); |
| } |
| _hwSensorClient_send(cl, (uint8_t*)sensor->serialized.value, |
| sensor->serialized.length); |
| } |
| |
| char buffer[64]; |
| int buffer_len = |
| snprintf(buffer, sizeof(buffer), "sync:%" PRId64, now_ns / 1000); |
| assert(buffer_len < sizeof(buffer)); |
| _hwSensorClient_send(cl, (uint8_t*)buffer, buffer_len); |
| |
| if (mask == 0) |
| return; |
| |
| // Rearm the timer to fire a little bit early, so we can sustain the |
| // requested frequency. Also make sure we have at least a minimal delay, |
| // otherwise this timer would hijack the main loop thread and won't allow |
| // guest to ever run. |
| // Note: (-1) is needed to account for an overhead of the timer firing on |
| // the host and execution of the tick function. 1ms is enough, as the |
| // overhead is very small; on the other hand, it's always present - that's |
| // why we can't just have (delay_ms) here. |
| // Note2: Let's cap the minimal tick interval to 5ms, to make sure we never |
| // overload the main QEMU loop. Upper limit is just some reasonable value. |
| if (delay_ms < 5) { |
| delay_ms = 5; |
| } else if (delay_ms > 60 * 60 * 1000) { |
| delay_ms = 60 * 60 * 1000; |
| } |
| loopTimer_startRelative(cl->timer, delay_ms - 1); |
| } |
| |
| /* handle incoming messages from the HAL module */ |
| static void _hwSensorClient_receive(HwSensorClient* cl, |
| uint8_t* msg, |
| int msglen) { |
| HwSensors* hw = cl->sensors; |
| |
| D("%s: '%.*s'", __FUNCTION__, msglen, msg); |
| |
| /* "list-sensors" is used to get an integer bit map of |
| * available emulated sensors. We compute the mask from the |
| * current hardware configuration. |
| */ |
| if (msglen == 12 && !memcmp(msg, "list-sensors", 12)) { |
| char buff[12]; |
| int mask = 0; |
| int nn; |
| |
| for (nn = 0; nn < MAX_SENSORS; nn++) { |
| if (hw->sensors[nn].enabled) |
| mask |= (1 << nn); |
| } |
| |
| const int len = snprintf(buff, sizeof buff, "%d", mask); |
| assert(len < sizeof(buff)); |
| _hwSensorClient_send(cl, (const uint8_t*)buff, len); |
| return; |
| } |
| |
| /* "wake" is a special message that must be sent back through |
| * the channel. It is used to exit a blocking read. |
| */ |
| if (msglen == 4 && !memcmp(msg, "wake", 4)) { |
| _hwSensorClient_send(cl, (const uint8_t*)"wake", 4); |
| return; |
| } |
| |
| /* "set-delay:<delay>" is used to set the delay in milliseconds |
| * between sensor events |
| */ |
| if (msglen > 10 && !memcmp(msg, "set-delay:", 10)) { |
| cl->delay_ms = atoi((const char*)msg + 10); |
| if (cl->enabledMask != 0) |
| _hwSensorClient_tick(cl, cl->timer); |
| |
| return; |
| } |
| |
| /* "set:<name>:<state>" is used to enable/disable a given |
| * sensor. <state> must be 0 or 1 |
| */ |
| if (msglen > 4 && !memcmp(msg, "set:", 4)) { |
| char* q; |
| int id, enabled, oldEnabledMask = cl->enabledMask; |
| msg += 4; |
| q = strchr((char*)msg, ':'); |
| if (q == NULL) { /* should not happen */ |
| D("%s: ignore bad 'set' command", __FUNCTION__); |
| return; |
| } |
| *q++ = 0; |
| |
| id = _sensorIdFromName((const char*)msg); |
| if (id < 0 || id >= MAX_SENSORS) { |
| D("%s: ignore unknown sensor name '%s'", __FUNCTION__, msg); |
| return; |
| } |
| |
| if (!hw->sensors[id].enabled) { |
| D("%s: trying to set disabled %s sensor", __FUNCTION__, msg); |
| return; |
| } |
| enabled = (q[0] == '1'); |
| |
| if (enabled) |
| cl->enabledMask |= (1 << id); |
| else |
| cl->enabledMask &= ~(1 << id); |
| |
| if (cl->enabledMask != (uint32_t)oldEnabledMask) { |
| D("%s: %s %s sensor", __FUNCTION__, |
| (cl->enabledMask & (1 << id)) ? "enabling" : "disabling", msg); |
| } |
| |
| /* If emulating device is connected update sensor state there too. */ |
| if (hw->sensors_port != NULL) { |
| if (enabled) { |
| sensors_port_enable_sensor(hw->sensors_port, (const char*)msg); |
| } else { |
| sensors_port_disable_sensor(hw->sensors_port, (const char*)msg); |
| } |
| } |
| |
| _hwSensorClient_tick(cl, cl->timer); |
| return; |
| } |
| |
| D("%s: ignoring unknown query", __FUNCTION__); |
| } |
| |
| /* Saves sensor-specific client data to snapshot */ |
| static void _hwSensorClient_save(Stream* f, QemudClient* client, void* opaque) { |
| HwSensorClient* sc = opaque; |
| |
| stream_put_be32(f, sc->delay_ms); |
| stream_put_be32(f, sc->enabledMask); |
| stream_put_timer(f, sc->timer); |
| } |
| |
| /* Loads sensor-specific client data from snapshot */ |
| static int _hwSensorClient_load(Stream* f, QemudClient* client, void* opaque) { |
| HwSensorClient* sc = opaque; |
| |
| sc->delay_ms = stream_get_be32(f); |
| sc->enabledMask = stream_get_be32(f); |
| stream_get_timer(f, sc->timer); |
| |
| return 0; |
| } |
| |
| static QemudClient* _hwSensors_connect(void* opaque, |
| QemudService* service, |
| int channel, |
| const char* client_param) { |
| HwSensors* sensors = opaque; |
| HwSensorClient* cl = _hwSensorClient_new(sensors); |
| QemudClient* client = qemud_client_new( |
| service, channel, client_param, cl, _hwSensorClient_recv, |
| _hwSensorClient_close, _hwSensorClient_save, _hwSensorClient_load); |
| qemud_client_set_framing(client, 1); |
| cl->client = client; |
| |
| return client; |
| } |
| |
| /* change the value of the emulated sensor vector */ |
| static void _hwSensors_setSensorValue(HwSensors* h, |
| int sensor_id, |
| float a, |
| float b, |
| float c) { |
| Sensor* s = &h->sensors[sensor_id]; |
| |
| if (s->u.value.a != a || s->u.value.b != b || s->u.value.c != c) { |
| s->u.value.a = a; |
| s->u.value.b = b; |
| s->u.value.c = c; |
| s->serialized.valid = false; |
| } |
| } |
| |
| /* Saves available sensors to allow checking availability when loaded. |
| */ |
| static void _hwSensors_save(Stream* f, QemudService* sv, void* opaque) { |
| HwSensors* h = opaque; |
| |
| // number of sensors |
| stream_put_be32(f, MAX_SENSORS); |
| AndroidSensor sensor_id; |
| for (sensor_id = 0; sensor_id < MAX_SENSORS; sensor_id++) { |
| Sensor* s = &h->sensors[sensor_id]; |
| stream_put_be32(f, s->enabled); |
| |
| /* this switch ensures that a warning is raised when a new sensor is |
| * added and is not added here as well. |
| */ |
| switch (sensor_id) { |
| case ANDROID_SENSOR_ACCELERATION: |
| stream_put_float(f, s->u.acceleration.x); |
| stream_put_float(f, s->u.acceleration.y); |
| stream_put_float(f, s->u.acceleration.z); |
| break; |
| case ANDROID_SENSOR_MAGNETIC_FIELD: |
| stream_put_float(f, s->u.magnetic.x); |
| stream_put_float(f, s->u.magnetic.y); |
| stream_put_float(f, s->u.magnetic.z); |
| break; |
| case ANDROID_SENSOR_ORIENTATION: |
| stream_put_float(f, s->u.orientation.azimuth); |
| stream_put_float(f, s->u.orientation.pitch); |
| stream_put_float(f, s->u.orientation.roll); |
| break; |
| case ANDROID_SENSOR_TEMPERATURE: |
| stream_put_float(f, s->u.temperature.celsius); |
| break; |
| case ANDROID_SENSOR_PROXIMITY: |
| stream_put_float(f, s->u.proximity.value); |
| break; |
| case ANDROID_SENSOR_LIGHT: |
| stream_put_float(f, s->u.light.value); |
| break; |
| case ANDROID_SENSOR_PRESSURE: |
| stream_put_float(f, s->u.pressure.value); |
| break; |
| case ANDROID_SENSOR_HUMIDITY: |
| stream_put_float(f, s->u.humidity.value); |
| break; |
| |
| case MAX_SENSORS: |
| break; |
| } |
| } |
| } |
| |
| static int _hwSensors_load(Stream* f, QemudService* s, void* opaque) { |
| HwSensors* h = opaque; |
| |
| /* check number of sensors */ |
| int32_t num_sensors = stream_get_be32(f); |
| if (num_sensors > MAX_SENSORS) { |
| D("%s: cannot load: snapshot requires %d sensors, %d available\n", |
| __FUNCTION__, num_sensors, MAX_SENSORS); |
| return -EIO; |
| } |
| |
| /* load sensor state */ |
| AndroidSensor sensor_id; |
| for (sensor_id = 0; sensor_id < (AndroidSensor)num_sensors; sensor_id++) { |
| Sensor* s = &h->sensors[sensor_id]; |
| s->enabled = stream_get_be32(f); |
| |
| /* this switch ensures that a warning is raised when a new sensor is |
| * added and is not added here as well. |
| */ |
| switch (sensor_id) { |
| case ANDROID_SENSOR_ACCELERATION: |
| s->u.acceleration.x = stream_get_float(f); |
| s->u.acceleration.y = stream_get_float(f); |
| s->u.acceleration.z = stream_get_float(f); |
| break; |
| case ANDROID_SENSOR_MAGNETIC_FIELD: |
| s->u.magnetic.x = stream_get_float(f); |
| s->u.magnetic.y = stream_get_float(f); |
| s->u.magnetic.z = stream_get_float(f); |
| break; |
| case ANDROID_SENSOR_ORIENTATION: |
| s->u.orientation.azimuth = stream_get_float(f); |
| s->u.orientation.pitch = stream_get_float(f); |
| s->u.orientation.roll = stream_get_float(f); |
| break; |
| case ANDROID_SENSOR_TEMPERATURE: |
| s->u.temperature.celsius = stream_get_float(f); |
| break; |
| case ANDROID_SENSOR_PROXIMITY: |
| s->u.proximity.value = stream_get_float(f); |
| break; |
| case ANDROID_SENSOR_LIGHT: |
| s->u.light.value = stream_get_float(f); |
| break; |
| case ANDROID_SENSOR_PRESSURE: |
| s->u.pressure.value = stream_get_float(f); |
| break; |
| case ANDROID_SENSOR_HUMIDITY: |
| s->u.humidity.value = stream_get_float(f); |
| break; |
| case MAX_SENSORS: |
| break; |
| } |
| |
| // Make sure we re-serialize it on the next tick. |
| s->serialized.valid = false; |
| } |
| |
| /* The following is necessary when we resume a snaphost |
| * created by an older version of the emulator that provided |
| * less hardware sensors. |
| */ |
| for (; sensor_id < MAX_SENSORS; sensor_id++) { |
| h->sensors[sensor_id].enabled = false; |
| h->sensors[sensor_id].serialized.valid = false; |
| } |
| |
| return 0; |
| } |
| |
| /* change the emulated proximity */ |
| static void _hwSensors_setProximity(HwSensors* h, float value) { |
| Sensor* s = &h->sensors[ANDROID_SENSOR_PROXIMITY]; |
| if (s->u.proximity.value != value) { |
| s->u.proximity.value = value; |
| s->serialized.valid = false; |
| } |
| } |
| |
| /* change the coarse orientation (landscape/portrait) of the emulated device */ |
| static void _hwSensors_setCoarseOrientation(HwSensors* h, |
| AndroidCoarseOrientation orient) { |
| /* The Android framework computes the orientation by looking at |
| * the accelerometer sensor (*not* the orientation sensor !) |
| * |
| * That's because the gravity is a constant 9.81 vector that |
| * can be determined quite easily. |
| * |
| * Also, for some reason, the framework code considers that the phone should |
| * be inclined by 30 degrees along the phone's X axis to be considered |
| * in its ideal "vertical" position |
| * |
| * If the phone is completely vertical, rotating it will not do anything ! |
| */ |
| const double g = 9.81; |
| const double angle = 20.0; |
| const double cos_angle = cos(angle / M_PI); |
| const double sin_angle = sin(angle / M_PI); |
| |
| if (VERBOSE_CHECK(rotation)) { |
| fprintf(stderr, "setCoarseOrientation - HwSensors %p\n", h); |
| } |
| switch (orient) { |
| case ANDROID_COARSE_PORTRAIT: |
| if (VERBOSE_CHECK(rotation)) { |
| fprintf(stderr, "Setting coarse orientation to portrait\n"); |
| } |
| _hwSensors_setSensorValue(h, ANDROID_SENSOR_ACCELERATION, 0., |
| g * cos_angle, g * sin_angle); |
| break; |
| |
| case ANDROID_COARSE_REVERSE_LANDSCAPE: |
| if (VERBOSE_CHECK(rotation)) { |
| fprintf(stderr, |
| "Setting coarse orientation to reverse landscape\n"); |
| } |
| _hwSensors_setSensorValue(h, ANDROID_SENSOR_ACCELERATION, |
| -g * cos_angle, 0., -g * sin_angle); |
| break; |
| |
| case ANDROID_COARSE_REVERSE_PORTRAIT: |
| if (VERBOSE_CHECK(rotation)) { |
| fprintf(stderr, |
| "Setting coarse orientation to reverse portrait\n"); |
| } |
| _hwSensors_setSensorValue(h, ANDROID_SENSOR_ACCELERATION, 0., |
| -g * cos_angle, -g * sin_angle); |
| break; |
| |
| case ANDROID_COARSE_LANDSCAPE: |
| if (VERBOSE_CHECK(rotation)) { |
| fprintf(stderr, "Setting coarse orientation to landscape\n"); |
| } |
| _hwSensors_setSensorValue(h, ANDROID_SENSOR_ACCELERATION, |
| g * cos_angle, 0., g * sin_angle); |
| break; |
| default: |
| if (VERBOSE_CHECK(rotation)) { |
| fprintf(stderr, "Invalid orientation\n"); |
| } |
| } |
| } |
| |
| /* initialize the sensors state */ |
| static void _hwSensors_init(HwSensors* h) { |
| h->sensors_port = NULL; |
| |
| h->service = qemud_service_register("sensors", 0, h, _hwSensors_connect, |
| _hwSensors_save, _hwSensors_load); |
| |
| if (android_hw->hw_accelerometer) { |
| h->sensors[ANDROID_SENSOR_ACCELERATION].enabled = true; |
| } |
| |
| if (android_hw->hw_sensors_proximity) { |
| h->sensors[ANDROID_SENSOR_PROXIMITY].enabled = true; |
| } |
| |
| if (android_hw->hw_sensors_magnetic_field) { |
| h->sensors[ANDROID_SENSOR_MAGNETIC_FIELD].enabled = true; |
| } |
| |
| if (android_hw->hw_sensors_orientation) { |
| h->sensors[ANDROID_SENSOR_ORIENTATION].enabled = true; |
| } |
| |
| if (android_hw->hw_sensors_temperature) { |
| h->sensors[ANDROID_SENSOR_TEMPERATURE].enabled = true; |
| } |
| |
| if (android_hw->hw_sensors_light) { |
| h->sensors[ANDROID_SENSOR_LIGHT].enabled = true; |
| } |
| |
| if (android_hw->hw_sensors_pressure) { |
| h->sensors[ANDROID_SENSOR_PRESSURE].enabled = true; |
| } |
| |
| if (android_hw->hw_sensors_humidity) { |
| h->sensors[ANDROID_SENSOR_HUMIDITY].enabled = true; |
| } |
| |
| /* XXX: TODO: Add other tests when we add the corresponding |
| * properties to hardware-properties.ini et al. */ |
| |
| _hwSensors_setCoarseOrientation(h, ANDROID_COARSE_PORTRAIT); |
| _hwSensors_setProximity(h, 1); |
| } |
| |
| static HwSensors _sensorsState[1] = {}; |
| |
| void android_hw_sensors_init(void) { |
| HwSensors* hw = _sensorsState; |
| |
| if (hw->service == NULL) { |
| _hwSensors_init(hw); |
| D("%s: sensors qemud service initialized", __FUNCTION__); |
| } |
| } |
| |
| void android_hw_sensors_init_remote_controller(void) { |
| HwSensors* hw = _sensorsState; |
| |
| if (!hw->sensors_port) { |
| /* Try to see if there is a device attached that can be used for |
| * sensor emulation. */ |
| hw->sensors_port = sensors_port_create(hw); |
| if (hw->sensors_port == NULL) { |
| V("Realistic sensor emulation is not available, since the remote " |
| "controller is not accessible:\n %s", |
| strerror(errno)); |
| } |
| } |
| } |
| |
| /* change the coarse orientation value */ |
| extern void android_sensors_set_coarse_orientation( |
| AndroidCoarseOrientation orient) { |
| android_hw_sensors_init(); |
| _hwSensors_setCoarseOrientation(_sensorsState, orient); |
| } |
| |
| /* Get sensor name from sensor id */ |
| extern const char* android_sensors_get_name_from_id(int sensor_id) { |
| if (sensor_id < 0 || sensor_id >= MAX_SENSORS) |
| return NULL; |
| |
| return _sensorNameFromId(sensor_id); |
| } |
| |
| /* Get sensor id from sensor name */ |
| extern int android_sensors_get_id_from_name(char* sensorname) { |
| HwSensors* hw = _sensorsState; |
| |
| if (sensorname == NULL) |
| return SENSOR_STATUS_UNKNOWN; |
| |
| int id = _sensorIdFromName(sensorname); |
| |
| if (id < 0 || id >= MAX_SENSORS) |
| return SENSOR_STATUS_UNKNOWN; |
| |
| if (hw->service != NULL) { |
| if (!hw->sensors[id].enabled) |
| return SENSOR_STATUS_DISABLED; |
| } else |
| return SENSOR_STATUS_NO_SERVICE; |
| |
| return id; |
| } |
| |
| /* Interface of reading the data for all sensors */ |
| extern int android_sensors_get(int sensor_id, float* a, float* b, float* c) { |
| HwSensors* hw = _sensorsState; |
| |
| *a = 0; |
| *b = 0; |
| *c = 0; |
| |
| if (sensor_id < 0 || sensor_id >= MAX_SENSORS) |
| return SENSOR_STATUS_UNKNOWN; |
| |
| Sensor* sensor = &hw->sensors[sensor_id]; |
| if (hw->service != NULL) { |
| if (!sensor->enabled) |
| return SENSOR_STATUS_DISABLED; |
| } else |
| return SENSOR_STATUS_NO_SERVICE; |
| |
| *a = sensor->u.value.a; |
| *b = sensor->u.value.b; |
| *c = sensor->u.value.c; |
| |
| return SENSOR_STATUS_OK; |
| } |
| |
| /* Interface of setting the data for all sensors */ |
| extern int android_sensors_set(int sensor_id, float a, float b, float c) { |
| HwSensors* hw = _sensorsState; |
| |
| if (sensor_id < 0 || sensor_id >= MAX_SENSORS) |
| return SENSOR_STATUS_UNKNOWN; |
| |
| if (hw->service != NULL) { |
| if (!hw->sensors[sensor_id].enabled) |
| return SENSOR_STATUS_DISABLED; |
| } else |
| return SENSOR_STATUS_NO_SERVICE; |
| |
| _hwSensors_setSensorValue(hw, sensor_id, a, b, c); |
| |
| return SENSOR_STATUS_OK; |
| } |
| |
| /* Get Sensor from sensor id */ |
| extern uint8_t android_sensors_get_sensor_status(int sensor_id) { |
| HwSensors* hw = _sensorsState; |
| |
| if (sensor_id < 0 || sensor_id >= MAX_SENSORS) |
| return SENSOR_STATUS_UNKNOWN; |
| |
| return hw->sensors[sensor_id].enabled; |
| } |