Home | History | Annotate | Download | only in android
      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(sensors_port)
     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 #include "android/sdk-controller-socket.h"
    177 
    178 static AsyncIOAction
    179 _on_sdkctl_connection(void* client_opaque, SDKCtlSocket* sdkctl, AsyncIOState status)
    180 {
    181     if (status == ASIO_STATE_FAILED) {
    182         sdkctl_socket_reconnect(sdkctl, 1970, 20);
    183     }
    184     return ASIO_ACTION_DONE;
    185 }
    186 
    187 void on_sdkctl_handshake(void* client_opaque,
    188                          SDKCtlSocket* sdkctl,
    189                          void* handshake,
    190                          uint32_t handshake_size,
    191                          AsyncIOState status)
    192 {
    193     if (status == ASIO_STATE_SUCCEEDED) {
    194         printf("---------- Handshake %d bytes received.\n", handshake_size);
    195     } else {
    196         printf("!!!!!!!!!! Handshake failed with status %d: %d -> %s\n",
    197                status, errno, strerror(errno));
    198         sdkctl_socket_reconnect(sdkctl, 1970, 20);
    199     }
    200 }
    201 
    202 void on_sdkctl_message(void* client_opaque,
    203                        SDKCtlSocket* sdkctl,
    204                        SDKCtlPacket* message,
    205                        int msg_type,
    206                        void* msg_data,
    207                        int msg_size)
    208 {
    209     printf("########################################################\n");
    210 }
    211 
    212 AndroidSensorsPort*
    213 sensors_port_create(void* opaque)
    214 {
    215     AndroidSensorsPort* asp;
    216     char* wrk;
    217     int res;
    218 
    219     SDKCtlSocket* sdkctl = sdkctl_socket_new(20, "test", _on_sdkctl_connection,
    220                                              on_sdkctl_handshake, on_sdkctl_message,
    221                                              NULL);
    222 //    sdkctl_init_recycler(sdkctl, 64, 8);
    223     sdkctl_socket_connect(sdkctl, 1970, 20);
    224 
    225     ANEW0(asp);
    226     asp->opaque = opaque;
    227     asp->is_connected = 0;
    228 
    229     asp->device = android_device_init(asp, AD_SENSOR_PORT, _on_io_failure);
    230     if (asp->device == NULL) {
    231         _sensors_port_free(asp);
    232         return NULL;
    233     }
    234 
    235     res = android_device_connect_sync(asp->device, ASP_QUERY_TIMEOUT);
    236     if (res != 0) {
    237         sensors_port_destroy(asp);
    238         return NULL;
    239     }
    240 
    241     res = android_device_query(asp->device, "list",
    242                                asp->sensors, sizeof(asp->sensors),
    243                                ASP_QUERY_TIMEOUT);
    244     if (res != 0) {
    245         sensors_port_destroy(asp);
    246         return NULL;
    247     }
    248 
    249     /* Parse sensor list. */
    250     asp->sensors_num = 0;
    251     wrk = asp->sensors;
    252 
    253     while (wrk != NULL && *wrk != '\0' && *wrk != '\n') {
    254         asp->sensor_list[asp->sensors_num] = wrk;
    255         asp->sensors_num++;
    256         wrk = strchr(wrk, '\n');
    257         if (wrk != NULL) {
    258             *wrk = '\0'; wrk++;
    259         }
    260     }
    261 
    262     android_device_listen(asp->device, asp->events, sizeof(asp->events),
    263                           _on_sensor_received);
    264     return asp;
    265 }
    266 
    267 int
    268 sensors_port_init_sensors(AndroidSensorsPort* asp)
    269 {
    270     int res, id;
    271 
    272     /* Disable all sensors for now. Reenable only those that are emulated. */
    273     res = sensors_port_disable_sensor(asp, "all");
    274     if (res) {
    275         return res;
    276     }
    277 
    278     /* Start listening on sensor events. */
    279     res = android_device_listen(asp->device, asp->events, sizeof(asp->events),
    280                                 _on_sensor_received);
    281     if (res) {
    282         return res;
    283     }
    284 
    285     /* Walk throuh the list of enabled sensors enabling them on the device. */
    286     for (id = 0; id < MAX_SENSORS; id++) {
    287         if (android_sensors_get_sensor_status(id) == 1) {
    288             res = sensors_port_enable_sensor(asp, android_sensors_get_name_from_id(id));
    289             if (res == 0) {
    290                 D("Sensor '%s' is enabled on the device.",
    291                   android_sensors_get_name_from_id(id));
    292             }
    293         }
    294     }
    295 
    296     /* Start sensor events. */
    297     return sensors_port_start(asp);
    298 }
    299 
    300 void
    301 sensors_port_destroy(AndroidSensorsPort* asp)
    302 {
    303     _sensors_port_free(asp);
    304 }
    305 
    306 int
    307 sensors_port_is_connected(AndroidSensorsPort* asp)
    308 {
    309     return asp->is_connected;
    310 }
    311 
    312 int
    313 sensors_port_enable_sensor(AndroidSensorsPort* asp, const char* name)
    314 {
    315     char query[1024];
    316     char qresp[1024];
    317     snprintf(query, sizeof(query), "enable:%s", name);
    318     const int res =
    319         android_device_query(asp->device, query, qresp, sizeof(qresp),
    320                              ASP_QUERY_TIMEOUT);
    321     if (res) {
    322         if (errno) {
    323             D("Query '%s' failed on I/O: %s", query, strerror(errno));
    324         } else {
    325             D("Query '%s' failed on device: %s", query, qresp);
    326         }
    327     }
    328     return res;
    329 }
    330 
    331 int
    332 sensors_port_disable_sensor(AndroidSensorsPort* asp, const char* name)
    333 {
    334     char query[1024];
    335     char qresp[1024];
    336     snprintf(query, sizeof(query), "disable:%s", name);
    337     const int res =
    338         android_device_query(asp->device, query, qresp, sizeof(qresp),
    339                              ASP_QUERY_TIMEOUT);
    340     if (res) {
    341         if (errno) {
    342             D("Query '%s' failed on I/O: %s", query, strerror(errno));
    343         } else {
    344             D("Query '%s' failed on device: %s", query, qresp);
    345         }
    346     }
    347     return res;
    348 }
    349 
    350 int
    351 sensors_port_start(AndroidSensorsPort* asp)
    352 {
    353     char qresp[ASP_MAX_SENSOR_MSG];
    354     const int res =
    355         android_device_query(asp->device, "start", qresp, sizeof(qresp),
    356                              ASP_QUERY_TIMEOUT);
    357     if (res) {
    358         if (errno) {
    359             D("Query 'start' failed on I/O: %s", strerror(errno));
    360         } else {
    361             D("Query 'start' failed on device: %s", qresp);
    362         }
    363     }
    364     return res;
    365 }
    366 
    367 int
    368 sensors_port_stop(AndroidSensorsPort* asp)
    369 {
    370     char qresp[ASP_MAX_SENSOR_MSG];
    371     const int res =
    372         android_device_query(asp->device, "stop", qresp, sizeof(qresp),
    373                              ASP_QUERY_TIMEOUT);
    374     if (res) {
    375         if (errno) {
    376             D("Query 'stop' failed on I/O: %s", strerror(errno));
    377         } else {
    378             D("Query 'stop' failed on device: %s", qresp);
    379         }
    380     }
    381 
    382     return res;
    383 }
    384