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