blob: 9e9351d9974e5f4ced169df49832af37d54ea227 [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "android/sensors-port.h"
#include "android/hw-sensors.h"
#define E(...) derror(__VA_ARGS__)
#define W(...) dwarning(__VA_ARGS__)
#define D(...) VERBOSE_PRINT(sensors_port,__VA_ARGS__)
#define D_ACTIVE VERBOSE_CHECK(sensors_port)
/* Maximum number of sensors supported. */
#define ASP_MAX_SENSOR 12
/* Maximum length of a sensor message. */
#define ASP_MAX_SENSOR_MSG 1024
/* Maximum length of a sensor event. */
#define ASP_MAX_SENSOR_EVENT 256
/* Query timeout in milliseconds. */
#define ASP_QUERY_TIMEOUT 3000
/* Sensors port descriptor. */
struct AndroidSensorsPort {
/* Caller identifier. */
void* opaque;
/* Connected android device. */
AndroidDevice* device;
/* String containing list of all available sensors. */
char sensors[ASP_MAX_SENSOR * 64];
/* Array of available sensor names. Note that each string in this array
* points inside the 'sensors' buffer. */
const char* sensor_list[ASP_MAX_SENSOR];
/* Number of available sensors. */
int sensors_num;
/* Connection status: 1 connected, 0 - disconnected. */
int is_connected;
/* Buffer where to receive sensor messages. */
char sensor_msg[ASP_MAX_SENSOR_MSG];
/* Buffer where to receive sensor events. */
char events[ASP_MAX_SENSOR_EVENT];
};
/* Destroys and frees the descriptor. */
static void
_sensors_port_free(AndroidSensorsPort* asp)
{
if (asp != NULL) {
if (asp->device != NULL) {
android_device_destroy(asp->device);
}
AFREE(asp);
}
}
/********************************************************************************
* Sensors port callbacks
*******************************************************************************/
/* A callback that invoked on sensor events.
* Param:
* opaque - AndroidSensorsPort instance.
* ad - Android device used by this sensors port.
* msg, msgsize - Sensor event message
* failure - Message receiving status.
*/
static void
_on_sensor_received(void* opaque, AndroidDevice* ad, char* msg, int msgsize)
{
float fvalues[3] = {0, 0, 0};
char sensor[ASP_MAX_SENSOR_MSG];
char* value;
int id;
AndroidSensorsPort* asp = (AndroidSensorsPort*)opaque;
if (errno) {
D("Sensors notification has failed on sensors port: %s", strerror(errno));
return;
}
/* Parse notification, separating sensor name from parameters. */
memcpy(sensor, msg, msgsize);
value = strchr(sensor, ':');
if (value == NULL) {
W("Bad format for sensor notification: %s", msg);
return;
}
sensor[value-sensor] = '\0';
value++;
id = android_sensors_get_id_from_name(sensor);
if (id >= 0) {
/* Parse the value part to get the sensor values(a, b, c) */
int i;
char* pnext;
char* pend = value + strlen(value);
for (i = 0; i < 3; i++, value = pnext + 1) {
pnext=strchr( value, ':' );
if (pnext) {
*pnext = 0;
} else {
pnext = pend;
}
if (pnext > value) {
if (1 != sscanf( value,"%g", &fvalues[i] )) {
W("Bad parameters in sensor notification %s", msg);
return;
}
}
}
android_sensors_set(id, fvalues[0], fvalues[1], fvalues[2]);
} else {
W("Unknown sensor name '%s' in '%s'", sensor, msg);
}
/* Listen to the next event. */
android_device_listen(ad, asp->events, sizeof(asp->events), _on_sensor_received);
}
/* A callback that is invoked when android device is connected (i.e. both, command
* and event channels have been stablished.
* Param:
* opaque - AndroidSensorsPort instance.
* ad - Android device used by this sensors port.
* failure - Connections status.
*/
static void
_on_device_connected(void* opaque, AndroidDevice* ad, int failure)
{
if (!failure) {
AndroidSensorsPort* asp = (AndroidSensorsPort*)opaque;
asp->is_connected = 1;
D("Sensor emulation has started");
/* Initialize sensors on device. */
sensors_port_init_sensors(asp);
}
}
/* Invoked when an I/O failure occurs on a socket.
* Note that this callback will not be invoked on connection failures.
* Param:
* opaque - AndroidSensorsPort instance.
* ad - Android device instance
* ads - Connection socket where failure has occured.
* failure - Contains 'errno' indicating the reason for failure.
*/
static void
_on_io_failure(void* opaque, AndroidDevice* ad, int failure)
{
AndroidSensorsPort* asp = (AndroidSensorsPort*)opaque;
E("Sensors port got disconnected: %s", strerror(failure));
asp->is_connected = false;
android_device_disconnect(ad);
android_device_connect_async(ad, _on_device_connected);
}
/********************************************************************************
* Sensors port API
*******************************************************************************/
AndroidSensorsPort*
sensors_port_create(void* opaque)
{
AndroidSensorsPort* asp;
char* wrk;
int res;
ANEW0(asp);
asp->opaque = opaque;
asp->is_connected = 0;
asp->device = android_device_init(asp, AD_SENSOR_PORT, _on_io_failure);
if (asp->device == NULL) {
_sensors_port_free(asp);
return NULL;
}
res = android_device_connect_sync(asp->device, ASP_QUERY_TIMEOUT);
if (res != 0) {
sensors_port_destroy(asp);
return NULL;
}
res = android_device_query(asp->device, "list",
asp->sensors, sizeof(asp->sensors),
ASP_QUERY_TIMEOUT);
if (res != 0) {
sensors_port_destroy(asp);
return NULL;
}
/* Parse sensor list. */
asp->sensors_num = 0;
wrk = asp->sensors;
while (wrk != NULL && *wrk != '\0' && *wrk != '\n') {
asp->sensor_list[asp->sensors_num] = wrk;
asp->sensors_num++;
wrk = strchr(wrk, '\n');
if (wrk != NULL) {
*wrk = '\0'; wrk++;
}
}
android_device_listen(asp->device, asp->events, sizeof(asp->events),
_on_sensor_received);
return asp;
}
int
sensors_port_init_sensors(AndroidSensorsPort* asp)
{
int res, id;
/* Disable all sensors for now. Reenable only those that are emulated. */
res = sensors_port_disable_sensor(asp, "all");
if (res) {
return res;
}
/* Start listening on sensor events. */
res = android_device_listen(asp->device, asp->events, sizeof(asp->events),
_on_sensor_received);
if (res) {
return res;
}
/* Walk throuh the list of enabled sensors enabling them on the device. */
for (id = 0; id < MAX_SENSORS; id++) {
if (android_sensors_get_sensor_status(id) == 1) {
res = sensors_port_enable_sensor(asp, android_sensors_get_name_from_id(id));
if (res == 0) {
D("Sensor '%s' is enabled on the device.",
android_sensors_get_name_from_id(id));
}
}
}
/* Start sensor events. */
return sensors_port_start(asp);
}
void
sensors_port_destroy(AndroidSensorsPort* asp)
{
_sensors_port_free(asp);
}
int
sensors_port_is_connected(AndroidSensorsPort* asp)
{
return asp->is_connected;
}
int
sensors_port_enable_sensor(AndroidSensorsPort* asp, const char* name)
{
char query[1024];
char qresp[1024];
snprintf(query, sizeof(query), "enable:%s", name);
const int res =
android_device_query(asp->device, query, qresp, sizeof(qresp),
ASP_QUERY_TIMEOUT);
if (res) {
if (errno) {
D("Query '%s' failed on I/O: %s", query, strerror(errno));
} else {
D("Query '%s' failed on device: %s", query, qresp);
}
}
return res;
}
int
sensors_port_disable_sensor(AndroidSensorsPort* asp, const char* name)
{
char query[1024];
char qresp[1024];
snprintf(query, sizeof(query), "disable:%s", name);
const int res =
android_device_query(asp->device, query, qresp, sizeof(qresp),
ASP_QUERY_TIMEOUT);
if (res) {
if (errno) {
D("Query '%s' failed on I/O: %s", query, strerror(errno));
} else {
D("Query '%s' failed on device: %s", query, qresp);
}
}
return res;
}
int
sensors_port_start(AndroidSensorsPort* asp)
{
char qresp[ASP_MAX_SENSOR_MSG];
const int res =
android_device_query(asp->device, "start", qresp, sizeof(qresp),
ASP_QUERY_TIMEOUT);
if (res) {
if (errno) {
D("Query 'start' failed on I/O: %s", strerror(errno));
} else {
D("Query 'start' failed on device: %s", qresp);
}
}
return res;
}
int
sensors_port_stop(AndroidSensorsPort* asp)
{
char qresp[ASP_MAX_SENSOR_MSG];
const int res =
android_device_query(asp->device, "stop", qresp, sizeof(qresp),
ASP_QUERY_TIMEOUT);
if (res) {
if (errno) {
D("Query 'stop' failed on I/O: %s", strerror(errno));
} else {
D("Query 'stop' failed on device: %s", qresp);
}
}
return res;
}