tizen beta release
[platform/core/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 <location-module.h>
25
26 #include <geoclue/geoclue-position.h>
27 #include <geoclue/geoclue-velocity.h>
28 #include <geoclue/geoclue-satellite.h>
29 #include <geoclue/geoclue-nmea.h>
30 #include <geoclue/geoclue-provider.h>
31 #include <dlfcn.h>
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include "log.h"
38
39 typedef struct{
40         char              devname[256];
41         GeocluePosition  *pos;
42         GeoclueVelocity  *vel;
43         GeoclueNmea      *nmea;
44         GeoclueSatellite *sat;
45         LocModStatusCB    status_cb;
46         LocModPositionCB  pos_cb;
47         LocModVelocityCB  vel_cb;
48         gpointer          userdata;
49         gboolean          is_started;
50 } GpsManagerData;
51
52 static void
53 status_callback (GeoclueProvider *provider,
54                  gint             status,
55                  gpointer         userdata)
56 {
57         GpsManagerData* gps_manager = (GpsManagerData*)userdata;
58         g_return_if_fail (gps_manager);
59         g_return_if_fail (gps_manager->status_cb);
60
61         switch(status){
62                 case GEOCLUE_STATUS_ERROR:
63                 case GEOCLUE_STATUS_UNAVAILABLE:
64                 case GEOCLUE_STATUS_ACQUIRING:
65                         MOD_LOGD("GEOCLUE_STATUS_ACQUIRING/ERROR/UNAVAILABLE");
66                         gps_manager->status_cb(FALSE, LOCATION_STATUS_NO_FIX, gps_manager->userdata);
67                         break;
68                 case GEOCLUE_STATUS_AVAILABLE:
69                         MOD_LOGD("GEOCLUE_STATUS_AVAILABLE");
70                         gps_manager->status_cb(TRUE, LOCATION_STATUS_3D_FIX, gps_manager->userdata);
71                         break;
72                 default:
73                         break;
74                 }
75 }
76
77 static void
78 satellite_callback (GeoclueSatellite *satellite,
79                     int               timestamp,
80                     int               satellite_used,
81                     int               satellite_visible,
82                     GArray           *used_prn,
83                     GPtrArray        *sat_info,
84                     gpointer          userdata)
85 {
86         int idx;
87
88         MOD_LOGD("satellite_callback!!!\n");
89         MOD_LOGD("timestamp: %d", timestamp);
90         MOD_LOGD("satellite_used: %d", satellite_used);
91         MOD_LOGD("satellite_visible: %d", satellite_visible);
92
93         for (idx = 0; idx < satellite_used; idx++) {
94                 MOD_LOGD ("used_prn[%d] : %d", idx, g_array_index (used_prn, guint, idx));
95         }
96         for (idx = 0; idx < satellite_visible; idx++) {
97                 GValueArray *vals = (GValueArray*)g_ptr_array_index (sat_info, idx);
98                 gint prn = g_value_get_int (g_value_array_get_nth (vals, 0));
99                 gint elev = g_value_get_int (g_value_array_get_nth (vals, 1));
100                 gint azim = g_value_get_int (g_value_array_get_nth (vals, 2));
101                 gint snr = g_value_get_int (g_value_array_get_nth (vals, 3));
102                 MOD_LOGD ("visible_prn[%d] : elev %d azim %d snr %d", prn, elev, azim, snr);
103         }
104 }
105 static void
106 nmea_callback (GeoclueNmea *nmea,
107                int          timestamp,
108                char        *data,
109                gpointer     userdata)
110 {
111 }
112
113 static void
114 position_callback (GeocluePosition      *position,
115                    GeocluePositionFields fields,
116                    int                   timestamp,
117                    double                latitude,
118                    double                longitude,
119                    double                altitude,
120                    GeoclueAccuracy      *accuracy,
121                    gpointer              userdata)
122 {
123         GpsManagerData* gps_manager = (GpsManagerData*)userdata;
124         g_return_if_fail (gps_manager);
125         g_return_if_fail (gps_manager->pos_cb);
126
127         GeoclueAccuracyLevel level;
128         double horiz_acc;
129         double vert_acc;
130         geoclue_accuracy_get_details (accuracy, &level, &horiz_acc, &vert_acc);
131
132         LocationPosition *pos = NULL;
133         LocationAccuracy *acc = NULL;
134
135         if ((fields & GEOCLUE_POSITION_FIELDS_LATITUDE) &&
136             (fields & GEOCLUE_POSITION_FIELDS_LONGITUDE)) {
137                 if (fields & GEOCLUE_POSITION_FIELDS_ALTITUDE) {
138                         pos = location_position_new (timestamp,
139                                                      latitude,
140                                                      longitude,
141                                                      altitude,
142                                                      LOCATION_STATUS_3D_FIX);
143                 } else {
144                         pos = location_position_new (timestamp,
145                                                      latitude,
146                                                      longitude,
147                                                      0.0,
148                                                      LOCATION_STATUS_2D_FIX);
149                 }
150         } else {
151                 pos = location_position_new (0.0,
152                                              0.0,
153                                              0.0,
154                                              0.0,
155                                              LOCATION_STATUS_NO_FIX);
156         }
157
158         if (accuracy) {
159                 GeoclueAccuracyLevel level;
160                 double horiz_acc;
161                 double vert_acc;
162                 geoclue_accuracy_get_details (accuracy, &level, &horiz_acc, &vert_acc);
163                 acc = location_accuracy_new (LOCATION_ACCURACY_LEVEL_DETAILED, horiz_acc, vert_acc);
164         } else {
165                 acc = location_accuracy_new (LOCATION_ACCURACY_LEVEL_NONE, horiz_acc, vert_acc);
166         }
167
168         MOD_LOGD("time(%d) lat(%f) long(%f) alt(%f) status(%d) acc_level(%d) hoz_acc(%f) vert_acc(%f)",
169                 pos->timestamp, pos->latitude, pos->longitude, pos->altitude,  pos->status,
170                 acc->level, acc->horizontal_accuracy, acc->vertical_accuracy);
171
172         gps_manager->pos_cb(TRUE, pos, acc, gps_manager->userdata);
173         location_position_free (pos);
174         location_accuracy_free (acc);
175 }
176
177
178 static void
179 velocity_callback (GeoclueVelocity      *velocity,
180                    GeoclueVelocityFields fields,
181                    int                   timestamp,
182                    double                speed,
183                    double                direction,
184                    double                climb,
185                    gpointer              userdata)
186 {
187         GpsManagerData* gps_manager = (GpsManagerData*)userdata;
188         g_return_if_fail (gps_manager);
189         g_return_if_fail (gps_manager->vel_cb);
190
191         LocationVelocity *vel = NULL;
192         LocationAccuracy *acc = NULL;
193
194         if (fields & GEOCLUE_VELOCITY_FIELDS_SPEED &&
195                 fields & GEOCLUE_VELOCITY_FIELDS_DIRECTION) {
196                 if (fields & GEOCLUE_VELOCITY_FIELDS_CLIMB) vel = location_velocity_new (timestamp, speed, direction, climb);
197                 else vel = location_velocity_new (timestamp, speed, direction, 0);
198                 acc = location_accuracy_new (LOCATION_ACCURACY_LEVEL_DETAILED, 0, 0);
199         } else {
200                 vel = location_velocity_new (0, 0, 0, 0);
201                 acc = location_accuracy_new (LOCATION_ACCURACY_LEVEL_NONE, 0, 0);
202         }
203         MOD_LOGD("timestamp(%d) speed(%f) direction(%f) climb(%f) acc_level(%d) hoz_acc(%f) vert_acc(%f)",
204                 vel->timestamp, vel->speed, vel->direction, vel->climb,
205                 acc->level, acc->horizontal_accuracy, acc->vertical_accuracy);
206
207         gps_manager->vel_cb(TRUE, vel, acc, gps_manager->userdata);
208         location_velocity_free (vel);
209         location_accuracy_free (acc);
210 }
211
212 static void
213 unref_gps_manager(GpsManagerData* gps_manager)
214 {
215         if(gps_manager->pos) {
216                 g_signal_handlers_disconnect_by_func(G_OBJECT (GEOCLUE_PROVIDER(gps_manager->pos)), G_CALLBACK (status_callback), gps_manager);
217                 g_signal_handlers_disconnect_by_func(G_OBJECT (GEOCLUE_PROVIDER(gps_manager->pos)), G_CALLBACK (position_callback), gps_manager);
218                 g_object_unref (gps_manager->pos);
219                 gps_manager->pos = NULL;
220         }
221
222         if(gps_manager->vel){
223                 g_signal_handlers_disconnect_by_func(G_OBJECT (GEOCLUE_PROVIDER(gps_manager->vel)), G_CALLBACK (velocity_callback), gps_manager);
224                 g_object_unref (gps_manager->vel);
225                 gps_manager->vel = NULL;
226         }
227
228         if(gps_manager->nmea)   {
229                 g_object_unref (gps_manager->nmea);
230                 gps_manager->nmea = NULL;
231         }
232
233         if(gps_manager->sat)    {
234                 g_object_unref (gps_manager->sat);
235                 gps_manager->sat = NULL;
236         }
237         gps_manager->is_started = FALSE;
238 }
239
240 static gboolean
241 ref_gps_manager(GpsManagerData* gps_manager)
242 {
243         if(gps_manager->is_started == TRUE){
244                 MOD_LOGW ("gps-manager is alredy started");
245                 return TRUE;
246         }
247
248         gchar *service, *path;
249         service = g_strdup_printf ("org.freedesktop.Geoclue.Providers.GpsManager");
250         path = g_strdup_printf ("/org/freedesktop/Geoclue/Providers/GpsManager");
251         if(!gps_manager->pos){
252                 gps_manager->pos = geoclue_position_new (service, path);
253         }
254         if(!gps_manager->vel){
255                 gps_manager->vel = geoclue_velocity_new (service, path);
256         }
257         if(!gps_manager->nmea){
258                 gps_manager->nmea = geoclue_nmea_new (service, path);
259         }
260         if(!gps_manager->sat){
261                 gps_manager->sat = geoclue_satellite_new (service, path);
262         }
263         g_free (service);
264         g_free (path);
265         if (!gps_manager->pos || !gps_manager->vel || !gps_manager->nmea || !gps_manager->sat) {
266                 MOD_LOGW ("Error while creating Geoclue object.");
267                 unref_gps_manager(gps_manager);
268                 return FALSE;
269         }
270
271         gps_manager->is_started = TRUE;
272         int ret;
273         ret = g_signal_connect (G_OBJECT (GEOCLUE_PROVIDER(gps_manager->pos)), "status-changed", G_CALLBACK (status_callback), gps_manager);
274         g_debug ("gsignal_connect status-changed %d", ret);
275         ret = g_signal_connect (G_OBJECT (GEOCLUE_PROVIDER(gps_manager->pos)), "position-changed", G_CALLBACK (position_callback), gps_manager);
276         g_debug ("gsignal_connect position-changed %d", ret);
277         ret = g_signal_connect (G_OBJECT (GEOCLUE_PROVIDER(gps_manager->vel)), "velocity-changed", G_CALLBACK (velocity_callback), gps_manager);
278         g_debug ("gsignal_connect velocity-changed %d", ret);
279         ret = g_signal_connect (G_OBJECT (GEOCLUE_PROVIDER(gps_manager->sat)), "satellite-changed", G_CALLBACK (satellite_callback), gps_manager);
280         g_debug ("gsignal_connect satellite-changed %d", ret);
281         ret = g_signal_connect (G_OBJECT (GEOCLUE_PROVIDER(gps_manager->nmea)), "nmea-changed", G_CALLBACK (nmea_callback), gps_manager);
282         g_debug ("gsignal_connect nmea-changed %d", ret);
283
284         return TRUE;
285 }
286
287 static int
288 start (gpointer handle,
289        LocModStatusCB status_cb,
290        LocModPositionCB pos_cb,
291        LocModVelocityCB vel_cb,
292        gpointer userdata)
293 {
294         MOD_LOGD("start");
295         GpsManagerData* gps_manager = (GpsManagerData*)handle;
296         g_return_val_if_fail(gps_manager, LOCATION_ERROR_NOT_AVAILABLE);
297         g_return_val_if_fail(status_cb, LOCATION_ERROR_NOT_AVAILABLE);
298         g_return_val_if_fail(pos_cb, LOCATION_ERROR_NOT_AVAILABLE);
299         g_return_val_if_fail(vel_cb, LOCATION_ERROR_NOT_AVAILABLE);
300
301         gps_manager->status_cb = status_cb;
302         gps_manager->pos_cb = pos_cb;
303         gps_manager->vel_cb = vel_cb;
304         gps_manager->userdata = userdata;
305
306         if (!ref_gps_manager(gps_manager)) return LOCATION_ERROR_NOT_AVAILABLE;
307         return LOCATION_ERROR_NONE;
308 }
309
310 static int
311 stop(gpointer handle)
312 {
313         MOD_LOGD("stop");
314         GpsManagerData* gps_manager = (GpsManagerData*)handle;
315         g_return_val_if_fail(gps_manager, LOCATION_ERROR_NOT_AVAILABLE);
316         g_return_val_if_fail(gps_manager->status_cb, LOCATION_ERROR_NOT_AVAILABLE);
317         unref_gps_manager(gps_manager);
318         gps_manager->status_cb (FALSE, LOCATION_STATUS_NO_FIX, gps_manager->userdata);
319         return LOCATION_ERROR_NONE;
320 }
321
322 static int
323 get_position(gpointer handle,
324              LocationPosition **position,
325              LocationAccuracy **accuracy)
326 {
327         MOD_LOGD("get_position");
328         GpsManagerData* gps_manager = (GpsManagerData*)handle;
329         g_return_val_if_fail(gps_manager, LOCATION_ERROR_NOT_AVAILABLE);
330         g_return_val_if_fail(gps_manager->pos, LOCATION_ERROR_NOT_AVAILABLE);
331         g_return_val_if_fail(position, LOCATION_ERROR_PARAMETER);
332         g_return_val_if_fail(accuracy, LOCATION_ERROR_PARAMETER);
333
334         GeocluePositionFields fields;
335         int timestamp;
336         double lat, lon, alt;
337         GeoclueAccuracy *_accuracy = NULL;
338         GError *error = NULL;
339
340         fields = geoclue_position_get_position (gps_manager->pos, &timestamp,
341                                                 &lat, &lon, &alt,
342                                                 &_accuracy, &error);
343         if (error) {
344                 MOD_LOGD ("Error getting position: %s", error->message);
345                 g_error_free (error);
346                 return LOCATION_ERROR_NOT_AVAILABLE;
347         }
348
349         if (fields & GEOCLUE_POSITION_FIELDS_LATITUDE &&
350                 fields & GEOCLUE_POSITION_FIELDS_LONGITUDE) {
351                 if(fields & GEOCLUE_POSITION_FIELDS_ALTITUDE) *position = location_position_new (timestamp, lat, lon, alt, LOCATION_STATUS_3D_FIX);
352                 else *position = location_position_new (timestamp, lat, lon, 0, LOCATION_STATUS_2D_FIX);
353         } else *position = location_position_new (0, 0, 0, 0, LOCATION_STATUS_NO_FIX);
354
355         if (_accuracy) {
356                 GeoclueAccuracyLevel level;
357                 double horiz_acc;
358                 double vert_acc;
359                 geoclue_accuracy_get_details (_accuracy, &level, &horiz_acc, &vert_acc);
360                 *accuracy = location_accuracy_new (LOCATION_ACCURACY_LEVEL_DETAILED, horiz_acc, vert_acc);
361                 geoclue_accuracy_free (_accuracy);
362         } else *accuracy = location_accuracy_new (LOCATION_ACCURACY_LEVEL_NONE, 0, 0);
363
364         return LOCATION_ERROR_NONE;
365 }
366
367 static int
368 get_velocity(gpointer           handle,
369              LocationVelocity **velocity,
370              LocationAccuracy **accuracy)
371 {
372         MOD_LOGD("get_velocity");
373         GpsManagerData* gps_manager = (GpsManagerData*)handle;
374         g_return_val_if_fail(gps_manager, LOCATION_ERROR_NOT_AVAILABLE);
375         g_return_val_if_fail(gps_manager->vel, LOCATION_ERROR_NOT_AVAILABLE);
376         g_return_val_if_fail(velocity, LOCATION_ERROR_PARAMETER);
377         g_return_val_if_fail(accuracy, LOCATION_ERROR_PARAMETER);
378
379         GeoclueVelocityFields fields;
380         int timestamp;
381         double spd, dir, climb;
382         GError *error = NULL;
383
384         fields = geoclue_velocity_get_velocity (gps_manager->vel, &timestamp,
385                                                 &spd, &dir, &climb,
386                                                 &error);
387         if (error) {
388                 MOD_LOGD ("Error getting velocity: %s", error->message);
389                 g_error_free (error);
390                 return LOCATION_ERROR_NOT_AVAILABLE;
391         }
392
393         if (fields & GEOCLUE_VELOCITY_FIELDS_SPEED &&
394                 fields & GEOCLUE_VELOCITY_FIELDS_DIRECTION) {
395                 if (fields & GEOCLUE_VELOCITY_FIELDS_CLIMB) *velocity = location_velocity_new (timestamp, spd, dir, climb);
396                 else *velocity = location_velocity_new (timestamp, spd, dir, 0);
397                 *accuracy = location_accuracy_new (LOCATION_ACCURACY_LEVEL_DETAILED, 0, 0);
398         } else {
399                 *velocity = location_velocity_new (0, 0, 0, 0);
400                 *accuracy = location_accuracy_new (LOCATION_ACCURACY_LEVEL_NONE, 0, 0);
401         }
402         return LOCATION_ERROR_NONE;
403 }
404
405 static int
406 get_nmea(gpointer handle,
407          gchar** nmea_data)
408 {
409         MOD_LOGD("get_nmea");
410         GpsManagerData* gps_manager = (GpsManagerData*)handle;
411         g_return_val_if_fail(gps_manager, LOCATION_ERROR_NOT_AVAILABLE);
412         g_return_val_if_fail(gps_manager->nmea, LOCATION_ERROR_NOT_AVAILABLE);
413         g_return_val_if_fail(nmea_data, LOCATION_ERROR_PARAMETER);
414
415         gboolean ret = FALSE;
416         int timestamp = 0;
417         char* _nmea_data = NULL;
418         GError *error = NULL;
419         ret = geoclue_nmea_get_nmea (gps_manager->nmea, &timestamp, &_nmea_data, &error);
420         if( !ret && error) {
421                 MOD_LOGD ("\t Error getting nmea: %s", error->message);
422                 g_error_free (error);
423                 return LOCATION_ERROR_NOT_AVAILABLE;
424         }
425         *nmea_data = g_strdup(_nmea_data);
426
427         return LOCATION_ERROR_NONE;
428 }
429
430 static int
431 get_satellite(gpointer handle,
432               LocationSatellite **satellite)
433 {
434         MOD_LOGD("get_satellite");
435         GpsManagerData* gps_manager = (GpsManagerData*)handle;
436         g_return_val_if_fail(gps_manager, LOCATION_ERROR_NOT_AVAILABLE);
437         g_return_val_if_fail(gps_manager->sat, LOCATION_ERROR_NOT_AVAILABLE);
438         g_return_val_if_fail(satellite, LOCATION_ERROR_PARAMETER);
439
440         int timestamp = 0;
441         int  idx = 0;
442         int sat_used = 0;
443         int sat_vis = 0;
444         GArray *u_prn = NULL;
445         GPtrArray *sat_info = NULL;
446         GError *error = NULL;
447
448         geoclue_satellite_get_satellite (gps_manager->sat, &timestamp, &sat_used, &sat_vis, &u_prn, &sat_info, &error);
449         if (error) {
450                 MOD_LOGW("\t Error getting satellite: %s", error->message);
451                 g_error_free (error);
452                 return LOCATION_ERROR_NOT_AVAILABLE;
453         }
454         *satellite = location_satellite_new (sat_vis);
455
456         for (idx=0; idx<sat_vis; idx++) {
457                 GValueArray *vals = (GValueArray*)g_ptr_array_index (sat_info, idx);
458                 gint prn = g_value_get_int (g_value_array_get_nth (vals, 0));
459                 gint elev = g_value_get_int (g_value_array_get_nth (vals, 1));
460                 gint azim = g_value_get_int (g_value_array_get_nth (vals, 2));
461                 gint snr = g_value_get_int (g_value_array_get_nth (vals, 3));
462
463                 int used_idx = 0;
464                 gboolean is_used = FALSE;
465                 for (used_idx = 0 ; used_idx < sat_used ; used_idx++) {
466                         if ((guint)prn == (guint)g_array_index(u_prn, guint, used_idx)) {
467                                 is_used = TRUE;
468                                 break;
469                         }
470                 }
471                 location_satellite_set_satellite_details(*satellite, idx, (guint)prn, is_used, (guint)elev, (guint)azim, (guint)snr);
472         }
473
474         if (u_prn)  g_array_free (u_prn, TRUE);
475         if (sat_info) g_ptr_array_free (sat_info, TRUE);
476
477         return LOCATION_ERROR_NONE;
478 }
479
480 static int
481 set_devname(gpointer    handle,
482             const char *devname)
483 {
484         GpsManagerData* gps_manager = (GpsManagerData*)handle;
485         g_return_val_if_fail(gps_manager, LOCATION_ERROR_NOT_AVAILABLE);
486         g_return_val_if_fail(gps_manager->devname, LOCATION_ERROR_NOT_AVAILABLE);
487         g_return_val_if_fail(devname, LOCATION_ERROR_PARAMETER);
488         MOD_LOGD("set_devname: %s --> %s", gps_manager->devname, devname);
489         g_stpcpy(gps_manager->devname, devname);
490
491         return LOCATION_ERROR_NONE;
492 }
493
494
495 static int
496 get_devname(gpointer handle,
497             char   **devname)
498 {
499         GpsManagerData* gps_manager = (GpsManagerData*)handle;
500         g_return_val_if_fail(gps_manager, LOCATION_ERROR_NOT_AVAILABLE);
501         g_return_val_if_fail(gps_manager->devname, LOCATION_ERROR_NOT_AVAILABLE);
502         g_return_val_if_fail(devname, LOCATION_ERROR_PARAMETER);
503         *devname = g_strdup(gps_manager->devname);
504         MOD_LOGD("get_devname: %s", *devname);
505
506         return LOCATION_ERROR_NONE;
507 }
508
509 LOCATION_MODULE_API gpointer
510 init(LocModGpsOps* ops)
511 {
512         MOD_LOGD("init");
513         g_return_val_if_fail(ops, NULL);
514         ops->start = start;
515         ops->stop = stop ;
516         ops->get_position = get_position;
517         ops->get_velocity = get_velocity;
518         Dl_info info;
519         if (dladdr(&get_position, &info) == 0) {
520                 MOD_LOGD ("Failed to get module name");
521         } else if (g_str_has_prefix(info.dli_fname, "gps")) {
522                 ops->get_nmea = get_nmea;
523                 ops->get_satellite = get_satellite;
524                 ops->set_devname = set_devname;
525                 ops->get_devname = get_devname;
526         }
527
528         GpsManagerData* gps_manager = g_new0(GpsManagerData, 1);
529         g_return_val_if_fail(gps_manager, NULL);
530
531         g_stpcpy(gps_manager->devname, "/dev/ttySAC1");
532         gps_manager->pos = NULL;
533         gps_manager->vel = NULL;
534         gps_manager->nmea = NULL;
535         gps_manager->sat = NULL;
536         gps_manager->status_cb= NULL;
537         gps_manager->pos_cb = NULL;
538         gps_manager->vel_cb = NULL;
539         gps_manager->userdata = NULL;
540         gps_manager->is_started = FALSE;
541
542         return (gpointer)gps_manager;
543 }
544
545 LOCATION_MODULE_API void
546 shutdown(gpointer handle)
547 {
548         MOD_LOGD("shutdown");
549         g_return_if_fail(handle);
550         GpsManagerData* gps_manager = (GpsManagerData*)handle;
551         unref_gps_manager(gps_manager);
552         if(gps_manager->status_cb) gps_manager->status_cb(FALSE, LOCATION_STATUS_NO_FIX, gps_manager->userdata);
553         g_free(gps_manager);
554 }