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