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. */
38struct 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. */
59static 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 */
81static 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 */
142static 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 */
162static 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
178static 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
187void 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
202void 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
212AndroidSensorsPort*
213sensors_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
267int
268sensors_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
300void
301sensors_port_destroy(AndroidSensorsPort* asp)
302{
303    _sensors_port_free(asp);
304}
305
306int
307sensors_port_is_connected(AndroidSensorsPort* asp)
308{
309    return asp->is_connected;
310}
311
312int
313sensors_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
331int
332sensors_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
350int
351sensors_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
367int
368sensors_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