98fb603142bee168ec4e62c9f6b3a890e0b608b8
[framework/location/gps-manager.git] / module / module_gps_manager.c
1 /*
2  * gps-manager
3  *
4  * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Youngae Kang <youngae.kang@samsung.com>, Yunhan Kim <yhan.kim@samsung.com>,
7  *          Genie Kim <daejins.kim@samsung.com>, Minjune Kim <sena06.kim@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21
22 #include <glib.h>
23
24 #include <vconf.h>
25 #include <vconf-internal-location-keys.h>
26 #include <location-module.h>
27
28 #include <geoclue/geoclue-position.h>
29 #include <geoclue/geoclue-velocity.h>
30 #include <geoclue/geoclue-satellite.h>
31 #include <geoclue/geoclue-nmea.h>
32 #include <geoclue/geoclue-provider.h>
33 #include <dlfcn.h>
34
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38
39 #include "log.h"
40
41 typedef struct {
42         char devname[256];
43         GeocluePosition *pos;
44         GeoclueVelocity *vel;
45         GeoclueNmea *nmea;
46         GeoclueSatellite *sat;
47         LocModStatusCB status_cb;
48         LocModPositionCB pos_cb;
49         LocModVelocityCB vel_cb;
50         LocModSatelliteCB sat_cb;
51         gpointer userdata;
52         gboolean is_started;
53 } GpsManagerData;
54
55 #define GPS_MANAGER_SERVICE_NAME "org.freedesktop.Geoclue.Providers.GpsManager"
56 #define GPS_MANAGER_SERVICE_PATH "/org/freedesktop/Geoclue/Providers/GpsManager"
57
58
59 static void status_callback(GeoclueProvider * provider, gint status, gpointer userdata)
60 {
61         GpsManagerData *gps_manager = (GpsManagerData *) userdata;
62         g_return_if_fail(gps_manager);
63         g_return_if_fail(gps_manager->status_cb);
64
65         switch (status) {
66         case GEOCLUE_STATUS_ERROR:
67         case GEOCLUE_STATUS_UNAVAILABLE:
68         case GEOCLUE_STATUS_ACQUIRING:
69                 MOD_LOGD("GEOCLUE_STATUS_ACQUIRING/ERROR/UNAVAILABLE");
70                 gps_manager->status_cb(FALSE, LOCATION_STATUS_NO_FIX, gps_manager->userdata);
71                 break;
72         case GEOCLUE_STATUS_AVAILABLE:
73                 MOD_LOGD("GEOCLUE_STATUS_AVAILABLE");
74                 gps_manager->status_cb(TRUE, LOCATION_STATUS_3D_FIX, gps_manager->userdata);
75                 break;
76         default:
77                 break;
78         }
79 }
80
81 static void satellite_callback(GeoclueSatellite * satellite, int timestamp,
82                                int satellite_used, int satellite_visible,
83                                GArray * used_prn, GPtrArray * sat_info, gpointer userdata)
84 {
85         GpsManagerData *gps_manager = (GpsManagerData *) userdata;
86         g_return_if_fail(gps_manager);
87         g_return_if_fail(gps_manager->sat_cb);
88
89         guint idx;
90         guint used_idx;
91         LocationSatellite *sat = NULL;
92
93         sat = location_satellite_new(satellite_visible);
94
95         sat->timestamp = timestamp;
96         sat->num_of_sat_inview = satellite_visible;
97         sat->num_of_sat_used = satellite_used;
98         for (idx = 0; idx < satellite_visible; idx++) {
99                 gboolean used = FALSE;
100                 GValueArray *vals = (GValueArray *) g_ptr_array_index(sat_info, idx);
101                 gint prn = g_value_get_int(g_value_array_get_nth(vals, 0));
102                 gint elev = g_value_get_int(g_value_array_get_nth(vals, 1));
103                 gint azim = g_value_get_int(g_value_array_get_nth(vals, 2));
104                 gint snr = g_value_get_int(g_value_array_get_nth(vals, 3));
105                 for (used_idx = 0; used_idx < satellite_used; used_idx++) {
106                         if (prn == g_array_index(used_prn, guint, idx)) {
107                                 used = TRUE;
108                                 break;
109                         }
110                 }
111                 MOD_LOGD("prn[%d] : used %d elev %d azim %d snr %d", prn, used, elev, azim, snr);
112                 location_satellite_set_satellite_details(sat, idx, prn, used, elev, azim, snr);
113         }
114
115         gps_manager->sat_cb(TRUE, sat, gps_manager->userdata);
116         location_satellite_free(sat);
117 }
118
119 static void nmea_callback(GeoclueNmea * nmea, int timestamp, char *data, gpointer userdata)
120 {
121 }
122
123 static void position_callback(GeocluePosition * position,
124                               GeocluePositionFields fields, int timestamp,
125                               double latitude, double longitude, double altitude, GeoclueAccuracy * accuracy, gpointer userdata)
126 {
127         GpsManagerData *gps_manager = (GpsManagerData *) userdata;
128         g_return_if_fail(gps_manager);
129         g_return_if_fail(gps_manager->pos_cb);
130
131         GeoclueAccuracyLevel level;
132         double horiz_acc;
133         double vert_acc;
134         geoclue_accuracy_get_details(accuracy, &level, &horiz_acc, &vert_acc);
135
136         LocationPosition *pos = NULL;
137         LocationAccuracy *acc = NULL;
138
139         if ((fields & GEOCLUE_POSITION_FIELDS_LATITUDE)
140             && (fields & GEOCLUE_POSITION_FIELDS_LONGITUDE)) {
141                 if (fields & GEOCLUE_POSITION_FIELDS_ALTITUDE) {
142                         pos = location_position_new(timestamp, latitude, longitude, altitude, LOCATION_STATUS_3D_FIX);
143                 } else {
144                         pos = location_position_new(timestamp, latitude, longitude, 0.0, LOCATION_STATUS_2D_FIX);
145                 }
146         } else {
147                 pos = location_position_new(0.0, 0.0, 0.0, 0.0, LOCATION_STATUS_NO_FIX);
148         }
149
150         if (accuracy) {
151                 GeoclueAccuracyLevel level;
152                 double horiz_acc;
153                 double vert_acc;
154                 geoclue_accuracy_get_details(accuracy, &level, &horiz_acc, &vert_acc);
155                 acc = location_accuracy_new(LOCATION_ACCURACY_LEVEL_DETAILED, horiz_acc, vert_acc);
156         } else {
157                 acc = location_accuracy_new(LOCATION_ACCURACY_LEVEL_NONE, horiz_acc, vert_acc);
158         }
159
160         MOD_LOGD
161             ("time(%d) lat(%f) long(%f) alt(%f) status(%d) acc_level(%d) hoz_acc(%f) vert_acc(%f)",
162              pos->timestamp, pos->latitude, pos->longitude, pos->altitude,
163              pos->status, acc->level, acc->horizontal_accuracy, acc->vertical_accuracy);
164
165         gps_manager->pos_cb(TRUE, pos, acc, gps_manager->userdata);
166         location_position_free(pos);
167         location_accuracy_free(acc);
168 }
169
170 static void velocity_callback(GeoclueVelocity * velocity,
171                               GeoclueVelocityFields fields, int timestamp,
172                               double speed, double direction, double climb, gpointer userdata)
173 {
174         GpsManagerData *gps_manager = (GpsManagerData *) userdata;
175         g_return_if_fail(gps_manager);
176         g_return_if_fail(gps_manager->vel_cb);
177
178         LocationVelocity *vel = NULL;
179         LocationAccuracy *acc = NULL;
180
181         if (fields & GEOCLUE_VELOCITY_FIELDS_SPEED && fields & GEOCLUE_VELOCITY_FIELDS_DIRECTION) {
182                 if (fields & GEOCLUE_VELOCITY_FIELDS_CLIMB)
183                         vel = location_velocity_new(timestamp, speed, direction, climb);
184                 else
185                         vel = location_velocity_new(timestamp, speed, direction, 0);
186                 acc = location_accuracy_new(LOCATION_ACCURACY_LEVEL_DETAILED, 0, 0);
187         } else {
188                 vel = location_velocity_new(0, 0, 0, 0);
189                 acc = location_accuracy_new(LOCATION_ACCURACY_LEVEL_NONE, 0, 0);
190         }
191         MOD_LOGD
192             ("timestamp(%d) speed(%f) direction(%f) climb(%f) acc_level(%d) hoz_acc(%f) vert_acc(%f)",
193              vel->timestamp, vel->speed, vel->direction, vel->climb, acc->level,
194              acc->horizontal_accuracy, acc->vertical_accuracy);
195
196         gps_manager->vel_cb(TRUE, vel, acc, gps_manager->userdata);
197         location_velocity_free(vel);
198         location_accuracy_free(acc);
199 }
200
201 static void unref_gps_manager(GpsManagerData * gps_manager)
202 {
203         if (gps_manager->pos) {
204                 g_signal_handlers_disconnect_by_func(G_OBJECT
205                                                      (GEOCLUE_PROVIDER
206                                                       (gps_manager->pos)), G_CALLBACK(status_callback), gps_manager);
207                 g_signal_handlers_disconnect_by_func(G_OBJECT
208                                                      (GEOCLUE_PROVIDER
209                                                       (gps_manager->pos)), G_CALLBACK(position_callback), gps_manager);
210                 g_object_unref(gps_manager->pos);
211                 gps_manager->pos = NULL;
212         }
213
214         if (gps_manager->vel) {
215                 g_signal_handlers_disconnect_by_func(G_OBJECT
216                                                      (GEOCLUE_PROVIDER
217                                                       (gps_manager->vel)), G_CALLBACK(velocity_callback), gps_manager);
218                 g_object_unref(gps_manager->vel);
219                 gps_manager->vel = NULL;
220         }
221
222         if (gps_manager->nmea) {
223                 g_signal_handlers_disconnect_by_func(G_OBJECT
224                                                      (GEOCLUE_PROVIDER
225                                                       (gps_manager->nmea)), G_CALLBACK(nmea_callback), gps_manager);
226                 g_object_unref(gps_manager->nmea);
227                 gps_manager->nmea = NULL;
228         }
229
230         if (gps_manager->sat) {
231                 g_signal_handlers_disconnect_by_func(G_OBJECT
232                                                      (GEOCLUE_PROVIDER
233                                                       (gps_manager->sat)), G_CALLBACK(satellite_callback), gps_manager);
234                 g_object_unref(gps_manager->sat);
235                 gps_manager->sat = NULL;
236         }
237
238         gps_manager->is_started = FALSE;
239 }
240
241 static gboolean ref_gps_manager(GpsManagerData * gps_manager)
242 {
243         gchar *service, *path;
244
245         if (gps_manager->is_started == TRUE) {
246                 MOD_LOGW("gps-manager is alredy started");
247                 return TRUE;
248         }
249
250         service = g_strdup_printf(GPS_MANAGER_SERVICE_NAME);
251         path = g_strdup_printf(GPS_MANAGER_SERVICE_PATH);
252
253         if (!gps_manager->pos) {
254                 gps_manager->pos = geoclue_position_new(service, path);
255         }
256         if (!gps_manager->vel) {
257                 gps_manager->vel = geoclue_velocity_new(service, path);
258         }
259         if (!gps_manager->nmea) {
260                 gps_manager->nmea = geoclue_nmea_new(service, path);
261         }
262         if (!gps_manager->sat) {
263                 gps_manager->sat = geoclue_satellite_new(service, path);
264         }
265
266         g_free(service);
267         g_free(path);
268
269         if (!gps_manager->pos || !gps_manager->vel || !gps_manager->nmea || !gps_manager->sat) {
270                 MOD_LOGW("Error while creating Geoclue object.");
271                 unref_gps_manager(gps_manager);
272                 return FALSE;
273         }
274
275         gps_manager->is_started = TRUE;
276         int ret;
277         ret =
278             g_signal_connect(G_OBJECT(GEOCLUE_PROVIDER(gps_manager->pos)),
279                              "status-changed", G_CALLBACK(status_callback), gps_manager);
280         MOD_LOGD("gsignal_connect status-changed %d", ret);
281         ret =
282             g_signal_connect(G_OBJECT(GEOCLUE_PROVIDER(gps_manager->pos)),
283                              "position-changed", G_CALLBACK(position_callback), gps_manager);
284         MOD_LOGD("gsignal_connect position-changed %d", ret);
285         ret =
286             g_signal_connect(G_OBJECT(GEOCLUE_PROVIDER(gps_manager->vel)),
287                              "velocity-changed", G_CALLBACK(velocity_callback), gps_manager);
288         MOD_LOGD("gsignal_connect velocity-changed %d", ret);
289         ret =
290             g_signal_connect(G_OBJECT(GEOCLUE_PROVIDER(gps_manager->sat)),
291                              "satellite-changed", G_CALLBACK(satellite_callback), gps_manager);
292         MOD_LOGD("gsignal_connect satellite-changed %d", ret);
293         ret =
294             g_signal_connect(G_OBJECT(GEOCLUE_PROVIDER(gps_manager->nmea)),
295                              "nmea-changed", G_CALLBACK(nmea_callback), gps_manager);
296         MOD_LOGD("gsignal_connect nmea-changed %d", ret);
297
298         return TRUE;
299 }
300
301 static int start(gpointer handle, LocModStatusCB status_cb, LocModPositionCB pos_cb, LocModVelocityCB vel_cb, LocModSatelliteCB sat_cb, gpointer userdata)
302 {
303         MOD_LOGD("start");
304         GpsManagerData *gps_manager = (GpsManagerData *) handle;
305         g_return_val_if_fail(gps_manager, LOCATION_ERROR_NOT_AVAILABLE);
306         g_return_val_if_fail(status_cb, LOCATION_ERROR_NOT_AVAILABLE);
307         g_return_val_if_fail(pos_cb, LOCATION_ERROR_NOT_AVAILABLE);
308         g_return_val_if_fail(vel_cb, LOCATION_ERROR_NOT_AVAILABLE);
309
310         gps_manager->status_cb = status_cb;
311         gps_manager->pos_cb = pos_cb;
312         gps_manager->vel_cb = vel_cb;
313         gps_manager->sat_cb = sat_cb;
314         gps_manager->userdata = userdata;
315
316         if (!ref_gps_manager(gps_manager))
317                 return LOCATION_ERROR_NOT_AVAILABLE;
318
319         GHashTable *options;
320         GError *error = NULL;
321
322         options = g_hash_table_new(g_str_hash, g_str_equal);
323         g_hash_table_insert(options, "CMD", "START");
324
325         if (!geoclue_provider_set_options(GEOCLUE_PROVIDER(gps_manager->pos), options, &error)) {
326                 MOD_LOGE("Error geoclue_provider_set_options(START) : %s", error->message);
327                 g_error_free(error);
328                 error = NULL;
329                 g_hash_table_destroy(options);
330                 return LOCATION_ERROR_NOT_AVAILABLE;
331         } else {
332                 MOD_LOGD("Success to geoclue_provider_set_options(START)");
333         }
334         g_hash_table_destroy(options);
335
336         return LOCATION_ERROR_NONE;
337 }
338
339 static int stop(gpointer handle)
340 {
341         MOD_LOGD("stop");
342         GpsManagerData *gps_manager = (GpsManagerData *) handle;
343         g_return_val_if_fail(gps_manager, LOCATION_ERROR_NOT_AVAILABLE);
344         g_return_val_if_fail(gps_manager->status_cb, LOCATION_ERROR_NOT_AVAILABLE);
345
346         GHashTable *options;
347         GError *error = NULL;
348
349         options = g_hash_table_new(g_str_hash, g_str_equal);
350         g_hash_table_insert(options, "CMD", "STOP");
351
352         if (!geoclue_provider_set_options(GEOCLUE_PROVIDER(gps_manager->pos), options, &error)) {
353                 MOD_LOGE("Error geoclue_provider_set_options(STOP) : %s", error->message);
354                 g_error_free(error);
355                 error = NULL;
356                 g_hash_table_destroy(options);
357                 return LOCATION_ERROR_NOT_AVAILABLE;
358         } else {
359                 MOD_LOGD("Success to geoclue_provider_set_options(STOP)");
360         }
361         g_hash_table_destroy(options);
362
363         unref_gps_manager(gps_manager);
364         gps_manager->status_cb(FALSE, LOCATION_STATUS_NO_FIX, gps_manager->userdata);
365         return LOCATION_ERROR_NONE;
366 }
367
368 static int get_position(gpointer handle, LocationPosition ** position, LocationAccuracy ** accuracy)
369 {
370         MOD_LOGD("get_position");
371         GpsManagerData *gps_manager = (GpsManagerData *) handle;
372         g_return_val_if_fail(gps_manager, LOCATION_ERROR_NOT_AVAILABLE);
373         g_return_val_if_fail(gps_manager->pos, LOCATION_ERROR_NOT_AVAILABLE);
374         g_return_val_if_fail(position, LOCATION_ERROR_PARAMETER);
375         g_return_val_if_fail(accuracy, LOCATION_ERROR_PARAMETER);
376
377         GeocluePositionFields fields;
378         int timestamp;
379         double lat, lon, alt;
380         GeoclueAccuracy *_accuracy = NULL;
381         GError *error = NULL;
382
383         fields = geoclue_position_get_position(gps_manager->pos, &timestamp, &lat, &lon, &alt, &_accuracy, &error);
384         if (error) {
385                 MOD_LOGD("Error getting position: %s", error->message);
386                 g_error_free(error);
387                 return LOCATION_ERROR_NOT_AVAILABLE;
388         }
389
390         if (fields & GEOCLUE_POSITION_FIELDS_LATITUDE && fields & GEOCLUE_POSITION_FIELDS_LONGITUDE) {
391                 if (fields & GEOCLUE_POSITION_FIELDS_ALTITUDE)
392                         *position = location_position_new(timestamp, lat, lon, alt, LOCATION_STATUS_3D_FIX);
393                 else
394                         *position = location_position_new(timestamp, lat, lon, 0, LOCATION_STATUS_2D_FIX);
395         } else
396                 *position = location_position_new(0, 0, 0, 0, LOCATION_STATUS_NO_FIX);
397
398         if (_accuracy) {
399                 GeoclueAccuracyLevel level;
400                 double horiz_acc;
401                 double vert_acc;
402                 geoclue_accuracy_get_details(_accuracy, &level, &horiz_acc, &vert_acc);
403                 *accuracy = location_accuracy_new(LOCATION_ACCURACY_LEVEL_DETAILED, horiz_acc, vert_acc);
404                 geoclue_accuracy_free(_accuracy);
405         } else
406                 *accuracy = location_accuracy_new(LOCATION_ACCURACY_LEVEL_NONE, 0, 0);
407
408         return LOCATION_ERROR_NONE;
409 }
410
411 static int get_velocity(gpointer handle, LocationVelocity ** velocity, LocationAccuracy ** accuracy)
412 {
413         MOD_LOGD("get_velocity");
414         GpsManagerData *gps_manager = (GpsManagerData *) handle;
415         g_return_val_if_fail(gps_manager, LOCATION_ERROR_NOT_AVAILABLE);
416         g_return_val_if_fail(gps_manager->vel, LOCATION_ERROR_NOT_AVAILABLE);
417         g_return_val_if_fail(velocity, LOCATION_ERROR_PARAMETER);
418         g_return_val_if_fail(accuracy, LOCATION_ERROR_PARAMETER);
419
420         GeoclueVelocityFields fields;
421         int timestamp;
422         double spd, dir, climb;
423         GError *error = NULL;
424
425         fields = geoclue_velocity_get_velocity(gps_manager->vel, &timestamp, &spd, &dir, &climb, &error);
426         if (error) {
427                 MOD_LOGD("Error getting velocity: %s", error->message);
428                 g_error_free(error);
429                 return LOCATION_ERROR_NOT_AVAILABLE;
430         }
431
432         if (fields & GEOCLUE_VELOCITY_FIELDS_SPEED && fields & GEOCLUE_VELOCITY_FIELDS_DIRECTION) {
433                 if (fields & GEOCLUE_VELOCITY_FIELDS_CLIMB)
434                         *velocity = location_velocity_new(timestamp, spd, dir, climb);
435                 else
436                         *velocity = location_velocity_new(timestamp, spd, dir, 0);
437                 *accuracy = location_accuracy_new(LOCATION_ACCURACY_LEVEL_DETAILED, 0, 0);
438         } else {
439                 *velocity = location_velocity_new(0, 0, 0, 0);
440                 *accuracy = location_accuracy_new(LOCATION_ACCURACY_LEVEL_NONE, 0, 0);
441         }
442         return LOCATION_ERROR_NONE;
443 }
444
445 static int get_nmea(gpointer handle, gchar ** nmea_data)
446 {
447         MOD_LOGD("get_nmea");
448         GpsManagerData *gps_manager = (GpsManagerData *) handle;
449         g_return_val_if_fail(gps_manager, LOCATION_ERROR_NOT_AVAILABLE);
450         g_return_val_if_fail(gps_manager->nmea, LOCATION_ERROR_NOT_AVAILABLE);
451         g_return_val_if_fail(nmea_data, LOCATION_ERROR_PARAMETER);
452
453         gboolean ret = FALSE;
454         int timestamp = 0;
455         char *_nmea_data = NULL;
456         GError *error = NULL;
457         ret = geoclue_nmea_get_nmea(gps_manager->nmea, &timestamp, &_nmea_data, &error);
458         if (!ret && error) {
459                 MOD_LOGD("\t Error getting nmea: %s", error->message);
460                 g_error_free(error);
461                 return LOCATION_ERROR_NOT_AVAILABLE;
462         }
463         *nmea_data = g_strdup(_nmea_data);
464
465         return LOCATION_ERROR_NONE;
466 }
467
468 static int get_satellite(gpointer handle, LocationSatellite ** satellite)
469 {
470         MOD_LOGD("get_satellite");
471         GpsManagerData *gps_manager = (GpsManagerData *) handle;
472         g_return_val_if_fail(gps_manager, LOCATION_ERROR_NOT_AVAILABLE);
473         g_return_val_if_fail(gps_manager->sat, LOCATION_ERROR_NOT_AVAILABLE);
474         g_return_val_if_fail(satellite, LOCATION_ERROR_PARAMETER);
475
476         int timestamp = 0;
477         int idx = 0;
478         int sat_used = 0;
479         int sat_vis = 0;
480         GArray *u_prn = NULL;
481         GPtrArray *sat_info = NULL;
482         GError *error = NULL;
483
484         geoclue_satellite_get_satellite(gps_manager->sat, &timestamp, &sat_used, &sat_vis, &u_prn, &sat_info, &error);
485         if (error) {
486                 MOD_LOGW("\t Error getting satellite: %s", error->message);
487                 g_error_free(error);
488                 return LOCATION_ERROR_NOT_AVAILABLE;
489         }
490         *satellite = location_satellite_new(sat_vis);
491         (*satellite)->timestamp = timestamp;
492
493         for (idx = 0; idx < sat_vis; idx++) {
494                 GValueArray *vals = (GValueArray *) g_ptr_array_index(sat_info, idx);
495                 gint prn = g_value_get_int(g_value_array_get_nth(vals, 0));
496                 gint elev = g_value_get_int(g_value_array_get_nth(vals, 1));
497                 gint azim = g_value_get_int(g_value_array_get_nth(vals, 2));
498                 gint snr = g_value_get_int(g_value_array_get_nth(vals, 3));
499
500                 int used_idx = 0;
501                 gboolean is_used = FALSE;
502                 for (used_idx = 0; used_idx < sat_used; used_idx++) {
503                         if ((guint) prn == (guint) g_array_index(u_prn, guint, used_idx)) {
504                                 is_used = TRUE;
505                                 break;
506                         }
507                 }
508                 location_satellite_set_satellite_details(*satellite, idx,
509                                                          (guint) prn, is_used, (guint) elev, (guint) azim, (guint) snr);
510         }
511
512         if (u_prn)
513                 g_array_free(u_prn, TRUE);
514         if (sat_info)
515                 g_ptr_array_free(sat_info, TRUE);
516
517         return LOCATION_ERROR_NONE;
518 }
519
520 static int get_last_position(gpointer handle, LocationPosition ** position, LocationAccuracy ** accuracy)
521 {
522         MOD_LOGD("get_last_position");
523         GpsManagerData *gps_manager = (GpsManagerData *) handle;
524         g_return_val_if_fail(gps_manager, LOCATION_ERROR_NOT_AVAILABLE);
525         g_return_val_if_fail(position, LOCATION_ERROR_PARAMETER);
526         g_return_val_if_fail(accuracy, LOCATION_ERROR_PARAMETER);
527
528         int timestamp = 0;
529         double longitude = 0.0, latitude = 0.0, altitude = 0.0;
530         double hor_accuracy = 0.0, ver_accuracy = 0.0;
531         LocationStatus status = LOCATION_STATUS_NO_FIX;
532         LocationAccuracyLevel level = LOCATION_ACCURACY_LEVEL_NONE;
533
534         if (vconf_get_int(VCONFKEY_LOCATION_LAST_GPS_TIMESTAMP, &timestamp) ||
535                 vconf_get_dbl(VCONFKEY_LOCATION_LAST_GPS_LATITUDE, &latitude) ||
536                 vconf_get_dbl(VCONFKEY_LOCATION_LAST_GPS_LONGITUDE, &longitude) ||
537                 vconf_get_dbl(VCONFKEY_LOCATION_LAST_GPS_ALTITUDE, &altitude) ||
538                 vconf_get_dbl(VCONFKEY_LOCATION_LAST_GPS_HOR_ACCURACY, &hor_accuracy) ||
539                 vconf_get_dbl(VCONFKEY_LOCATION_LAST_GPS_VER_ACCURACY, &ver_accuracy)) {
540                 *position = NULL;
541                 *accuracy = NULL;
542                 return LOCATION_ERROR_NOT_AVAILABLE;
543         }
544
545         if (timestamp) {
546                 if (altitude) status = LOCATION_STATUS_3D_FIX;
547                 else status = LOCATION_STATUS_2D_FIX;
548         }
549         else {
550                 *position = NULL;
551                 *accuracy = NULL;
552                 return LOCATION_ERROR_NOT_AVAILABLE;
553         }
554
555         level = LOCATION_ACCURACY_LEVEL_DETAILED;
556         *position = location_position_new(timestamp, latitude, longitude, altitude, status);
557         *accuracy = location_accuracy_new(level, hor_accuracy, ver_accuracy);
558
559         return LOCATION_ERROR_NONE;
560 }
561
562 static int get_last_velocity(gpointer handle, LocationVelocity ** velocity, LocationAccuracy ** accuracy)
563 {
564         MOD_LOGD("get_last_velocity");
565         GpsManagerData *gps_manager = (GpsManagerData *) handle;
566         g_return_val_if_fail(gps_manager, LOCATION_ERROR_NOT_AVAILABLE);
567         g_return_val_if_fail(velocity, LOCATION_ERROR_PARAMETER);
568         g_return_val_if_fail(accuracy, LOCATION_ERROR_PARAMETER);
569
570         gint timestamp = 0;
571         gdouble speed = 0.0, direction = 0.0;
572         gdouble hor_accuracy = 0.0, ver_accuracy = 0.0;
573
574         if (vconf_get_int(VCONFKEY_LOCATION_LAST_GPS_TIMESTAMP, &timestamp) ||
575                 vconf_get_dbl(VCONFKEY_LOCATION_LAST_GPS_SPEED, &speed) ||
576                 vconf_get_dbl(VCONFKEY_LOCATION_LAST_GPS_DIRECTION, &direction) ||
577                 vconf_get_dbl(VCONFKEY_LOCATION_LAST_GPS_HOR_ACCURACY, &hor_accuracy) ||
578                 vconf_get_dbl(VCONFKEY_LOCATION_LAST_GPS_VER_ACCURACY, &ver_accuracy)) {
579                 *velocity = NULL;
580                 *accuracy = NULL;
581                 return LOCATION_ERROR_NOT_AVAILABLE;;
582         }
583
584         if (!timestamp || (speed < 0 && direction < 0)) {
585                 *velocity = NULL;
586                 *accuracy = NULL;
587                 return LOCATION_ERROR_NOT_AVAILABLE;
588         }
589
590         *velocity = location_velocity_new ((guint) timestamp, speed, direction, 0.0);
591         *accuracy = location_accuracy_new (LOCATION_ACCURACY_LEVEL_DETAILED, hor_accuracy, ver_accuracy);
592
593         return LOCATION_ERROR_NONE;
594 }
595
596 static int get_last_satellite(gpointer handle, LocationSatellite ** satellite)
597 {
598         MOD_LOGD("get_last_satellite");
599         GpsManagerData *gps_manager = (GpsManagerData *) handle;
600         g_return_val_if_fail(gps_manager, LOCATION_ERROR_NOT_AVAILABLE);
601         g_return_val_if_fail(satellite, LOCATION_ERROR_PARAMETER);
602
603         int timestamp = 0;
604         int idx = 0;
605         int sat_used = 0;
606         int sat_vis = 0;
607         GArray *u_prn = NULL;
608         GPtrArray *sat_info = NULL;
609         GError *error = NULL;
610         gchar *service = g_strdup_printf(GPS_MANAGER_SERVICE_NAME);
611         gchar *path = g_strdup_printf(GPS_MANAGER_SERVICE_PATH);
612
613         GeoclueSatellite *last_sat = geoclue_satellite_new(service, path);
614
615         geoclue_satellite_get_last_satellite(last_sat, &timestamp, &sat_used, &sat_vis, &u_prn, &sat_info, &error);
616         if (error) {
617                 MOD_LOGW("\t Error getting last satellite: %s", error->message);
618                 g_error_free(error);
619                 g_object_unref(last_sat);
620                 g_free (service);
621                 g_free (path);
622                 return LOCATION_ERROR_NOT_AVAILABLE;
623         }
624         *satellite = location_satellite_new(sat_vis);
625         (*satellite)->timestamp = timestamp;
626
627         for (idx = 0; idx < sat_vis; idx++) {
628                 GValueArray *vals = (GValueArray *) g_ptr_array_index(sat_info, idx);
629                 gint prn = g_value_get_int(g_value_array_get_nth(vals, 0));
630                 gint elev = g_value_get_int(g_value_array_get_nth(vals, 1));
631                 gint azim = g_value_get_int(g_value_array_get_nth(vals, 2));
632                 gint snr = g_value_get_int(g_value_array_get_nth(vals, 3));
633
634                 int used_idx = 0;
635                 gboolean is_used = FALSE;
636                 for (used_idx = 0; used_idx < sat_used; used_idx++) {
637                         if ((guint) prn == (guint) g_array_index(u_prn, guint, used_idx)) {
638                                 is_used = TRUE;
639                                 break;
640                         }
641                 }
642                 location_satellite_set_satellite_details(*satellite, idx,
643                                                          (guint) prn, is_used, (guint) elev, (guint) azim, (guint) snr);
644         }
645
646         if (u_prn)
647                 g_array_free(u_prn, TRUE);
648         if (sat_info)
649                 g_ptr_array_free(sat_info, TRUE);
650
651         g_object_unref(last_sat);
652         g_free (service);
653         g_free (path);
654         
655         return LOCATION_ERROR_NONE;
656 }
657
658 static int set_devname(gpointer handle, const char *devname)
659 {
660         GpsManagerData *gps_manager = (GpsManagerData *) handle;
661         g_return_val_if_fail(gps_manager, LOCATION_ERROR_NOT_AVAILABLE);
662         g_return_val_if_fail(gps_manager->devname, LOCATION_ERROR_NOT_AVAILABLE);
663         g_return_val_if_fail(devname, LOCATION_ERROR_PARAMETER);
664         MOD_LOGD("set_devname: %s --> %s", gps_manager->devname, devname);
665         g_stpcpy(gps_manager->devname, devname);
666
667         return LOCATION_ERROR_NONE;
668 }
669
670 static int get_devname(gpointer handle, char **devname)
671 {
672         GpsManagerData *gps_manager = (GpsManagerData *) handle;
673         g_return_val_if_fail(gps_manager, LOCATION_ERROR_NOT_AVAILABLE);
674         g_return_val_if_fail(gps_manager->devname, LOCATION_ERROR_NOT_AVAILABLE);
675         g_return_val_if_fail(devname, LOCATION_ERROR_PARAMETER);
676         *devname = g_strdup(gps_manager->devname);
677         MOD_LOGD("get_devname: %s", *devname);
678
679         return LOCATION_ERROR_NONE;
680 }
681
682 LOCATION_MODULE_API gpointer init(LocModGpsOps * ops)
683 {
684         MOD_LOGD("init");
685
686         g_return_val_if_fail(ops, NULL);
687         ops->start = start;
688         ops->stop = stop;
689         ops->get_position = get_position;
690         ops->get_velocity = get_velocity;
691         ops->get_last_position = get_last_position;
692         ops->get_last_velocity = get_last_velocity;
693
694         Dl_info info;
695         if (dladdr(&get_position, &info) == 0) {
696                 MOD_LOGD("Failed to get module name");
697         } else if (g_strrstr(info.dli_fname, "gps")) {
698                 ops->get_nmea = get_nmea;
699                 ops->get_satellite = get_satellite;
700                 ops->get_last_satellite = get_last_satellite;
701                 ops->set_devname = set_devname;
702                 ops->get_devname = get_devname;
703         }
704
705         GpsManagerData *gps_manager = g_new0(GpsManagerData, 1);
706         g_return_val_if_fail(gps_manager, NULL);
707
708         g_stpcpy(gps_manager->devname, "/dev/ttySAC1");
709         gps_manager->pos = NULL;
710         gps_manager->vel = NULL;
711         gps_manager->nmea = NULL;
712         gps_manager->sat = NULL;
713         gps_manager->status_cb = NULL;
714         gps_manager->pos_cb = NULL;
715         gps_manager->vel_cb = NULL;
716         gps_manager->userdata = NULL;
717         gps_manager->is_started = FALSE;
718
719         return (gpointer) gps_manager;
720 }
721
722 LOCATION_MODULE_API void shutdown(gpointer handle)
723 {
724         MOD_LOGD("shutdown");
725         g_return_if_fail(handle);
726         GpsManagerData *gps_manager = (GpsManagerData *) handle;
727
728         unref_gps_manager(gps_manager);
729         if (gps_manager->status_cb)
730                 gps_manager->status_cb(FALSE, LOCATION_STATUS_NO_FIX, gps_manager->userdata);
731         g_free(gps_manager);
732 }