4 * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
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>
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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.
29 #include <glib-object.h>
31 #include <dbus/dbus.h>
32 #include <dbus/dbus-glib-bindings.h>
33 #include <dbus/dbus-glib-lowlevel.h>
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"
46 #define GEOCLUE_GPSMANAGER_DBUS_SERVICE "org.freedesktop.Geoclue.Providers.GpsManager"
47 #define GEOCLUE_GPSMANAGER_DBUS_PATH "/org/freedesktop/Geoclue/Providers/GpsManager"
58 GHashTable *connections;
62 GcProviderClass parent_class;
63 } GeoclueGpsManagerClass;
65 #define GEOCLUE_TYPE_GPSMANAGER (geoclue_gpsmanager_get_type ())
66 #define GEOCLUE_GPSMANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEOCLUE_TYPE_GPSMANAGER, GeoclueGpsManager))
68 static void init_position(GcIfacePositionClass * iface);
69 static void init_velocity(GcIfaceVelocityClass * iface);
70 static void init_nmea(GcIfaceNmeaClass * iface);
71 static void init_satellite(GcIfaceSatelliteClass * iface);
72 static void init_geoclue(GcIfaceGeoclueClass * iface);
74 G_DEFINE_TYPE_WITH_CODE(GeoclueGpsManager, geoclue_gpsmanager, GC_TYPE_PROVIDER,
75 G_IMPLEMENT_INTERFACE(GC_TYPE_IFACE_POSITION, init_position)
76 G_IMPLEMENT_INTERFACE(GC_TYPE_IFACE_VELOCITY, init_velocity)
77 G_IMPLEMENT_INTERFACE(GC_TYPE_IFACE_NMEA, init_nmea)
78 G_IMPLEMENT_INTERFACE(GC_TYPE_IFACE_SATELLITE, init_satellite)
79 G_IMPLEMENT_INTERFACE(GC_TYPE_IFACE_GEOCLUE, init_geoclue));
81 static void constructed(GObject * object)
83 GeoclueGpsManager *gps_manager = GEOCLUE_GPSMANAGER(object);
85 gps_manager->connections = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
87 gps_manager->status = GEOCLUE_STATUS_UNAVAILABLE;
89 memset(&gps_manager->position, 0x00, sizeof(pos_data_t));
90 memset(&gps_manager->satellite, 0x00, sizeof(sv_data_t));
91 memset(&gps_manager->nmea, 0x00, sizeof(nmea_data_t));
93 ((GObjectClass *) geoclue_gpsmanager_parent_class)->constructed(object);
96 static void finalize(GObject * object)
98 ((GObjectClass *) geoclue_gpsmanager_parent_class)->finalize(object);
101 static void dispose(GObject * object)
103 GeoclueGpsManager *gpsmanager = GEOCLUE_GPSMANAGER(object);
105 g_hash_table_destroy(gpsmanager->connections);
107 ((GObjectClass *) geoclue_gpsmanager_parent_class)->dispose(object);
110 static gboolean get_status(GcIfaceGeoclue * gc, GeoclueStatus * status, GError ** error)
112 GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
114 *status = gpsmanager->status;
119 static gboolean get_provider_info(GcIfaceGeoclue * geoclue, gchar ** name, gchar ** description, GError ** error)
122 *name = g_strdup("geoclue-gpsmanager");
125 *description = g_strdup("Geoclue-gpsmanager");
130 static void print_option(gpointer key, gpointer value, gpointer data)
132 g_print(" %s - %s\n", (char *)key, (char *)value);
135 static gboolean set_options(GcIfaceGeoclue * gc, GHashTable * options, GError ** error)
137 g_print("Options received---\n");
138 g_hash_table_foreach(options, print_option, NULL);
142 static void shutdown(GcProvider * provider)
147 static void start_tracking(GeoclueGpsManager * gpsmanager)
149 gpsmanager->status = GEOCLUE_STATUS_ACQUIRING;
150 request_start_session();
153 static void stop_tracking(GeoclueGpsManager * gpsmanager)
155 request_stop_session();
156 gpsmanager->status = GEOCLUE_STATUS_UNAVAILABLE;
159 static void update_position_cb(pos_data_t * pos, gps_error_t error, void *user_data)
161 GeocluePositionFields fields;
162 GeoclueAccuracy *accuracy;
164 GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(user_data));
165 memcpy(&gpsmanager->position, pos, sizeof(pos_data_t));
167 gpsmanager->status = GEOCLUE_STATUS_AVAILABLE;
169 fields = (GEOCLUE_POSITION_FIELDS_LATITUDE | GEOCLUE_POSITION_FIELDS_LONGITUDE | GEOCLUE_POSITION_FIELDS_ALTITUDE);
171 accuracy = geoclue_accuracy_new(GEOCLUE_ACCURACY_LEVEL_DETAILED, pos->hor_accuracy, pos->ver_accuracy);
173 gc_iface_position_emit_position_changed(GC_IFACE_POSITION(gpsmanager),
174 fields, pos->timestamp, pos->latitude, pos->longitude, pos->altitude, accuracy);
176 fields = (GEOCLUE_VELOCITY_FIELDS_SPEED | GEOCLUE_VELOCITY_FIELDS_DIRECTION);
178 gc_iface_velocity_emit_velocity_changed(GC_IFACE_VELOCITY(gpsmanager),
179 fields, pos->timestamp, pos->speed, pos->bearing, 0.0);
181 geoclue_accuracy_free(accuracy);
183 gc_iface_geoclue_emit_status_changed(GC_IFACE_GEOCLUE(gpsmanager), GEOCLUE_STATUS_AVAILABLE);
186 static void update_satellite_cb(sv_data_t * sv, void *user_data)
190 int satellite_used = 0;
192 GPtrArray *satellite_info;
194 GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(user_data));
195 memcpy(&gpsmanager->satellite, sv, sizeof(sv_data_t));
197 used_prn = g_array_new(FALSE, FALSE, sizeof(guint));
198 for (index = 0; index < sv->num_of_sat; ++index) {
199 if (sv->sat[index].used) {
200 g_array_append_val(used_prn, sv->sat[index].prn);
205 satellite_info = g_ptr_array_new();
207 for (index = 0; index < sv->num_of_sat; ++index) {
208 GValue sv_info = { 0, };
209 g_value_init(&sv_info, GEOCLUE_SATELLITE_INFO);
210 g_value_take_boxed(&sv_info, dbus_g_type_specialized_construct(GEOCLUE_SATELLITE_INFO));
211 dbus_g_type_struct_set(&sv_info,
212 0, sv->sat[index].prn,
213 1, sv->sat[index].elevation,
214 2, sv->sat[index].azimuth, 3, sv->sat[index].snr, G_MAXUINT);
215 g_ptr_array_add(satellite_info, g_value_get_boxed(&sv_info));
218 gc_iface_satellite_emit_satellite_changed(GC_IFACE_SATELLITE(gpsmanager),
219 timestamp, satellite_used, sv->num_of_sat, used_prn, satellite_info);
221 g_array_free(used_prn, TRUE);
222 g_ptr_array_free(satellite_info, TRUE);
225 static void update_nmea_cb(nmea_data_t * nmea, void *user_data)
229 GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(user_data));
231 gpsmanager->nmea.data = g_malloc(nmea->len + 1);
232 g_memmove(gpsmanager->nmea.data, nmea->data, nmea->len);
233 gpsmanager->nmea.data[nmea->len] = '\0';
235 gc_iface_nmea_emit_nmea_changed(GC_IFACE_NMEA(gpsmanager), timestamp, gpsmanager->nmea.data);
237 g_free(gpsmanager->nmea.data);
240 static void add_reference(GcIfaceGeoclue * gc, DBusGMethodInvocation * context)
242 GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
246 sender = dbus_g_method_get_sender(context);
247 if (g_hash_table_size(gpsmanager->connections) == 0) {
248 start_tracking(gpsmanager);
250 pcount = g_hash_table_lookup(gpsmanager->connections, sender);
252 pcount = g_malloc0(sizeof(int));
253 g_hash_table_insert(gpsmanager->connections, sender, pcount);
257 g_debug("add_reference (%s) (%d)", sender, (*pcount));
259 dbus_g_method_return(context);
262 static gboolean remove_client(GeoclueGpsManager * gpsmanager, const char *client)
266 pcount = g_hash_table_lookup(gpsmanager->connections, client);
272 g_hash_table_remove(gpsmanager->connections, client);
274 if (g_hash_table_size(gpsmanager->connections) == 0) {
275 g_debug("There is no connections!");
276 stop_tracking(gpsmanager);
281 static gboolean remove_all_clients(GeoclueGpsManager * gpsmanager, const char *client)
285 pcount = g_hash_table_lookup(gpsmanager->connections, client);
289 g_hash_table_remove(gpsmanager->connections, client);
290 if (g_hash_table_size(gpsmanager->connections) == 0) {
291 g_debug("There is no connections!");
292 stop_tracking(gpsmanager);
297 static void remove_reference(GcIfaceGeoclue * gc, DBusGMethodInvocation * context)
299 GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
302 sender = dbus_g_method_get_sender(context);
303 if (!remove_client(gpsmanager, sender)) {
304 g_warning("Unreffed by client taht has not been referenced");
309 dbus_g_method_return(context);
312 static void name_owner_changed(DBusGProxy * proxy, const char *name, const char *prev_owner, const char *new_owner, void *gc)
314 GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
315 g_debug("name_owner_changed, name:%s, prev_owner:%s, new_owner:%s", name, prev_owner, new_owner);
316 if (strcmp(new_owner, "") == 0 && strcmp(name, prev_owner) == 0) {
317 if (remove_all_clients(gpsmanager, prev_owner)) {
318 g_warning("Impolite client %s disconnected without unreferencing\n", prev_owner);
323 static void geoclue_gpsmanager_class_init(GeoclueGpsManagerClass * klass)
325 GObjectClass *o_class = (GObjectClass *) klass;
326 GcProviderClass *p_class = (GcProviderClass *) klass;
328 o_class->constructed = constructed;
329 o_class->finalize = finalize;
330 o_class->dispose = dispose;
331 p_class->get_status = get_status;
332 p_class->set_options = set_options;
333 p_class->shutdown = shutdown;
336 static void geoclue_gpsmanager_init(GeoclueGpsManager * gpsmanager)
338 GError *error = NULL;
341 GcProvider *provider;
342 g_debug("geoclue_gpsmanager_init");
344 g_return_if_fail(GC_IS_PROVIDER(gpsmanager));
345 provider = GC_PROVIDER(gpsmanager);
346 g_return_if_fail(provider->connection != NULL);
348 driver = dbus_g_proxy_new_for_name(provider->connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
350 if (!org_freedesktop_DBus_request_name(driver, GEOCLUE_GPSMANAGER_DBUS_SERVICE, 0, &request_ret, &error)) {
351 g_warning("%s was unable to register service %s: %s",
352 G_OBJECT_TYPE_NAME(provider), GEOCLUE_GPSMANAGER_DBUS_SERVICE, error->message);
357 dbus_g_proxy_add_signal(driver, "NameOwnerChanged", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
359 dbus_g_proxy_connect_signal(driver, "NameOwnerChanged", G_CALLBACK(name_owner_changed), provider, NULL);
361 dbus_g_connection_register_g_object(provider->connection, GEOCLUE_GPSMANAGER_DBUS_PATH, G_OBJECT(provider));
364 static gboolean get_position(GcIfacePosition * gc,
365 GeocluePositionFields * fields,
368 double *longitude, double *altitude, GeoclueAccuracy ** accuracy, GError ** error)
370 GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
372 if (gpsmanager->status == GEOCLUE_STATUS_ACQUIRING) {
373 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_NOT_AVAILABLE, "ERROR: Acquiring");
377 if (gpsmanager->status != GEOCLUE_STATUS_AVAILABLE) {
378 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_FAILED, "ERROR: Not Available");
383 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_FAILED, "ERROR: Invalid parameters");
387 *fields = GEOCLUE_POSITION_FIELDS_NONE;
390 *timestamp = gpsmanager->position.timestamp;
394 *fields |= GEOCLUE_POSITION_FIELDS_LATITUDE;
395 *latitude = gpsmanager->position.latitude;
399 *fields |= GEOCLUE_POSITION_FIELDS_LONGITUDE;
400 *longitude = gpsmanager->position.longitude;
404 *fields |= GEOCLUE_POSITION_FIELDS_ALTITUDE;
405 *altitude = gpsmanager->position.altitude;
409 *accuracy = geoclue_accuracy_new(GEOCLUE_ACCURACY_LEVEL_DETAILED,
410 gpsmanager->position.hor_accuracy, gpsmanager->position.ver_accuracy);
416 static gboolean get_velocity(GcIfaceVelocity * gc,
417 GeoclueVelocityFields * fields,
418 int *timestamp, double *speed, double *direction, double *climb, GError ** error)
420 GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
422 if (gpsmanager->status == GEOCLUE_STATUS_ACQUIRING) {
423 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_NOT_AVAILABLE, "ERROR: Acquiring");
427 if (gpsmanager->status != GEOCLUE_STATUS_AVAILABLE) {
428 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_FAILED, "ERROR: Not Available");
433 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_FAILED, "ERROR: Invalid parameters");
437 *fields = GEOCLUE_VELOCITY_FIELDS_NONE;
440 *timestamp = gpsmanager->position.timestamp;
444 *fields |= GEOCLUE_VELOCITY_FIELDS_SPEED;
445 *speed = gpsmanager->position.speed;
449 *fields |= GEOCLUE_VELOCITY_FIELDS_DIRECTION;
450 *direction = gpsmanager->position.bearing;
453 /* A climb field does not supported because of poor accuracy. */
458 static gboolean get_nmea(GcIfaceNmea * gc, int *timestamp, char **nmea_data, GError ** error)
460 GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
462 if (gpsmanager->status == GEOCLUE_STATUS_UNAVAILABLE || gpsmanager->status == GEOCLUE_STATUS_ERROR) {
463 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_FAILED, "ERROR: Not Available");
468 *timestamp = gpsmanager->position.timestamp;
472 *nmea_data = g_memdup(gpsmanager->nmea.data, gpsmanager->nmea.len);
478 static gboolean get_satellite(GcIfaceSatellite * gc,
481 int *satellite_visible, GArray ** used_prn, GPtrArray ** satellite_info, GError ** error)
483 GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
485 if (gpsmanager->status == GEOCLUE_STATUS_UNAVAILABLE || gpsmanager->status == GEOCLUE_STATUS_ERROR) {
486 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_FAILED, "ERROR: Not Available");
491 *timestamp = gpsmanager->position.timestamp;
494 if (satellite_used) {
497 for (index = 0; index < gpsmanager->satellite.num_of_sat; ++index) {
498 count += gpsmanager->satellite.sat[index].used ? 1 : 0;
500 *satellite_used = count;
503 if (satellite_visible) {
504 *satellite_visible = gpsmanager->satellite.num_of_sat;
509 *used_prn = g_array_new(FALSE, FALSE, sizeof(guint));
511 for (index = 0; index < gpsmanager->satellite.num_of_sat; ++index) {
512 if (gpsmanager->satellite.sat[index].used) {
513 g_array_append_val(*used_prn, gpsmanager->satellite.sat[index].prn);
518 if (satellite_info) {
520 *satellite_info = g_ptr_array_new();
521 for (index = 0; index < gpsmanager->satellite.num_of_sat; ++index) {
522 GValue sv_info = { 0, };
523 g_value_init(&sv_info, GEOCLUE_SATELLITE_INFO);
524 g_value_take_boxed(&sv_info, dbus_g_type_specialized_construct(GEOCLUE_SATELLITE_INFO));
525 dbus_g_type_struct_set(&sv_info,
526 0, gpsmanager->satellite.sat[index].prn,
527 1, gpsmanager->satellite.sat[index].elevation,
528 2, gpsmanager->satellite.sat[index].azimuth,
529 3, gpsmanager->satellite.sat[index].snr, G_MAXUINT);
530 g_ptr_array_add(*satellite_info, g_value_get_boxed(&sv_info));
537 static void init_position(GcIfacePositionClass * iface)
539 iface->get_position = get_position;
542 static void init_velocity(GcIfaceVelocityClass * iface)
544 iface->get_velocity = get_velocity;
547 static void init_nmea(GcIfaceNmeaClass * iface)
549 iface->get_nmea = get_nmea;
552 static void init_satellite(GcIfaceSatelliteClass * iface)
554 iface->get_satellite = get_satellite;
557 static void init_geoclue(GcIfaceGeoclueClass * iface)
559 iface->get_provider_info = get_provider_info;
560 iface->add_reference = add_reference;
561 iface->remove_reference = remove_reference;
564 int main(int argc, char **argv)
566 GeoclueGpsManager *gpsmanager;
567 struct gps_callbacks cb;
568 cb.pos_cb = update_position_cb;
569 cb.sv_cb = update_satellite_cb;
570 cb.nmea_cb = update_nmea_cb;
572 if (!g_thread_supported()) {
575 dbus_g_thread_init();
578 initialize_server(argc, argv);
580 gpsmanager = g_object_new(GEOCLUE_TYPE_GPSMANAGER, NULL);
581 register_update_callbacks(&cb, gpsmanager);
583 gpsmanager->loop = g_main_loop_new(NULL, TRUE);
584 g_main_loop_run(gpsmanager->loop);
586 g_main_loop_unref(gpsmanager->loop);
587 g_object_unref(gpsmanager);
589 deinitialize_server();