2ab68fe216d61c25b65467862d34bc0a82331289
[platform/core/location/lbs-server.git] / module / fused_module.c
1 /*
2  * lbs-server
3  *
4  * Copyright (c) 2016-2017 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <glib.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include <vconf.h>
25 #include <vconf-internal-location-keys.h>
26 #include <location-module.h>
27
28 #include <dlfcn.h>
29 #include <lbs_dbus_client.h>
30 #include <lbs_agps.h>
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #include "log.h"
37
38 #define MAX_GPS_LOC_ITEM                7
39 #define LOCATION_FUSED_HIGH             0
40 #define LOCATION_FUSED_BALANCED 1
41
42 typedef struct {
43         lbs_client_dbus_h lbs_client;
44         LocModPositionExtCB pos_cb;
45         gpointer userdata;
46         gboolean is_started;
47         guint pos_interval;
48         gint fused_mode;
49 } ModFusedData;
50
51 static void position_callback(GVariant *param, void *user_data)
52 {
53         ModFusedData *module = (ModFusedData *)user_data;
54         g_return_if_fail(module);
55         g_return_if_fail(module->pos_cb);
56
57         int method = 0, fields = 0 , timestamp = 0 , level = 0;
58         double latitude = 0.0, longitude = 0.0, altitude = 0.0, speed = 0.0, direction = 0.0, climb = 0.0, horizontal = 0.0, vertical = 0.0;
59         GVariant *accuracy = NULL;
60
61         g_variant_get(param, "(iiidddddd@(idd))", &method, &fields, &timestamp, &latitude, &longitude, &altitude, &speed, &direction, &climb, &accuracy);
62
63 //      MOD_FUSED_LOGD("position_callback [method: %d] GPS=0, WPS=1/AGPS=2/GEOFENCE/MOCK/FUSED", method);
64
65         if (method != LBS_CLIENT_METHOD_GPS && method != LBS_CLIENT_METHOD_NPS) {
66                 if (method != LBS_CLIENT_METHOD_MOCK) {
67                         MOD_FUSED_LOGD("Method is not LBS_CLIENT_METHOD_FUSED: %d", method);
68                         return;
69                 }
70         }
71
72         g_variant_get(accuracy, "(idd)", &level, &horizontal, &vertical);
73
74         LocationPosition *pos = NULL;
75         LocationVelocity *vel = NULL;
76         LocationAccuracy *acc = NULL;
77
78         pos = location_position_new(timestamp, latitude, longitude, altitude, LOCATION_STATUS_3D_FIX);
79         vel = location_velocity_new(timestamp, speed, direction, climb);
80         acc = location_accuracy_new(LOCATION_ACCURACY_LEVEL_DETAILED, horizontal, vertical);
81
82         module->pos_cb(TRUE, pos, vel, acc, module->userdata);
83
84         location_position_free(pos);
85         location_velocity_free(vel);
86         location_accuracy_free(acc);
87         g_variant_unref(accuracy);
88 }
89
90 static void on_signal_callback(const gchar *sig, GVariant *param, gpointer user_data)
91 {
92         if (!g_strcmp0(sig, "PositionChanged")) {
93                 position_callback(param, user_data);
94         }
95 }
96
97 static int start_gps(gpointer handle, guint pos_update_interval, LocModStatusCB status_cb, LocModPositionExtCB pos_cb, LocModSatelliteCB sat_cb, gpointer userdata)
98 {
99         MOD_FUSED_LOGD("Fused : start_gps");
100         ModFusedData *module = (ModFusedData *)handle;
101         g_return_val_if_fail(module, LOCATION_ERROR_NOT_AVAILABLE);
102         g_return_val_if_fail(pos_cb, LOCATION_ERROR_NOT_AVAILABLE);
103
104         module->pos_cb = pos_cb;
105         module->userdata = userdata;
106
107         int ret = LBS_CLIENT_ERROR_NONE;
108         ret = lbs_client_create(LBS_CLIENT_METHOD_GPS, &(module->lbs_client));
109         if (ret != LBS_CLIENT_ERROR_NONE || !module->lbs_client) {
110                 MOD_FUSED_LOGE("Fail to create lbs_client_h. Error[%d]", ret);
111                 return LOCATION_ERROR_NOT_AVAILABLE;
112         }
113         MOD_FUSED_LOGD("Fused : gps-manger(%p) pos_cb (%p) user_data(%p)", module, module->pos_cb, module->userdata);
114
115         ret = lbs_client_start(module->lbs_client, pos_update_interval, LBS_CLIENT_LOCATION_CB | LBS_CLIENT_LOCATION_STATUS_CB, on_signal_callback, LOCATION_FUSED_HIGH, module);
116         if (ret != LBS_CLIENT_ERROR_NONE) {
117                 if (ret == LBS_CLIENT_ERROR_ACCESS_DENIED) {
118                         MOD_FUSED_LOGE("Access denied[%d]", ret);
119                         return LOCATION_ERROR_NOT_ALLOWED;
120                 }
121                 MOD_FUSED_LOGE("Fail to start_gps lbs_client_h. Error[%d]", ret);
122                 lbs_client_destroy(module->lbs_client);
123                 module->lbs_client = NULL;
124
125                 return LOCATION_ERROR_NOT_AVAILABLE;
126         }
127
128         module->pos_interval = pos_update_interval;
129         module->fused_mode = LOCATION_FUSED_HIGH;
130         return LOCATION_ERROR_NONE;
131 }
132
133 static int start_wps(gpointer handle, guint pos_update_interval, LocModStatusCB status_cb, LocModPositionExtCB pos_cb, LocModSatelliteCB sat_cb, gpointer userdata)
134 {
135         MOD_FUSED_LOGD("Fused : start_wps");
136         ModFusedData *module = (ModFusedData *)handle;
137         g_return_val_if_fail(module, LOCATION_ERROR_NOT_AVAILABLE);
138         g_return_val_if_fail(pos_cb, LOCATION_ERROR_NOT_AVAILABLE);
139         module->pos_cb = pos_cb;
140         module->userdata = userdata;
141
142         int ret = LBS_CLIENT_ERROR_NONE;
143         ret = lbs_client_create(LBS_CLIENT_METHOD_NPS, &(module->lbs_client));
144         if (ret != LBS_CLIENT_ERROR_NONE || !module->lbs_client) {
145                 MOD_FUSED_LOGE("Fail to create lbs_client_h. Error[%d]", ret);
146                 return LOCATION_ERROR_NOT_AVAILABLE;
147         }
148         MOD_FUSED_LOGD("wps-manger(%p) pos_cb (%p) user_data(%p)", module, module->pos_cb, module->userdata);
149
150         ret = lbs_client_start(module->lbs_client, pos_update_interval, LBS_CLIENT_LOCATION_CB | LBS_CLIENT_LOCATION_STATUS_CB, on_signal_callback, LOCATION_FUSED_BALANCED, module);
151         if (ret != LBS_CLIENT_ERROR_NONE) {
152                 if (ret == LBS_CLIENT_ERROR_ACCESS_DENIED) {
153                         MOD_FUSED_LOGE("Access denied[%d]", ret);
154                         return LOCATION_ERROR_NOT_ALLOWED;
155                 }
156                 MOD_FUSED_LOGE("Fail to start_wps lbs_client_h. Error[%d]", ret);
157                 lbs_client_destroy(module->lbs_client);
158                 module->lbs_client = NULL;
159
160                 return LOCATION_ERROR_NOT_AVAILABLE;
161         }
162         module->pos_interval = pos_update_interval;
163         module->fused_mode = LOCATION_FUSED_BALANCED;
164         return LOCATION_ERROR_NONE;
165 }
166
167 static int stop(gpointer handle)
168 {
169         MOD_FUSED_LOGD("stop");
170         ModFusedData *module = (ModFusedData *) handle;
171         g_return_val_if_fail(module, LOCATION_ERROR_NOT_AVAILABLE);
172         g_return_val_if_fail(module->lbs_client, LOCATION_ERROR_NOT_AVAILABLE);
173
174         int ret = LBS_CLIENT_ERROR_NONE;
175
176         ret = lbs_client_stop(module->lbs_client, module->pos_interval, module->fused_mode);
177         MOD_FUSED_LOGD("stop gps interval [%d]", module->pos_interval);
178         if (ret != LBS_CLIENT_ERROR_NONE) {
179                 MOD_FUSED_LOGE("Fail to stop. Error[%d]", ret);
180                 lbs_client_destroy(module->lbs_client);
181                 module->lbs_client = NULL;
182                 return LOCATION_ERROR_NOT_AVAILABLE;
183         }
184
185         ret = lbs_client_destroy(module->lbs_client);
186         if (ret != LBS_CLIENT_ERROR_NONE) {
187                 MOD_FUSED_LOGE("Fail to destroy. Error[%d]", ret);
188                 return LOCATION_ERROR_NOT_AVAILABLE;
189         }
190         module->lbs_client = NULL;
191         module->pos_cb = NULL;
192
193         return LOCATION_ERROR_NONE;
194 }
195
196 static int get_last_position(gpointer handle, LocationPosition **position, LocationVelocity **velocity, LocationAccuracy **accuracy)
197 {
198         MOD_FUSED_LOGD("get_last_position");
199
200         ModFusedData *module = (ModFusedData *)handle;
201         g_return_val_if_fail(module, LOCATION_ERROR_NOT_AVAILABLE);
202
203         int timestamp = 0;
204         char location[128] = {0,};
205         char *last_location[MAX_GPS_LOC_ITEM] = {0,};
206         char *last = NULL;
207         char *str = NULL;
208         double longitude = 0.0, latitude = 0.0, altitude = 0.0;
209         double speed = 0.0, direction = 0.0;
210         double hor_accuracy = 0.0, ver_accuracy = 0.0;
211         int index = 0;
212         LocationStatus status = LOCATION_STATUS_NO_FIX;
213         LocationAccuracyLevel level = LOCATION_ACCURACY_LEVEL_NONE;
214
215         if (vconf_get_int(VCONFKEY_LOCATION_LAST_GPS_TIMESTAMP, &timestamp)) {
216                 MOD_FUSED_LOGD("Error to get VCONFKEY_LOCATION_LAST_GPS_TIMESTAMP");
217                 return LOCATION_ERROR_NOT_AVAILABLE;
218         } else {
219                 if (timestamp != 0) {
220                         if (vconf_get_dbl(VCONFKEY_LOCATION_LAST_GPS_LATITUDE, &latitude) ||
221                                 vconf_get_dbl(VCONFKEY_LOCATION_LAST_GPS_LONGITUDE, &longitude) ||
222                                 vconf_get_dbl(VCONFKEY_LOCATION_LAST_GPS_ALTITUDE, &altitude) ||
223                                 vconf_get_dbl(VCONFKEY_LOCATION_LAST_GPS_SPEED, &speed) ||
224                                 vconf_get_dbl(VCONFKEY_LOCATION_LAST_GPS_DIRECTION, &direction) ||
225                                 vconf_get_dbl(VCONFKEY_LOCATION_LAST_GPS_HOR_ACCURACY, &hor_accuracy) ||
226                                 vconf_get_dbl(VCONFKEY_LOCATION_LAST_GPS_VER_ACCURACY, &ver_accuracy)) {
227                                 return LOCATION_ERROR_NOT_AVAILABLE;
228                         }
229                 } else {
230                         if (vconf_get_int(VCONFKEY_LOCATION_NV_LAST_GPS_TIMESTAMP, &timestamp)) {
231                                 MOD_FUSED_LOGD("Error to get VCONFKEY_LOCATION_NV_LAST_GPS_TIMESTAMP");
232                                 return LOCATION_ERROR_NOT_AVAILABLE;
233                         }
234                         str = vconf_get_str(VCONFKEY_LOCATION_NV_LAST_GPS_LOCATION);
235                         if (str == NULL) {
236                                 MOD_FUSED_LOGD("Error to get VCONFKEY_LOCATION_NV_LAST_GPS_LOCATION");
237                                 return LOCATION_ERROR_NOT_AVAILABLE;
238                         }
239                         snprintf(location, sizeof(location), "%s", str);
240                         free(str);
241
242                         index = 0;
243                         last_location[index] = (char *)strtok_r(location, ";", &last);
244                         while (last_location[index] != NULL) {
245                                 switch (index) {
246                                 case 0:
247                                         latitude = strtod(last_location[index], NULL);
248                                         break;
249                                 case 1:
250                                         longitude = strtod(last_location[index], NULL);
251                                         break;
252                                 case 2:
253                                         altitude = strtod(last_location[index], NULL);
254                                         break;
255                                 case 3:
256                                         speed = strtod(last_location[index], NULL);
257                                         break;
258                                 case 4:
259                                         direction = strtod(last_location[index], NULL);
260                                         break;
261                                 case 5:
262                                         hor_accuracy = strtod(last_location[index], NULL);
263                                         break;
264                                 case 6:
265                                         ver_accuracy = strtod(last_location[index], NULL);
266                                         break;
267                                 default:
268                                         break;
269                                 }
270                                 if (++index == MAX_GPS_LOC_ITEM) break;
271                                 last_location[index] = (char *)strtok_r(NULL, ";", &last);
272                         }
273                 }
274         }
275
276         if (timestamp) {
277                 status = LOCATION_STATUS_3D_FIX;
278         } else {
279                 return LOCATION_ERROR_NOT_AVAILABLE;
280         }
281
282         level = LOCATION_ACCURACY_LEVEL_DETAILED;
283         if (position)
284                 *position = location_position_new(timestamp, latitude, longitude, altitude, status);
285         if (velocity)
286                 *velocity = location_velocity_new((guint) timestamp, speed, direction, 0.0);
287         if (accuracy)
288                 *accuracy = location_accuracy_new(level, hor_accuracy, ver_accuracy);
289
290         return LOCATION_ERROR_NONE;
291 }
292
293 static int set_position_update_interval(gpointer handle, guint interval)
294 {
295         ModFusedData *module = (ModFusedData *) handle;
296         g_return_val_if_fail(module, LOCATION_ERROR_NOT_AVAILABLE);
297         g_return_val_if_fail(module->lbs_client, LOCATION_ERROR_NOT_AVAILABLE);
298
299         int ret;
300         MOD_FUSED_LOGD("set_position_update inteval [%d] -> [%d]", module->pos_interval, interval);
301         ret = lbs_client_set_position_update_interval(module->lbs_client, interval, module->pos_interval);
302         if (ret != LBS_CLIENT_ERROR_NONE) {
303                 if (ret == LBS_CLIENT_ERROR_ACCESS_DENIED) {
304                         MOD_LOGE("Access denied[%d]", ret);
305                         return LOCATION_ERROR_NOT_ALLOWED;
306                 }
307                 MOD_LOGE("Failed lbs_client_set_position_update_interval. Error[%d]", ret);
308                 return LOCATION_ERROR_NOT_AVAILABLE;
309         }
310
311         module->pos_interval = interval;
312
313         return LOCATION_ERROR_NONE;
314 }
315
316 LOCATION_MODULE_API gpointer init(LocModFusedOps *ops)
317 {
318         MOD_FUSED_LOGD("init");
319
320         g_return_val_if_fail(ops, NULL);
321         ops->start_gps = start_gps;
322         ops->start_wps = start_wps;
323         ops->stop = stop;
324         ops->get_last_position = get_last_position;
325         ops->set_position_update_interval = set_position_update_interval;
326
327         ModFusedData *module = g_new0(ModFusedData, 1);
328         g_return_val_if_fail(module, NULL);
329
330         module->pos_cb = NULL;
331         module->userdata = NULL;
332         module->is_started = FALSE;
333         module->pos_interval = 0;
334         module->fused_mode = LOCATION_FUSED_HIGH;
335
336         return (gpointer) module;
337 }
338
339 LOCATION_MODULE_API void shutdown(gpointer handle)
340 {
341         MOD_FUSED_LOGD("shutdown");
342         g_return_if_fail(handle);
343         ModFusedData *module = (ModFusedData *) handle;
344
345         if (module->lbs_client) {
346                 lbs_client_stop(module->lbs_client, module->pos_interval, module->fused_mode);
347                 lbs_client_destroy(module->lbs_client);
348                 module->lbs_client = NULL;
349         }
350
351         module->pos_cb = NULL;
352         module->pos_interval = 0;
353         module->fused_mode = LOCATION_FUSED_HIGH;
354
355         g_free(module);
356         module = NULL;
357 }
358