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