Release Tizen2.0 beta
[framework/location/gps-manager.git] / gps-manager / 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 <config.h>
23
24 #include <string.h>
25 #include <time.h>
26 #include <stdlib.h>
27
28 #include <glib.h>
29 #include <glib-object.h>
30
31 #include <dbus/dbus.h>
32 #include <dbus/dbus-glib-bindings.h>
33 #include <dbus/dbus-glib-lowlevel.h>
34
35 #include <geoclue/gc-provider.h>
36 #include <geoclue/geoclue-error.h>
37 #include <geoclue/gc-iface-position.h>
38 #include <geoclue/gc-iface-velocity.h>
39 #include <geoclue/gc-iface-nmea.h>
40 #include <geoclue/gc-iface-satellite.h>
41 #include "gps_manager_data_types.h"
42 #include "gps_manager.h"
43
44 #include "server.h"
45 #include "last_position.h"
46 #include "debug_util.h"
47
48 #define GEOCLUE_GPSMANAGER_DBUS_SERVICE "org.freedesktop.Geoclue.Providers.GpsManager"
49 #define GEOCLUE_GPSMANAGER_DBUS_PATH    "/org/freedesktop/Geoclue/Providers/GpsManager"
50
51 typedef struct {
52         GcProvider parent;
53         GMainLoop *loop;
54         GMutex *mutex;
55
56         GeoclueStatus status;
57         pos_data_t position;
58         sv_data_t satellite;
59         nmea_data_t nmea;
60
61         pos_data_t last_position;
62         sv_data_t last_satellite;
63
64         gboolean is_running;
65         gint client_count;
66 } GeoclueGpsManager;
67
68 typedef struct {
69         GcProviderClass parent_class;
70 } GeoclueGpsManagerClass;
71
72 #define GEOCLUE_TYPE_GPSMANAGER (geoclue_gpsmanager_get_type ())
73 #define GEOCLUE_GPSMANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEOCLUE_TYPE_GPSMANAGER, GeoclueGpsManager))
74
75 static void init_position(GcIfacePositionClass * iface);
76 static void init_velocity(GcIfaceVelocityClass * iface);
77 static void init_nmea(GcIfaceNmeaClass * iface);
78 static void init_satellite(GcIfaceSatelliteClass * iface);
79 static void init_geoclue(GcIfaceGeoclueClass * iface);
80
81 G_DEFINE_TYPE_WITH_CODE(GeoclueGpsManager, geoclue_gpsmanager, GC_TYPE_PROVIDER,
82                         G_IMPLEMENT_INTERFACE(GC_TYPE_IFACE_POSITION, init_position)
83                         G_IMPLEMENT_INTERFACE(GC_TYPE_IFACE_VELOCITY, init_velocity)
84                         G_IMPLEMENT_INTERFACE(GC_TYPE_IFACE_NMEA, init_nmea)
85                         G_IMPLEMENT_INTERFACE(GC_TYPE_IFACE_SATELLITE, init_satellite)
86                         G_IMPLEMENT_INTERFACE(GC_TYPE_IFACE_GEOCLUE, init_geoclue));
87
88 static GObject* constructor (GType type, guint n_props, GObjectConstructParam *props)
89 {
90         GObject *object;
91
92         object = ((GObjectClass *) geoclue_gpsmanager_parent_class)->constructor(type, n_props, props);
93
94         return object;
95 }
96
97 static void finalize(GObject * object)
98 {
99         ((GObjectClass *) geoclue_gpsmanager_parent_class)->finalize(object);
100 }
101
102 static void dispose(GObject * object)
103 {
104         GeoclueGpsManager *gpsmanager = GEOCLUE_GPSMANAGER(object);
105         g_mutex_free(gpsmanager->mutex);
106         ((GObjectClass *) geoclue_gpsmanager_parent_class)->dispose(object);
107 }
108
109 static gboolean get_status(GcIfaceGeoclue * gc, GeoclueStatus * status, GError ** error)
110 {
111         GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
112
113         *status = gpsmanager->status;
114
115         return TRUE;
116 }
117
118 static gboolean get_provider_info(GcIfaceGeoclue * geoclue, gchar ** name, gchar ** description, GError ** error)
119 {
120         if (name) {
121                 *name = g_strdup("geoclue-gpsmanager");
122         }
123         if (description) {
124                 *description = g_strdup("Geoclue-gpsmanager");
125         }
126         return TRUE;
127 }
128
129 static void start_tracking(GeoclueGpsManager * gpsmanager)
130 {
131         LOG_GPS(DBG_LOW, "start_tracking");
132         gpsmanager->status = GEOCLUE_STATUS_ACQUIRING;
133         g_mutex_lock(gpsmanager->mutex);
134         if (request_start_session() == TRUE) {
135                 gpsmanager->is_running = TRUE;
136         } else {
137                 LOG_GPS(DBG_ERR, "Fail to request_start_session");
138         }
139         g_mutex_unlock(gpsmanager->mutex);
140 }
141
142 static void stop_tracking(GeoclueGpsManager * gpsmanager)
143 {
144         LOG_GPS(DBG_LOW, "stop_tracking");
145         g_mutex_lock(gpsmanager->mutex);
146         if (request_stop_session() == TRUE) {
147                 gpsmanager->is_running = FALSE;
148         }
149         g_mutex_unlock(gpsmanager->mutex);
150         gpsmanager->status = GEOCLUE_STATUS_UNAVAILABLE;
151 }
152
153 static gboolean set_options(GcIfaceGeoclue * gc, GHashTable * options, GError ** error)
154 {
155         LOG_GPS(DBG_LOW, "set_options");
156
157         GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
158         gchar *value = NULL;
159
160         value = g_hash_table_lookup(options, "CMD");
161
162         if (value) {
163                 if (!g_strcmp0(value, "START")) {
164                         g_mutex_lock(gpsmanager->mutex);
165                         gpsmanager->client_count++;
166                         g_mutex_unlock(gpsmanager->mutex);
167
168                         if (gpsmanager->is_running == TRUE) {
169                                 LOG_GPS(DBG_LOW, "gps-manager is already running");
170                                 return TRUE;
171                         }
172                         start_tracking(gpsmanager);
173                 } else if (!g_strcmp0(value, "STOP")) {
174                         g_mutex_lock(gpsmanager->mutex);
175                         gpsmanager->client_count--;
176                         g_mutex_unlock(gpsmanager->mutex);
177
178                         if (gpsmanager->is_running == FALSE) {
179                                 return TRUE;
180                         }
181                         if (gpsmanager->client_count <= 0 ) {
182                                 stop_tracking(gpsmanager);
183                         }
184                 }
185         }
186         return TRUE;
187 }
188
189 static gboolean remove_all_clients(GeoclueGpsManager * gpsmanager)
190 {
191         if (gpsmanager->client_count <= 0) {
192                 return FALSE;
193         }
194
195         gpsmanager->client_count = 0;
196         stop_tracking(gpsmanager);
197
198         return TRUE;
199 }
200
201 static void shutdown(GcProvider * provider)
202 {
203         GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(provider));
204
205         if (gpsmanager->is_running) {
206                 if (remove_all_clients(gpsmanager)) {
207                         LOG_GPS(DBG_ERR, "<<<< Abnormal shutdown >>>>");
208                 }
209         }
210 }
211
212 static void update_position_cb(pos_data_t * pos, gps_error_t error, void *user_data)
213 {
214         GeocluePositionFields fields;
215         GeoclueAccuracy *accuracy;
216
217         GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(user_data));
218         memcpy(&gpsmanager->position, pos, sizeof(pos_data_t));
219         memcpy(&gpsmanager->last_position, pos, sizeof(pos_data_t));
220
221         gpsmanager->status = GEOCLUE_STATUS_AVAILABLE;
222
223         accuracy = geoclue_accuracy_new(GEOCLUE_ACCURACY_LEVEL_DETAILED, pos->hor_accuracy, pos->ver_accuracy);
224
225         fields = (GEOCLUE_VELOCITY_FIELDS_SPEED | GEOCLUE_VELOCITY_FIELDS_DIRECTION);
226         gc_iface_velocity_emit_velocity_changed(GC_IFACE_VELOCITY(gpsmanager),
227                                                 fields, pos->timestamp, pos->speed, pos->bearing, 0.0);
228
229         fields = (GEOCLUE_POSITION_FIELDS_LATITUDE | GEOCLUE_POSITION_FIELDS_LONGITUDE | GEOCLUE_POSITION_FIELDS_ALTITUDE);
230         gc_iface_position_emit_position_changed(GC_IFACE_POSITION(gpsmanager),
231                                                 fields, pos->timestamp, pos->latitude, pos->longitude, pos->altitude, accuracy);
232
233         geoclue_accuracy_free(accuracy);
234
235         gc_iface_geoclue_emit_status_changed(GC_IFACE_GEOCLUE(gpsmanager), GEOCLUE_STATUS_AVAILABLE);
236 }
237
238 static void update_satellite_cb(sv_data_t * sv, void *user_data)
239 {
240         int index;
241         int timestamp = 0;
242         int satellite_used = 0;
243         GArray *used_prn;
244         GPtrArray *satellite_info;
245
246         GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(user_data));
247         memcpy(&gpsmanager->satellite, sv, sizeof(sv_data_t));
248         memcpy(&gpsmanager->last_satellite, sv, sizeof(sv_data_t));
249         timestamp = sv->timestamp;
250
251         used_prn = g_array_new(FALSE, FALSE, sizeof(guint));
252         for (index = 0; index < sv->num_of_sat; ++index) {
253                 if (sv->sat[index].used) {
254                         g_array_append_val(used_prn, sv->sat[index].prn);
255                         ++satellite_used;
256                 }
257         }
258
259         satellite_info = g_ptr_array_new();
260
261         for (index = 0; index < sv->num_of_sat; ++index) {
262                 GValue sv_info = { 0, };
263                 g_value_init(&sv_info, GEOCLUE_SATELLITE_INFO);
264                 g_value_take_boxed(&sv_info, dbus_g_type_specialized_construct(GEOCLUE_SATELLITE_INFO));
265                 dbus_g_type_struct_set(&sv_info, 0, sv->sat[index].prn, 1,
266                                        sv->sat[index].elevation, 2, sv->sat[index].azimuth, 3, sv->sat[index].snr, G_MAXUINT);
267                 g_ptr_array_add(satellite_info, g_value_get_boxed(&sv_info));
268         }
269
270         gc_iface_satellite_emit_satellite_changed(GC_IFACE_SATELLITE
271                                                   (gpsmanager), timestamp,
272                                                   satellite_used, sv->num_of_sat, used_prn, satellite_info);
273
274         g_array_free(used_prn, TRUE);
275         g_ptr_array_free(satellite_info, TRUE);
276 }
277
278 static void update_nmea_cb(nmea_data_t * nmea, void *user_data)
279 {
280         int timestamp = 0;
281
282         GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(user_data));
283
284         gpsmanager->nmea.data = g_malloc(nmea->len + 1);
285         g_memmove(gpsmanager->nmea.data, nmea->data, nmea->len);
286         gpsmanager->nmea.data[nmea->len] = '\0';
287
288         timestamp = gpsmanager->position.timestamp;
289
290         gc_iface_nmea_emit_nmea_changed(GC_IFACE_NMEA(gpsmanager), timestamp, gpsmanager->nmea.data);
291
292         g_free(gpsmanager->nmea.data);
293 }
294
295 static void geoclue_gpsmanager_class_init(GeoclueGpsManagerClass * klass)
296 {
297         GObjectClass *o_class = (GObjectClass *) klass;
298         GcProviderClass *p_class = (GcProviderClass *) klass;
299
300         o_class->constructor = constructor;
301         o_class->finalize = finalize;
302         o_class->dispose = dispose;
303         p_class->get_status = get_status;
304         p_class->set_options = set_options;
305         p_class->shutdown = shutdown;
306 }
307
308 static void geoclue_gpsmanager_init(GeoclueGpsManager * gpsmanager)
309 {
310         LOG_GPS(DBG_LOW, "geoclue_gpsmanager_init");
311
312         gpsmanager->status = GEOCLUE_STATUS_UNAVAILABLE;
313         gpsmanager->mutex = g_mutex_new();
314
315         memset(&gpsmanager->position, 0x00, sizeof(pos_data_t));
316         memset(&gpsmanager->satellite, 0x00, sizeof(sv_data_t));
317         memset(&gpsmanager->nmea, 0x00, sizeof(nmea_data_t));
318         memset(&gpsmanager->last_position, 0x00, sizeof(pos_data_t));
319         memset(&gpsmanager->last_satellite, 0x00, sizeof(sv_data_t));
320
321         gpsmanager->is_running = FALSE;
322         gpsmanager->client_count = 0;
323
324         gc_provider_set_details(GC_PROVIDER(gpsmanager), GEOCLUE_GPSMANAGER_DBUS_SERVICE, GEOCLUE_GPSMANAGER_DBUS_PATH, "gps-manager", "GPS Manager");
325
326         gps_manager_get_last_position(&gpsmanager->last_position);
327 }
328
329 static gboolean get_position(GcIfacePosition * gc,
330                              GeocluePositionFields * fields,
331                              int *timestamp,
332                              double *latitude,
333                              double *longitude, double *altitude, GeoclueAccuracy ** accuracy, GError ** error)
334 {
335         GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
336
337         if (gpsmanager->status == GEOCLUE_STATUS_ACQUIRING) {
338                 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_NOT_AVAILABLE, "ERROR: Acquiring");
339                 return FALSE;
340         }
341
342         if (gpsmanager->status != GEOCLUE_STATUS_AVAILABLE) {
343                 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_FAILED, "ERROR: Not Available");
344                 return FALSE;
345         }
346
347         if (!fields) {
348                 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_FAILED, "ERROR: Invalid parameters");
349                 return FALSE;
350         }
351
352         *fields = GEOCLUE_POSITION_FIELDS_NONE;
353
354         if (timestamp) {
355                 *timestamp = gpsmanager->position.timestamp;
356         }
357
358         if (latitude) {
359                 *fields |= GEOCLUE_POSITION_FIELDS_LATITUDE;
360                 *latitude = gpsmanager->position.latitude;
361         }
362
363         if (longitude) {
364                 *fields |= GEOCLUE_POSITION_FIELDS_LONGITUDE;
365                 *longitude = gpsmanager->position.longitude;
366         }
367
368         if (altitude) {
369                 *fields |= GEOCLUE_POSITION_FIELDS_ALTITUDE;
370                 *altitude = gpsmanager->position.altitude;
371         }
372
373         if (accuracy) {
374                 *accuracy =
375                     geoclue_accuracy_new(GEOCLUE_ACCURACY_LEVEL_DETAILED,
376                                          gpsmanager->position.hor_accuracy, gpsmanager->position.ver_accuracy);
377         }
378
379         return TRUE;
380 }
381
382 static gboolean get_last_position(GcIfacePosition * gc,
383                                   GeocluePositionFields * fields,
384                                   int *timestamp, double *latitude,
385                                   double *longitude, double *altitude, GeoclueAccuracy ** accuracy, GError ** error)
386 {
387         GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
388
389         if (!fields) {
390                 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_FAILED, "ERROR: Invalid parameters");
391                 return FALSE;
392         }
393
394         *fields = GEOCLUE_POSITION_FIELDS_NONE;
395
396         if (timestamp) {
397                 *timestamp = gpsmanager->last_position.timestamp;
398         }
399
400         if (latitude) {
401                 *fields |= GEOCLUE_POSITION_FIELDS_LATITUDE;
402                 *latitude = gpsmanager->last_position.latitude;
403         }
404
405         if (longitude) {
406                 *fields |= GEOCLUE_POSITION_FIELDS_LONGITUDE;
407                 *longitude = gpsmanager->last_position.longitude;
408         }
409
410         if (altitude) {
411                 *fields |= GEOCLUE_POSITION_FIELDS_ALTITUDE;
412                 *altitude = gpsmanager->last_position.altitude;
413
414         }
415
416         if (accuracy) {
417                 *accuracy =
418                     geoclue_accuracy_new(GEOCLUE_ACCURACY_LEVEL_DETAILED,
419                                          gpsmanager->last_position.hor_accuracy, gpsmanager->last_position.ver_accuracy);
420         }
421
422         return TRUE;
423 }
424
425 static gboolean get_velocity(GcIfaceVelocity * gc,
426                              GeoclueVelocityFields * fields,
427                              int *timestamp, double *speed, double *direction, double *climb, GError ** error)
428 {
429         GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
430
431         if (gpsmanager->status == GEOCLUE_STATUS_ACQUIRING) {
432                 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_NOT_AVAILABLE, "ERROR: Acquiring");
433                 return FALSE;
434         }
435
436         if (gpsmanager->status != GEOCLUE_STATUS_AVAILABLE) {
437                 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_FAILED, "ERROR: Not Available");
438                 return FALSE;
439         }
440
441         if (!fields) {
442                 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_FAILED, "ERROR: Invalid parameters");
443                 return FALSE;
444         }
445
446         *fields = GEOCLUE_VELOCITY_FIELDS_NONE;
447
448         if (timestamp) {
449                 *timestamp = gpsmanager->position.timestamp;
450         }
451
452         if (speed) {
453                 *fields |= GEOCLUE_VELOCITY_FIELDS_SPEED;
454                 *speed = gpsmanager->position.speed;
455         }
456
457         if (direction) {
458                 *fields |= GEOCLUE_VELOCITY_FIELDS_DIRECTION;
459                 *direction = gpsmanager->position.bearing;
460         }
461
462         /* A climb field does not supported because of poor accuracy. */
463
464         return TRUE;
465 }
466
467 static gboolean get_last_velocity(GcIfaceVelocity * gc,
468                                   GeoclueVelocityFields * fields,
469                                   int *timestamp, double *speed, double *direction, double *climb, GError ** error)
470 {
471         GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
472
473         if (!fields) {
474                 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_FAILED, "ERROR: Invalid parameters");
475                 return FALSE;
476         }
477
478         *fields = GEOCLUE_VELOCITY_FIELDS_NONE;
479
480         if (timestamp) {
481                 *timestamp = gpsmanager->last_position.timestamp;
482         }
483
484         if (speed) {
485                 *fields |= GEOCLUE_VELOCITY_FIELDS_SPEED;
486                 *speed = gpsmanager->last_position.speed;
487         }
488
489         if (direction) {
490                 *fields |= GEOCLUE_VELOCITY_FIELDS_DIRECTION;
491                 *direction = gpsmanager->last_position.bearing;
492         }
493
494         return TRUE;
495 }
496
497 static gboolean get_nmea(GcIfaceNmea * gc, int *timestamp, char **nmea_data, GError ** error)
498 {
499         GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
500
501         if (gpsmanager->status == GEOCLUE_STATUS_UNAVAILABLE || gpsmanager->status == GEOCLUE_STATUS_ERROR) {
502                 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_FAILED, "ERROR: Not Available");
503                 return FALSE;
504         }
505
506         if (timestamp) {
507                 *timestamp = gpsmanager->position.timestamp;
508         }
509
510         if (nmea_data) {
511                 *nmea_data = g_memdup(gpsmanager->nmea.data, gpsmanager->nmea.len);
512         }
513
514         return TRUE;
515 }
516
517 static gboolean get_satellite(GcIfaceSatellite * gc,
518                               int *timestamp,
519                               int *satellite_used,
520                               int *satellite_visible, GArray ** used_prn, GPtrArray ** satellite_info, GError ** error)
521 {
522         GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
523
524         if (gpsmanager->status == GEOCLUE_STATUS_UNAVAILABLE || gpsmanager->status == GEOCLUE_STATUS_ERROR) {
525                 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_FAILED, "ERROR: Not Available");
526                 return FALSE;
527         }
528
529         if (timestamp) {
530                 *timestamp = gpsmanager->satellite.timestamp;
531         }
532
533         if (satellite_used) {
534                 int index;
535                 int count = 0;
536                 for (index = 0; index < gpsmanager->satellite.num_of_sat; ++index) {
537                         count += gpsmanager->satellite.sat[index].used ? 1 : 0;
538                 }
539                 *satellite_used = count;
540         }
541
542         if (satellite_visible) {
543                 *satellite_visible = gpsmanager->satellite.num_of_sat;
544         }
545
546         if (used_prn) {
547                 int index;
548                 *used_prn = g_array_new(FALSE, FALSE, sizeof(guint));
549
550                 for (index = 0; index < gpsmanager->satellite.num_of_sat; ++index) {
551                         if (gpsmanager->satellite.sat[index].used) {
552                                 g_array_append_val(*used_prn, gpsmanager->satellite.sat[index].prn);
553                         }
554                 }
555         }
556
557         if (satellite_info) {
558                 int index;
559                 *satellite_info = g_ptr_array_new();
560                 for (index = 0; index < gpsmanager->satellite.num_of_sat; ++index) {
561                         GValue sv_info = { 0, };
562                         g_value_init(&sv_info, GEOCLUE_SATELLITE_INFO);
563                         g_value_take_boxed(&sv_info, dbus_g_type_specialized_construct(GEOCLUE_SATELLITE_INFO));
564                         dbus_g_type_struct_set(&sv_info,
565                                         0, gpsmanager->satellite.sat[index].prn,
566                                         1, gpsmanager->satellite.sat[index].elevation,
567                                         2, gpsmanager->satellite.sat[index].azimuth,
568                                         3, gpsmanager->satellite.sat[index].snr, G_MAXUINT);
569                         g_ptr_array_add(*satellite_info, g_value_get_boxed(&sv_info));
570                 }
571         }
572         return TRUE;
573 }
574
575 static gboolean get_last_satellite(GcIfaceSatellite * gc,
576                                    int *timestamp, int *satellite_used,
577                                    int *satellite_visible, GArray ** used_prn, GPtrArray ** satellite_info, GError ** error)
578 {
579         GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
580
581         if (timestamp) {
582                 *timestamp = gpsmanager->last_satellite.timestamp;
583         }
584
585         if (satellite_used) {
586                 int index;
587                 int count = 0;
588                 for (index = 0; index < gpsmanager->last_satellite.num_of_sat; ++index) {
589                         count += gpsmanager->last_satellite.sat[index].used ? 1 : 0;
590                 }
591                 *satellite_used = count;
592         }
593
594         if (satellite_visible) {
595                 *satellite_visible = gpsmanager->last_satellite.num_of_sat;
596         }
597
598         if (used_prn) {
599                 int index;
600                 *used_prn = g_array_new(FALSE, FALSE, sizeof(guint));
601
602                 for (index = 0; index < gpsmanager->last_satellite.num_of_sat; ++index) {
603                         if (gpsmanager->last_satellite.sat[index].used) {
604                                 g_array_append_val(*used_prn, gpsmanager->last_satellite.sat[index].prn);
605                         }
606                 }
607         }
608
609         if (satellite_info) {
610                 int index;
611                 *satellite_info = g_ptr_array_new();
612                 for (index = 0; index < gpsmanager->last_satellite.num_of_sat; ++index) {
613                         GValue sv_info = { 0, };
614                         g_value_init(&sv_info, GEOCLUE_SATELLITE_INFO);
615                         g_value_take_boxed(&sv_info, dbus_g_type_specialized_construct(GEOCLUE_SATELLITE_INFO));
616                         dbus_g_type_struct_set(&sv_info, 0,
617                                                gpsmanager->last_satellite.sat[index].prn, 1,
618                                                gpsmanager->last_satellite.sat[index].elevation, 2,
619                                                gpsmanager->last_satellite.sat[index].azimuth, 3,
620                                                gpsmanager->last_satellite.sat[index].snr, G_MAXUINT);
621                         g_ptr_array_add(*satellite_info, g_value_get_boxed(&sv_info));
622                 }
623
624         }
625         return TRUE;
626 }
627
628 static void init_position(GcIfacePositionClass * iface)
629 {
630         iface->get_position = get_position;
631         iface->get_last_position = get_last_position;
632 }
633
634 static void init_velocity(GcIfaceVelocityClass * iface)
635 {
636         iface->get_velocity = get_velocity;
637         iface->get_last_velocity = get_last_velocity;
638 }
639
640 static void init_nmea(GcIfaceNmeaClass * iface)
641 {
642         iface->get_nmea = get_nmea;
643 }
644
645 static void init_satellite(GcIfaceSatelliteClass * iface)
646 {
647         iface->get_satellite = get_satellite;
648         iface->get_last_satellite = get_last_satellite;
649 }
650
651 static void init_geoclue(GcIfaceGeoclueClass * iface)
652 {
653         iface->get_provider_info = get_provider_info;
654 }
655
656 int main(int argc, char **argv)
657 {
658         GeoclueGpsManager *gpsmanager;
659         struct gps_callbacks cb;
660         cb.pos_cb = update_position_cb;
661         cb.sv_cb = update_satellite_cb;
662         cb.nmea_cb = update_nmea_cb;
663
664 #if !GLIB_CHECK_VERSION (2, 31, 0)
665         if (!g_thread_supported()) {
666                 g_thread_init(NULL);
667         }
668 #endif
669
670         dbus_g_thread_init();
671         g_type_init();
672
673         initialize_server(argc, argv);
674
675         gpsmanager = g_object_new(GEOCLUE_TYPE_GPSMANAGER, NULL);
676         register_update_callbacks(&cb, gpsmanager);
677
678         gpsmanager->loop = g_main_loop_new(NULL, TRUE);
679         g_main_loop_run(gpsmanager->loop);
680
681         g_main_loop_unref(gpsmanager->loop);
682         g_object_unref(gpsmanager);
683
684         deinitialize_server();
685
686         return 0;
687 }