| Vladimir Chtchetkine | db611d5 | 2011-11-01 17:35:07 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2011 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include "android/sensors-port.h" |
| 18 | #include "android/hw-sensors.h" |
| 19 | |
| 20 | #define E(...) derror(__VA_ARGS__) |
| 21 | #define W(...) dwarning(__VA_ARGS__) |
| 22 | #define D(...) VERBOSE_PRINT(sensors_port,__VA_ARGS__) |
| 23 | #define D_ACTIVE VERBOSE_CHECK(camera) |
| 24 | |
| 25 | /* Maximum number of sensors supported. */ |
| 26 | #define ASP_MAX_SENSOR 12 |
| 27 | |
| 28 | /* Maximum length of a sensor message. */ |
| 29 | #define ASP_MAX_SENSOR_MSG 1024 |
| 30 | |
| 31 | /* Maximum length of a sensor event. */ |
| 32 | #define ASP_MAX_SENSOR_EVENT 256 |
| 33 | |
| 34 | /* Query timeout in milliseconds. */ |
| 35 | #define ASP_QUERY_TIMEOUT 3000 |
| 36 | |
| 37 | /* Sensors port descriptor. */ |
| 38 | struct AndroidSensorsPort { |
| 39 | /* Caller identifier. */ |
| 40 | void* opaque; |
| 41 | /* Connected android device. */ |
| 42 | AndroidDevice* device; |
| 43 | /* String containing list of all available sensors. */ |
| 44 | char sensors[ASP_MAX_SENSOR * 64]; |
| 45 | /* Array of available sensor names. Note that each string in this array |
| 46 | * points inside the 'sensors' buffer. */ |
| 47 | const char* sensor_list[ASP_MAX_SENSOR]; |
| 48 | /* Number of available sensors. */ |
| 49 | int sensors_num; |
| 50 | /* Connection status: 1 connected, 0 - disconnected. */ |
| 51 | int is_connected; |
| 52 | /* Buffer where to receive sensor messages. */ |
| 53 | char sensor_msg[ASP_MAX_SENSOR_MSG]; |
| 54 | /* Buffer where to receive sensor events. */ |
| 55 | char events[ASP_MAX_SENSOR_EVENT]; |
| 56 | }; |
| 57 | |
| 58 | /* Destroys and frees the descriptor. */ |
| 59 | static void |
| 60 | _sensors_port_free(AndroidSensorsPort* asp) |
| 61 | { |
| 62 | if (asp != NULL) { |
| 63 | if (asp->device != NULL) { |
| 64 | android_device_destroy(asp->device); |
| 65 | } |
| 66 | AFREE(asp); |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | /******************************************************************************** |
| 71 | * Sensors port callbacks |
| 72 | *******************************************************************************/ |
| 73 | |
| 74 | /* A callback that invoked on sensor events. |
| 75 | * Param: |
| 76 | * opaque - AndroidSensorsPort instance. |
| 77 | * ad - Android device used by this sensors port. |
| 78 | * msg, msgsize - Sensor event message |
| 79 | * failure - Message receiving status. |
| 80 | */ |
| 81 | static void |
| 82 | _on_sensor_received(void* opaque, AndroidDevice* ad, char* msg, int msgsize) |
| 83 | { |
| 84 | float fvalues[3] = {0, 0, 0}; |
| 85 | char sensor[ASP_MAX_SENSOR_MSG]; |
| 86 | char* value; |
| 87 | int id; |
| 88 | AndroidSensorsPort* asp = (AndroidSensorsPort*)opaque; |
| 89 | |
| 90 | if (errno) { |
| 91 | D("Sensors notification has failed on sensors port: %s", strerror(errno)); |
| 92 | return; |
| 93 | } |
| 94 | |
| 95 | /* Parse notification, separating sensor name from parameters. */ |
| 96 | memcpy(sensor, msg, msgsize); |
| 97 | value = strchr(sensor, ':'); |
| 98 | if (value == NULL) { |
| 99 | W("Bad format for sensor notification: %s", msg); |
| 100 | return; |
| 101 | } |
| 102 | sensor[value-sensor] = '\0'; |
| 103 | value++; |
| 104 | |
| 105 | id = android_sensors_get_id_from_name(sensor); |
| 106 | if (id >= 0) { |
| 107 | /* Parse the value part to get the sensor values(a, b, c) */ |
| 108 | int i; |
| 109 | char* pnext; |
| 110 | char* pend = value + strlen(value); |
| 111 | for (i = 0; i < 3; i++, value = pnext + 1) { |
| 112 | pnext=strchr( value, ':' ); |
| 113 | if (pnext) { |
| 114 | *pnext = 0; |
| 115 | } else { |
| 116 | pnext = pend; |
| 117 | } |
| 118 | |
| 119 | if (pnext > value) { |
| 120 | if (1 != sscanf( value,"%g", &fvalues[i] )) { |
| 121 | W("Bad parameters in sensor notification %s", msg); |
| 122 | return; |
| 123 | } |
| 124 | } |
| 125 | } |
| 126 | android_sensors_set(id, fvalues[0], fvalues[1], fvalues[2]); |
| 127 | } else { |
| 128 | W("Unknown sensor name '%s' in '%s'", sensor, msg); |
| 129 | } |
| 130 | |
| 131 | /* Listen to the next event. */ |
| 132 | android_device_listen(ad, asp->events, sizeof(asp->events), _on_sensor_received); |
| 133 | } |
| 134 | |
| 135 | /* A callback that is invoked when android device is connected (i.e. both, command |
| 136 | * and event channels have been stablished. |
| 137 | * Param: |
| 138 | * opaque - AndroidSensorsPort instance. |
| 139 | * ad - Android device used by this sensors port. |
| 140 | * failure - Connections status. |
| 141 | */ |
| 142 | static void |
| 143 | _on_device_connected(void* opaque, AndroidDevice* ad, int failure) |
| 144 | { |
| 145 | if (!failure) { |
| 146 | AndroidSensorsPort* asp = (AndroidSensorsPort*)opaque; |
| 147 | asp->is_connected = 1; |
| 148 | D("Sensor emulation has started"); |
| 149 | /* Initialize sensors on device. */ |
| 150 | sensors_port_init_sensors(asp); |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | /* Invoked when an I/O failure occurs on a socket. |
| 155 | * Note that this callback will not be invoked on connection failures. |
| 156 | * Param: |
| 157 | * opaque - AndroidSensorsPort instance. |
| 158 | * ad - Android device instance |
| 159 | * ads - Connection socket where failure has occured. |
| 160 | * failure - Contains 'errno' indicating the reason for failure. |
| 161 | */ |
| 162 | static void |
| 163 | _on_io_failure(void* opaque, AndroidDevice* ad, int failure) |
| 164 | { |
| 165 | AndroidSensorsPort* asp = (AndroidSensorsPort*)opaque; |
| 166 | E("Sensors port got disconnected: %s", strerror(failure)); |
| 167 | asp->is_connected = false; |
| 168 | android_device_disconnect(ad); |
| 169 | android_device_connect_async(ad, _on_device_connected); |
| 170 | } |
| 171 | |
| 172 | /******************************************************************************** |
| 173 | * Sensors port API |
| 174 | *******************************************************************************/ |
| 175 | |
| 176 | AndroidSensorsPort* |
| 177 | sensors_port_create(void* opaque) |
| 178 | { |
| 179 | AndroidSensorsPort* asp; |
| 180 | char* wrk; |
| 181 | int res; |
| 182 | |
| 183 | ANEW0(asp); |
| 184 | asp->opaque = opaque; |
| 185 | asp->is_connected = 0; |
| 186 | |
| 187 | asp->device = android_device_init(asp, AD_SENSOR_PORT, _on_io_failure); |
| 188 | if (asp->device == NULL) { |
| 189 | _sensors_port_free(asp); |
| 190 | return NULL; |
| 191 | } |
| 192 | |
| 193 | res = android_device_connect_sync(asp->device, ASP_QUERY_TIMEOUT); |
| 194 | if (res != 0) { |
| 195 | sensors_port_destroy(asp); |
| 196 | return NULL; |
| 197 | } |
| 198 | |
| 199 | res = android_device_query(asp->device, "list", |
| 200 | asp->sensors, sizeof(asp->sensors), |
| 201 | ASP_QUERY_TIMEOUT); |
| 202 | if (res != 0) { |
| 203 | sensors_port_destroy(asp); |
| 204 | return NULL; |
| 205 | } |
| 206 | |
| 207 | /* Parse sensor list. */ |
| 208 | asp->sensors_num = 0; |
| 209 | wrk = asp->sensors; |
| 210 | |
| 211 | while (wrk != NULL && *wrk != '\0' && *wrk != '\n') { |
| 212 | asp->sensor_list[asp->sensors_num] = wrk; |
| 213 | asp->sensors_num++; |
| 214 | wrk = strchr(wrk, '\n'); |
| 215 | if (wrk != NULL) { |
| 216 | *wrk = '\0'; wrk++; |
| 217 | } |
| 218 | } |
| 219 | |
| 220 | android_device_listen(asp->device, asp->events, sizeof(asp->events), |
| 221 | _on_sensor_received); |
| 222 | return asp; |
| 223 | } |
| 224 | |
| 225 | int |
| 226 | sensors_port_init_sensors(AndroidSensorsPort* asp) |
| 227 | { |
| 228 | int res, id; |
| 229 | |
| 230 | /* Disable all sensors for now. Reenable only those that are emulated. */ |
| 231 | res = sensors_port_disable_sensor(asp, "all"); |
| 232 | if (res) { |
| 233 | return res; |
| 234 | } |
| 235 | |
| 236 | /* Start listening on sensor events. */ |
| 237 | res = android_device_listen(asp->device, asp->events, sizeof(asp->events), |
| 238 | _on_sensor_received); |
| 239 | if (res) { |
| 240 | return res; |
| 241 | } |
| 242 | |
| 243 | /* Walk throuh the list of enabled sensors enabling them on the device. */ |
| 244 | for (id = 0; id < MAX_SENSORS; id++) { |
| 245 | if (android_sensors_get_sensor_status(id) == 1) { |
| 246 | res = sensors_port_enable_sensor(asp, android_sensors_get_name_from_id(id)); |
| 247 | if (res == 0) { |
| 248 | D("Sensor '%s' is enabled on the device.", |
| 249 | android_sensors_get_name_from_id(id)); |
| 250 | } |
| 251 | } |
| 252 | } |
| 253 | |
| 254 | /* Start sensor events. */ |
| 255 | return sensors_port_start(asp); |
| 256 | } |
| 257 | |
| 258 | void |
| 259 | sensors_port_destroy(AndroidSensorsPort* asp) |
| 260 | { |
| 261 | _sensors_port_free(asp); |
| 262 | } |
| 263 | |
| 264 | int |
| 265 | sensors_port_is_connected(AndroidSensorsPort* asp) |
| 266 | { |
| 267 | return asp->is_connected; |
| 268 | } |
| 269 | |
| 270 | int |
| 271 | sensors_port_enable_sensor(AndroidSensorsPort* asp, const char* name) |
| 272 | { |
| 273 | char query[1024]; |
| 274 | char qresp[1024]; |
| 275 | snprintf(query, sizeof(query), "enable:%s", name); |
| 276 | const int res = |
| 277 | android_device_query(asp->device, query, qresp, sizeof(qresp), |
| 278 | ASP_QUERY_TIMEOUT); |
| 279 | if (res) { |
| 280 | if (errno) { |
| 281 | D("Query '%s' failed on I/O: %s", query, strerror(errno)); |
| 282 | } else { |
| 283 | D("Query '%s' failed on device: %s", query, qresp); |
| 284 | } |
| 285 | } |
| 286 | return res; |
| 287 | } |
| 288 | |
| 289 | int |
| 290 | sensors_port_disable_sensor(AndroidSensorsPort* asp, const char* name) |
| 291 | { |
| 292 | char query[1024]; |
| 293 | char qresp[1024]; |
| 294 | snprintf(query, sizeof(query), "disable:%s", name); |
| 295 | const int res = |
| 296 | android_device_query(asp->device, query, qresp, sizeof(qresp), |
| 297 | ASP_QUERY_TIMEOUT); |
| 298 | if (res) { |
| 299 | if (errno) { |
| 300 | D("Query '%s' failed on I/O: %s", query, strerror(errno)); |
| 301 | } else { |
| 302 | D("Query '%s' failed on device: %s", query, qresp); |
| 303 | } |
| 304 | } |
| 305 | return res; |
| 306 | } |
| 307 | |
| 308 | int |
| 309 | sensors_port_start(AndroidSensorsPort* asp) |
| 310 | { |
| 311 | char qresp[ASP_MAX_SENSOR_MSG]; |
| 312 | const int res = |
| 313 | android_device_query(asp->device, "start", qresp, sizeof(qresp), |
| 314 | ASP_QUERY_TIMEOUT); |
| 315 | if (res) { |
| 316 | if (errno) { |
| 317 | D("Query 'start' failed on I/O: %s", strerror(errno)); |
| 318 | } else { |
| 319 | D("Query 'start' failed on device: %s", qresp); |
| 320 | } |
| 321 | } |
| 322 | return res; |
| 323 | } |
| 324 | |
| 325 | int |
| 326 | sensors_port_stop(AndroidSensorsPort* asp) |
| 327 | { |
| 328 | char qresp[ASP_MAX_SENSOR_MSG]; |
| 329 | const int res = |
| 330 | android_device_query(asp->device, "stop", qresp, sizeof(qresp), |
| 331 | ASP_QUERY_TIMEOUT); |
| 332 | if (res) { |
| 333 | if (errno) { |
| 334 | D("Query 'stop' failed on I/O: %s", strerror(errno)); |
| 335 | } else { |
| 336 | D("Query 'stop' failed on device: %s", qresp); |
| 337 | } |
| 338 | } |
| 339 | |
| 340 | return res; |
| 341 | } |