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"
45 #include "last_position.h"
46 #include "debug_util.h"
48 #define GEOCLUE_GPSMANAGER_DBUS_SERVICE "org.freedesktop.Geoclue.Providers.GpsManager"
49 #define GEOCLUE_GPSMANAGER_DBUS_PATH "/org/freedesktop/Geoclue/Providers/GpsManager"
61 pos_data_t last_position;
62 sv_data_t last_satellite;
69 GcProviderClass parent_class;
70 } GeoclueGpsManagerClass;
72 #define GEOCLUE_TYPE_GPSMANAGER (geoclue_gpsmanager_get_type ())
73 #define GEOCLUE_GPSMANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEOCLUE_TYPE_GPSMANAGER, GeoclueGpsManager))
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);
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));
88 static GObject* constructor (GType type, guint n_props, GObjectConstructParam *props)
92 object = ((GObjectClass *) geoclue_gpsmanager_parent_class)->constructor(type, n_props, props);
97 static void finalize(GObject * object)
99 ((GObjectClass *) geoclue_gpsmanager_parent_class)->finalize(object);
102 static void dispose(GObject * object)
104 GeoclueGpsManager *gpsmanager = GEOCLUE_GPSMANAGER(object);
105 g_mutex_free(gpsmanager->mutex);
106 ((GObjectClass *) geoclue_gpsmanager_parent_class)->dispose(object);
109 static gboolean get_status(GcIfaceGeoclue * gc, GeoclueStatus * status, GError ** error)
111 GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
113 *status = gpsmanager->status;
118 static gboolean get_provider_info(GcIfaceGeoclue * geoclue, gchar ** name, gchar ** description, GError ** error)
121 *name = g_strdup("geoclue-gpsmanager");
124 *description = g_strdup("Geoclue-gpsmanager");
129 static void start_tracking(GeoclueGpsManager * gpsmanager)
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;
137 LOG_GPS(DBG_ERR, "Fail to request_start_session");
139 g_mutex_unlock(gpsmanager->mutex);
142 static void stop_tracking(GeoclueGpsManager * gpsmanager)
144 LOG_GPS(DBG_LOW, "stop_tracking");
145 g_mutex_lock(gpsmanager->mutex);
146 if (request_stop_session() == TRUE) {
147 gpsmanager->is_running = FALSE;
149 g_mutex_unlock(gpsmanager->mutex);
150 gpsmanager->status = GEOCLUE_STATUS_UNAVAILABLE;
153 static gboolean set_options(GcIfaceGeoclue * gc, GHashTable * options, GError ** error)
155 LOG_GPS(DBG_LOW, "set_options");
157 GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
160 value = g_hash_table_lookup(options, "CMD");
163 if (!g_strcmp0(value, "START")) {
164 g_mutex_lock(gpsmanager->mutex);
165 gpsmanager->client_count++;
166 g_mutex_unlock(gpsmanager->mutex);
168 if (gpsmanager->is_running == TRUE) {
169 LOG_GPS(DBG_LOW, "gps-manager is already running");
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);
178 if (gpsmanager->is_running == FALSE) {
181 if (gpsmanager->client_count <= 0 ) {
182 stop_tracking(gpsmanager);
189 static gboolean remove_all_clients(GeoclueGpsManager * gpsmanager)
191 if (gpsmanager->client_count <= 0) {
195 gpsmanager->client_count = 0;
196 stop_tracking(gpsmanager);
201 static void shutdown(GcProvider * provider)
203 GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(provider));
205 if (gpsmanager->is_running) {
206 if (remove_all_clients(gpsmanager)) {
207 LOG_GPS(DBG_ERR, "<<<< Abnormal shutdown >>>>");
212 static void update_position_cb(pos_data_t * pos, gps_error_t error, void *user_data)
214 GeocluePositionFields fields;
215 GeoclueAccuracy *accuracy;
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));
221 gpsmanager->status = GEOCLUE_STATUS_AVAILABLE;
223 accuracy = geoclue_accuracy_new(GEOCLUE_ACCURACY_LEVEL_DETAILED, pos->hor_accuracy, pos->ver_accuracy);
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);
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);
233 geoclue_accuracy_free(accuracy);
235 gc_iface_geoclue_emit_status_changed(GC_IFACE_GEOCLUE(gpsmanager), GEOCLUE_STATUS_AVAILABLE);
238 static void update_satellite_cb(sv_data_t * sv, void *user_data)
242 int satellite_used = 0;
244 GPtrArray *satellite_info;
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;
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);
259 satellite_info = g_ptr_array_new();
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));
270 gc_iface_satellite_emit_satellite_changed(GC_IFACE_SATELLITE
271 (gpsmanager), timestamp,
272 satellite_used, sv->num_of_sat, used_prn, satellite_info);
274 g_array_free(used_prn, TRUE);
275 g_ptr_array_free(satellite_info, TRUE);
278 static void update_nmea_cb(nmea_data_t * nmea, void *user_data)
282 GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(user_data));
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';
288 timestamp = gpsmanager->position.timestamp;
290 gc_iface_nmea_emit_nmea_changed(GC_IFACE_NMEA(gpsmanager), timestamp, gpsmanager->nmea.data);
292 g_free(gpsmanager->nmea.data);
295 static void geoclue_gpsmanager_class_init(GeoclueGpsManagerClass * klass)
297 GObjectClass *o_class = (GObjectClass *) klass;
298 GcProviderClass *p_class = (GcProviderClass *) klass;
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;
308 static void geoclue_gpsmanager_init(GeoclueGpsManager * gpsmanager)
310 LOG_GPS(DBG_LOW, "geoclue_gpsmanager_init");
312 gpsmanager->status = GEOCLUE_STATUS_UNAVAILABLE;
313 gpsmanager->mutex = g_mutex_new();
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));
321 gpsmanager->is_running = FALSE;
322 gpsmanager->client_count = 0;
324 gc_provider_set_details(GC_PROVIDER(gpsmanager), GEOCLUE_GPSMANAGER_DBUS_SERVICE, GEOCLUE_GPSMANAGER_DBUS_PATH, "gps-manager", "GPS Manager");
326 gps_manager_get_last_position(&gpsmanager->last_position);
329 static gboolean get_position(GcIfacePosition * gc,
330 GeocluePositionFields * fields,
333 double *longitude, double *altitude, GeoclueAccuracy ** accuracy, GError ** error)
335 GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
337 if (gpsmanager->status == GEOCLUE_STATUS_ACQUIRING) {
338 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_NOT_AVAILABLE, "ERROR: Acquiring");
342 if (gpsmanager->status != GEOCLUE_STATUS_AVAILABLE) {
343 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_FAILED, "ERROR: Not Available");
348 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_FAILED, "ERROR: Invalid parameters");
352 *fields = GEOCLUE_POSITION_FIELDS_NONE;
355 *timestamp = gpsmanager->position.timestamp;
359 *fields |= GEOCLUE_POSITION_FIELDS_LATITUDE;
360 *latitude = gpsmanager->position.latitude;
364 *fields |= GEOCLUE_POSITION_FIELDS_LONGITUDE;
365 *longitude = gpsmanager->position.longitude;
369 *fields |= GEOCLUE_POSITION_FIELDS_ALTITUDE;
370 *altitude = gpsmanager->position.altitude;
375 geoclue_accuracy_new(GEOCLUE_ACCURACY_LEVEL_DETAILED,
376 gpsmanager->position.hor_accuracy, gpsmanager->position.ver_accuracy);
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)
387 GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
390 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_FAILED, "ERROR: Invalid parameters");
394 *fields = GEOCLUE_POSITION_FIELDS_NONE;
397 *timestamp = gpsmanager->last_position.timestamp;
401 *fields |= GEOCLUE_POSITION_FIELDS_LATITUDE;
402 *latitude = gpsmanager->last_position.latitude;
406 *fields |= GEOCLUE_POSITION_FIELDS_LONGITUDE;
407 *longitude = gpsmanager->last_position.longitude;
411 *fields |= GEOCLUE_POSITION_FIELDS_ALTITUDE;
412 *altitude = gpsmanager->last_position.altitude;
418 geoclue_accuracy_new(GEOCLUE_ACCURACY_LEVEL_DETAILED,
419 gpsmanager->last_position.hor_accuracy, gpsmanager->last_position.ver_accuracy);
425 static gboolean get_velocity(GcIfaceVelocity * gc,
426 GeoclueVelocityFields * fields,
427 int *timestamp, double *speed, double *direction, double *climb, GError ** error)
429 GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
431 if (gpsmanager->status == GEOCLUE_STATUS_ACQUIRING) {
432 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_NOT_AVAILABLE, "ERROR: Acquiring");
436 if (gpsmanager->status != GEOCLUE_STATUS_AVAILABLE) {
437 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_FAILED, "ERROR: Not Available");
442 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_FAILED, "ERROR: Invalid parameters");
446 *fields = GEOCLUE_VELOCITY_FIELDS_NONE;
449 *timestamp = gpsmanager->position.timestamp;
453 *fields |= GEOCLUE_VELOCITY_FIELDS_SPEED;
454 *speed = gpsmanager->position.speed;
458 *fields |= GEOCLUE_VELOCITY_FIELDS_DIRECTION;
459 *direction = gpsmanager->position.bearing;
462 /* A climb field does not supported because of poor accuracy. */
467 static gboolean get_last_velocity(GcIfaceVelocity * gc,
468 GeoclueVelocityFields * fields,
469 int *timestamp, double *speed, double *direction, double *climb, GError ** error)
471 GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
474 g_set_error(error, GEOCLUE_ERROR, GEOCLUE_ERROR_FAILED, "ERROR: Invalid parameters");
478 *fields = GEOCLUE_VELOCITY_FIELDS_NONE;
481 *timestamp = gpsmanager->last_position.timestamp;
485 *fields |= GEOCLUE_VELOCITY_FIELDS_SPEED;
486 *speed = gpsmanager->last_position.speed;
490 *fields |= GEOCLUE_VELOCITY_FIELDS_DIRECTION;
491 *direction = gpsmanager->last_position.bearing;
497 static gboolean get_nmea(GcIfaceNmea * gc, int *timestamp, char **nmea_data, GError ** error)
499 GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
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");
507 *timestamp = gpsmanager->position.timestamp;
511 *nmea_data = g_memdup(gpsmanager->nmea.data, gpsmanager->nmea.len);
517 static gboolean get_satellite(GcIfaceSatellite * gc,
520 int *satellite_visible, GArray ** used_prn, GPtrArray ** satellite_info, GError ** error)
522 GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
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");
530 *timestamp = gpsmanager->satellite.timestamp;
533 if (satellite_used) {
536 for (index = 0; index < gpsmanager->satellite.num_of_sat; ++index) {
537 count += gpsmanager->satellite.sat[index].used ? 1 : 0;
539 *satellite_used = count;
542 if (satellite_visible) {
543 *satellite_visible = gpsmanager->satellite.num_of_sat;
548 *used_prn = g_array_new(FALSE, FALSE, sizeof(guint));
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);
557 if (satellite_info) {
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));
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)
579 GeoclueGpsManager *gpsmanager = (GEOCLUE_GPSMANAGER(gc));
582 *timestamp = gpsmanager->last_satellite.timestamp;
585 if (satellite_used) {
588 for (index = 0; index < gpsmanager->last_satellite.num_of_sat; ++index) {
589 count += gpsmanager->last_satellite.sat[index].used ? 1 : 0;
591 *satellite_used = count;
594 if (satellite_visible) {
595 *satellite_visible = gpsmanager->last_satellite.num_of_sat;
600 *used_prn = g_array_new(FALSE, FALSE, sizeof(guint));
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);
609 if (satellite_info) {
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));
628 static void init_position(GcIfacePositionClass * iface)
630 iface->get_position = get_position;
631 iface->get_last_position = get_last_position;
634 static void init_velocity(GcIfaceVelocityClass * iface)
636 iface->get_velocity = get_velocity;
637 iface->get_last_velocity = get_last_velocity;
640 static void init_nmea(GcIfaceNmeaClass * iface)
642 iface->get_nmea = get_nmea;
645 static void init_satellite(GcIfaceSatelliteClass * iface)
647 iface->get_satellite = get_satellite;
648 iface->get_last_satellite = get_last_satellite;
651 static void init_geoclue(GcIfaceGeoclueClass * iface)
653 iface->get_provider_info = get_provider_info;
656 int main(int argc, char **argv)
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;
664 #if !GLIB_CHECK_VERSION (2, 31, 0)
665 if (!g_thread_supported()) {
670 dbus_g_thread_init();
673 initialize_server(argc, argv);
675 gpsmanager = g_object_new(GEOCLUE_TYPE_GPSMANAGER, NULL);
676 register_update_callbacks(&cb, gpsmanager);
678 gpsmanager->loop = g_main_loop_new(NULL, TRUE);
679 g_main_loop_run(gpsmanager->loop);
681 g_main_loop_unref(gpsmanager->loop);
682 g_object_unref(gpsmanager);
684 deinitialize_server();