blob: 1fa12dc0f42f84c0ff9058ca246f5b6836609c7b [file] [log] [blame]
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001/* Copyright (C) 2009 The Android Open Source Project
2**
3** This software is licensed under the terms of the GNU General Public
4** License version 2, as published by the Free Software Foundation, and
5** may be copied, distributed, and modified under those terms.
6**
7** This program is distributed in the hope that it will be useful,
8** but WITHOUT ANY WARRANTY; without even the implied warranty of
9** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10** GNU General Public License for more details.
11*/
12
13#include "android/hw-sensors.h"
14#include "android/utils/debug.h"
15#include "android/utils/misc.h"
David 'Digit' Turner5998b892009-06-11 14:43:03 +020016#include "android/utils/system.h"
The Android Open Source Project9877e2e2009-03-18 17:39:44 -070017#include "android/hw-qemud.h"
18#include "android/globals.h"
19#include "qemu-char.h"
20#include "qemu-timer.h"
21
22#define D(...) VERBOSE_PRINT(sensors,__VA_ARGS__)
23
24/* define T_ACTIVE to 1 to debug transport communications */
25#define T_ACTIVE 0
26
27#if T_ACTIVE
28#define T(...) VERBOSE_PRINT(sensors,__VA_ARGS__)
29#else
30#define T(...) ((void)0)
31#endif
32
33/* this code supports emulated sensor hardware
34 *
35 * Note that currently, only the accelerometer is really emulated, and only
36 * for the purpose of allowing auto-rotating the screen in keyboard-less
37 * configurations.
38 *
39 *
40 */
41
42
43static const struct {
44 const char* name;
45 int id;
46} _sSensors[MAX_SENSORS] = {
47#define SENSOR_(x,y) { y, ANDROID_SENSOR_##x },
48 SENSORS_LIST
49#undef SENSOR_
50};
51
52
53static int
54_sensorIdFromName( const char* name )
55{
56 int nn;
57 for (nn = 0; nn < MAX_SENSORS; nn++)
58 if (!strcmp(_sSensors[nn].name,name))
59 return _sSensors[nn].id;
60 return -1;
61}
62
63
64typedef struct {
65 float x, y, z;
66} Acceleration;
67
68
69typedef struct {
70 float x, y, z;
71} MagneticField;
72
73
74typedef struct {
75 float azimuth;
76 float pitch;
77 float roll;
78} Orientation;
79
80
81typedef struct {
82 float celsius;
83} Temperature;
84
85
86typedef struct {
87 char enabled;
88 union {
89 Acceleration acceleration;
90 MagneticField magnetic;
91 Orientation orientation;
92 Temperature temperature;
93 } u;
94} Sensor;
95
96/*
97 * - when the qemu-specific sensors HAL module starts, it sends
98 * "list-sensors"
99 *
100 * - this code replies with a string containing an integer corresponding
101 * to a bitmap of available hardware sensors in the current AVD
102 * configuration (e.g. "1" a.k.a (1 << ANDROID_SENSOR_ACCELERATION))
103 *
104 * - the HAL module sends "set:<sensor>:<flag>" to enable or disable
105 * the report of a given sensor state. <sensor> must be the name of
106 * a given sensor (e.g. "accelerometer"), and <flag> must be either
107 * "1" (to enable) or "0" (to disable).
108 *
109 * - Once at least one sensor is "enabled", this code should periodically
110 * send information about the corresponding enabled sensors. The default
111 * period is 200ms.
112 *
113 * - the HAL module sends "set-delay:<delay>", where <delay> is an integer
114 * corresponding to a time delay in milli-seconds. This corresponds to
115 * a new interval between sensor events sent by this code to the HAL
116 * module.
117 *
118 * - the HAL module can also send a "wake" command. This code should simply
119 * send the "wake" back to the module. This is used internally to wake a
120 * blocking read that happens in a different thread. This ping-pong makes
121 * the code in the HAL module very simple.
122 *
123 * - each timer tick, this code sends sensor reports in the following
124 * format (each line corresponds to a different line sent to the module):
125 *
126 * acceleration:<x>:<y>:<z>
127 * magnetic-field:<x>:<y>:<z>
128 * orientation:<azimuth>:<pitch>:<roll>
129 * temperature:<celsius>
130 * sync:<time_us>
131 *
132 * Where each line before the sync:<time_us> is optional and will only
133 * appear if the corresponding sensor has been enabled by the HAL module.
134 *
135 * Note that <time_us> is the VM time in micro-seconds when the report
136 * was "taken" by this code. This is adjusted by the HAL module to
137 * emulated system time (using the first sync: to compute an adjustment
138 * offset).
139 */
140#define HEADER_SIZE 4
141#define BUFFER_SIZE 512
142
David 'Digit' Turner5998b892009-06-11 14:43:03 +0200143typedef struct HwSensorClient HwSensorClient;
144
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700145typedef struct {
David 'Digit' Turner5998b892009-06-11 14:43:03 +0200146 QemudService* service;
147 Sensor sensors[MAX_SENSORS];
148 HwSensorClient* clients;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700149} HwSensors;
150
David 'Digit' Turner5998b892009-06-11 14:43:03 +0200151struct HwSensorClient {
152 HwSensorClient* next;
153 HwSensors* sensors;
154 QemudClient* client;
155 QEMUTimer* timer;
156 uint32_t enabledMask;
157 int32_t delay_ms;
158};
159
160static void
161_hwSensorClient_free( HwSensorClient* cl )
162{
163 /* remove from sensors's list */
164 if (cl->sensors) {
165 HwSensorClient** pnode = &cl->sensors->clients;
166 for (;;) {
167 HwSensorClient* node = *pnode;
168 if (node == NULL)
169 break;
170 if (node == cl) {
171 *pnode = cl->next;
172 break;
173 }
174 pnode = &node->next;
175 }
176 cl->next = NULL;
177 cl->sensors = NULL;
178 }
179
180 /* close QEMUD client, if any */
181 if (cl->client) {
182 qemud_client_close(cl->client);
183 cl->client = NULL;
184 }
185 /* remove timer, if any */
186 if (cl->timer) {
187 qemu_del_timer(cl->timer);
188 qemu_free_timer(cl->timer);
189 cl->timer = NULL;
190 }
191 AFREE(cl);
192}
193
194/* forward */
195static void _hwSensorClient_tick(void* opaque);
196
197
198static HwSensorClient*
199_hwSensorClient_new( HwSensors* sensors )
200{
201 HwSensorClient* cl;
202
203 ANEW0(cl);
204
205 cl->sensors = sensors;
206 cl->enabledMask = 0;
207 cl->delay_ms = 1000;
208 cl->timer = qemu_new_timer(vm_clock, _hwSensorClient_tick, cl);
209
210 cl->next = sensors->clients;
211 sensors->clients = cl;
212
213 return cl;
214}
215
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700216/* forward */
217
David 'Digit' Turner5998b892009-06-11 14:43:03 +0200218static void _hwSensorClient_receive( HwSensorClient* cl,
219 uint8_t* query,
220 int querylen );
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700221
222/* Qemud service management */
223
224static void
David 'Digit' Turner5998b892009-06-11 14:43:03 +0200225_hwSensorClient_recv( void* opaque, uint8_t* msg, int msglen,
226 QemudClient* client )
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700227{
David 'Digit' Turner5998b892009-06-11 14:43:03 +0200228 HwSensorClient* cl = opaque;
229
230 _hwSensorClient_receive(cl, msg, msglen);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700231}
232
David 'Digit' Turner5998b892009-06-11 14:43:03 +0200233static void
234_hwSensorClient_close( void* opaque )
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700235{
David 'Digit' Turner5998b892009-06-11 14:43:03 +0200236 HwSensorClient* cl = opaque;
237
238 /* the client is already closed here */
239 cl->client = NULL;
240 _hwSensorClient_free(cl);
241}
242
243/* send a one-line message to the HAL module through a qemud channel */
244static void
245_hwSensorClient_send( HwSensorClient* cl, const uint8_t* msg, int msglen )
246{
247 D("%s: '%s'", __FUNCTION__, quote_bytes((const void*)msg, msglen));
248 qemud_client_send(cl->client, msg, msglen);
249}
250
251static int
252_hwSensorClient_enabled( HwSensorClient* cl, int sensorId )
253{
254 return (cl->enabledMask & (1 << sensorId)) != 0;
255}
256
257/* this function is called periodically to send sensor reports
258 * to the HAL module, and re-arm the timer if necessary
259 */
260static void
261_hwSensorClient_tick( void* opaque )
262{
263 HwSensorClient* cl = opaque;
264 HwSensors* hw = cl->sensors;
265 int64_t delay = cl->delay_ms;
266 int64_t now_ns;
267 uint32_t mask = cl->enabledMask;
268 Sensor* sensor;
269 char buffer[128];
270
271 if (_hwSensorClient_enabled(cl, ANDROID_SENSOR_ACCELERATION)) {
272 sensor = &hw->sensors[ANDROID_SENSOR_ACCELERATION];
273 snprintf(buffer, sizeof buffer, "acceleration:%g:%g:%g",
274 sensor->u.acceleration.x,
275 sensor->u.acceleration.y,
276 sensor->u.acceleration.z);
277 _hwSensorClient_send(cl, (uint8_t*)buffer, strlen(buffer));
278 }
279
280 if (_hwSensorClient_enabled(cl, ANDROID_SENSOR_MAGNETIC_FIELD)) {
281 sensor = &hw->sensors[ANDROID_SENSOR_MAGNETIC_FIELD];
282 snprintf(buffer, sizeof buffer, "magnetic-field:%g:%g:%g",
283 sensor->u.magnetic.x,
284 sensor->u.magnetic.y,
285 sensor->u.magnetic.z);
286 _hwSensorClient_send(cl, (uint8_t*)buffer, strlen(buffer));
287 }
288
289 if (_hwSensorClient_enabled(cl, ANDROID_SENSOR_ORIENTATION)) {
290 sensor = &hw->sensors[ANDROID_SENSOR_ORIENTATION];
291 snprintf(buffer, sizeof buffer, "orientation:%g:%g:%g",
292 sensor->u.orientation.azimuth,
293 sensor->u.orientation.pitch,
294 sensor->u.orientation.roll);
295 _hwSensorClient_send(cl, (uint8_t*)buffer, strlen(buffer));
296 }
297
298 if (_hwSensorClient_enabled(cl, ANDROID_SENSOR_TEMPERATURE)) {
299 sensor = &hw->sensors[ANDROID_SENSOR_TEMPERATURE];
300 snprintf(buffer, sizeof buffer, "temperature:%g",
301 sensor->u.temperature.celsius);
302 _hwSensorClient_send(cl, (uint8_t*)buffer, strlen(buffer));
303 }
304
305 now_ns = qemu_get_clock(vm_clock);
306
307 snprintf(buffer, sizeof buffer, "sync:%lld", now_ns/1000);
308 _hwSensorClient_send(cl, (uint8_t*)buffer, strlen(buffer));
309
310 /* rearm timer, use a minimum delay of 20 ms, just to
311 * be safe.
312 */
313 if (mask == 0)
314 return;
315
316 if (delay < 20)
317 delay = 20;
318
319 delay *= 1000000LL; /* convert to nanoseconds */
320 qemu_mod_timer(cl->timer, now_ns + delay);
321}
322
323/* handle incoming messages from the HAL module */
324static void
325_hwSensorClient_receive( HwSensorClient* cl, uint8_t* msg, int msglen )
326{
327 HwSensors* hw = cl->sensors;
328
329 D("%s: '%.*s'", __FUNCTION__, msglen, msg);
330
331 /* "list-sensors" is used to get an integer bit map of
332 * available emulated sensors. We compute the mask from the
333 * current hardware configuration.
334 */
335 if (msglen == 12 && !memcmp(msg, "list-sensors", 12)) {
336 char buff[12];
337 int mask = 0;
338 int nn;
339
340 for (nn = 0; nn < MAX_SENSORS; nn++) {
341 if (hw->sensors[nn].enabled)
342 mask |= (1 << nn);
343 }
344
345 snprintf(buff, sizeof buff, "%d", mask);
346 _hwSensorClient_send(cl, (const uint8_t*)buff, strlen(buff));
347 return;
348 }
349
350 /* "wake" is a special message that must be sent back through
351 * the channel. It is used to exit a blocking read.
352 */
353 if (msglen == 4 && !memcmp(msg, "wake", 4)) {
354 _hwSensorClient_send(cl, (const uint8_t*)"wake", 4);
355 return;
356 }
357
358 /* "set-delay:<delay>" is used to set the delay in milliseconds
359 * between sensor events
360 */
361 if (msglen > 10 && !memcmp(msg, "set-delay:", 10)) {
362 cl->delay_ms = atoi((const char*)msg+10);
363 if (cl->enabledMask != 0)
364 _hwSensorClient_tick(cl);
365
366 return;
367 }
368
369 /* "set:<name>:<state>" is used to enable/disable a given
370 * sensor. <state> must be 0 or 1
371 */
372 if (msglen > 4 && !memcmp(msg, "set:", 4)) {
373 char* q;
374 int id, enabled, oldEnabledMask = cl->enabledMask;
375 msg += 4;
376 q = strchr((char*)msg, ':');
377 if (q == NULL) { /* should not happen */
378 D("%s: ignore bad 'set' command", __FUNCTION__);
379 return;
380 }
381 *q++ = 0;
382
383 id = _sensorIdFromName((const char*)msg);
384 if (id < 0 || id >= MAX_SENSORS) {
385 D("%s: ignore unknown sensor name '%s'", __FUNCTION__, msg);
386 return;
387 }
388
389 if (!hw->sensors[id].enabled) {
390 D("%s: trying to set disabled %s sensor", __FUNCTION__, msg);
391 return;
392 }
393 enabled = (q[0] == '1');
394
395 if (enabled)
396 cl->enabledMask |= (1 << id);
397 else
398 cl->enabledMask &= ~(1 << id);
399
400 if (cl->enabledMask != oldEnabledMask) {
401 D("%s: %s %s sensor", __FUNCTION__,
402 (cl->enabledMask & (1 << id)) ? "enabling" : "disabling", msg);
403 }
404 _hwSensorClient_tick(cl);
405 return;
406 }
407
408 D("%s: ignoring unknown query", __FUNCTION__);
409}
410
411
412static QemudClient*
413_hwSensors_connect( void* opaque, QemudService* service, int channel )
414{
415 HwSensors* sensors = opaque;
416 HwSensorClient* cl = _hwSensorClient_new(sensors);
417 QemudClient* client = qemud_client_new(service, channel, cl,
418 _hwSensorClient_recv,
419 _hwSensorClient_close);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700420 qemud_client_set_framing(client, 1);
David 'Digit' Turner5998b892009-06-11 14:43:03 +0200421 cl->client = client;
422
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700423 return client;
424}
425
426/* change the value of the emulated acceleration vector */
427static void
David 'Digit' Turner5998b892009-06-11 14:43:03 +0200428_hwSensors_setAcceleration( HwSensors* h, float x, float y, float z )
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700429{
430 Sensor* s = &h->sensors[ANDROID_SENSOR_ACCELERATION];
431 s->u.acceleration.x = x;
432 s->u.acceleration.y = y;
433 s->u.acceleration.z = z;
434}
435
436#if 0 /* not used yet */
437/* change the value of the emulated magnetic vector */
438static void
David 'Digit' Turner5998b892009-06-11 14:43:03 +0200439_hwSensors_setMagneticField( HwSensors* h, float x, float y, float z )
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700440{
441 Sensor* s = &h->sensors[ANDROID_SENSOR_MAGNETIC_FIELD];
442 s->u.magnetic.x = x;
443 s->u.magnetic.y = y;
444 s->u.magnetic.z = z;
445}
446
447/* change the values of the emulated orientation */
448static void
David 'Digit' Turner5998b892009-06-11 14:43:03 +0200449_hwSensors_setOrientation( HwSensors* h, float azimuth, float pitch, float roll )
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700450{
David 'Digit' Turner5998b892009-06-11 14:43:03 +0200451 Sensor* s = &h->sensors[ANDROID_SENSOR_ORIENTATION];
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700452 s->u.orientation.azimuth = azimuth;
453 s->u.orientation.pitch = pitch;
454 s->u.orientation.roll = roll;
455}
456
457/* change the emulated temperature */
458static void
David 'Digit' Turner5998b892009-06-11 14:43:03 +0200459_hwSensors_setTemperature( HwSensors* h, float celsius )
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700460{
David 'Digit' Turner5998b892009-06-11 14:43:03 +0200461 Sensor* s = &h->sensors[ANDROID_SENSOR_TEMPERATURE];
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700462 s->u.temperature.celsius = celsius;
463}
464#endif
465
466/* change the coarse orientation (landscape/portrait) of the emulated device */
467static void
David 'Digit' Turner5998b892009-06-11 14:43:03 +0200468_hwSensors_setCoarseOrientation( HwSensors* h, AndroidCoarseOrientation orient )
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700469{
470 /* The Android framework computes the orientation by looking at
471 * the accelerometer sensor (*not* the orientation sensor !)
472 *
473 * That's because the gravity is a constant 9.81 vector that
474 * can be determined quite easily.
475 *
476 * Also, for some reason, the framework code considers that the phone should
477 * be inclined by 30 degrees along the phone's X axis to be considered
478 * in its ideal "vertical" position
479 *
480 * If the phone is completely vertical, rotating it will not do anything !
481 */
482 const double g = 9.81;
483 const double cos_30 = 0.866025403784;
484 const double sin_30 = 0.5;
485
486 switch (orient) {
487 case ANDROID_COARSE_PORTRAIT:
David 'Digit' Turner5998b892009-06-11 14:43:03 +0200488 _hwSensors_setAcceleration( h, 0., g*cos_30, g*sin_30 );
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700489 break;
490
491 case ANDROID_COARSE_LANDSCAPE:
David 'Digit' Turner5998b892009-06-11 14:43:03 +0200492 _hwSensors_setAcceleration( h, g*cos_30, 0., g*sin_30 );
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700493 break;
494 default:
495 ;
496 }
497}
498
499
500/* initialize the sensors state */
501static void
David 'Digit' Turner5998b892009-06-11 14:43:03 +0200502_hwSensors_init( HwSensors* h )
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700503{
David 'Digit' Turner5998b892009-06-11 14:43:03 +0200504 h->service = qemud_service_register("sensors", 0, h,
505 _hwSensors_connect );
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700506
David 'Digit' Turner5998b892009-06-11 14:43:03 +0200507 if (android_hw->hw_accelerometer)
508 h->sensors[ANDROID_SENSOR_ACCELERATION].enabled = 1;
509
510 /* XXX: TODO: Add other tests when we add the corresponding
511 * properties to hardware-properties.ini et al. */
512
513 _hwSensors_setCoarseOrientation(h, ANDROID_COARSE_PORTRAIT);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700514}
515
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700516static HwSensors _sensorsState[1];
517
518void
519android_hw_sensors_init( void )
520{
521 HwSensors* hw = _sensorsState;
522
523 if (hw->service == NULL) {
David 'Digit' Turner5998b892009-06-11 14:43:03 +0200524 _hwSensors_init(hw);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700525 D("%s: sensors qemud service initialized", __FUNCTION__);
526 }
527}
528
529/* change the coarse orientation value */
530extern void
531android_sensors_set_coarse_orientation( AndroidCoarseOrientation orient )
532{
533 android_hw_sensors_init();
David 'Digit' Turner5998b892009-06-11 14:43:03 +0200534 _hwSensors_setCoarseOrientation(_sensorsState, orient);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700535}
536