summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2012-03-27 17:15:57 +0200
committerAleksander Morgado <aleksander@lanedo.com>2012-03-29 09:18:03 +0200
commit53b500c11dc648cff834be2885886f5e575046e4 (patch)
treec1827fbb6fcd80cbb9bfecbf41ff8bcce9092bc6
parent0012b7118656afd127097d3cbfa27e9190cedd47 (diff)
downloadModemManager-53b500c11dc648cff834be2885886f5e575046e4.tar.gz
iface-modem-location: handle the NMEA-based GPS location source
-rw-r--r--src/mm-iface-modem-location.c153
-rw-r--r--src/mm-iface-modem-location.h4
2 files changed, 140 insertions, 17 deletions
diff --git a/src/mm-iface-modem-location.c b/src/mm-iface-modem-location.c
index dc5e0805b..064bd7704 100644
--- a/src/mm-iface-modem-location.c
+++ b/src/mm-iface-modem-location.c
@@ -21,6 +21,8 @@
#include "mm-iface-modem-location.h"
#include "mm-log.h"
+#define MM_LOCATION_GPS_REFRESH_TIME_SECS 30
+
#define LOCATION_CONTEXT_TAG "location-context-tag"
static GQuark location_context_quark;
@@ -38,6 +40,9 @@ mm_iface_modem_location_bind_simple_status (MMIfaceModemLocation *self,
typedef struct {
/* 3GPP location */
MMLocation3gpp *location_3gpp;
+ /* GPS location */
+ time_t location_gps_last_time;
+ MMLocationGpsNmea *location_gps_nmea;
} LocationContext;
static void
@@ -45,6 +50,8 @@ location_context_free (LocationContext *ctx)
{
if (ctx->location_3gpp)
g_object_unref (ctx->location_3gpp);
+ if (ctx->location_gps_nmea)
+ g_object_unref (ctx->location_gps_nmea);
g_free (ctx);
}
@@ -88,27 +95,122 @@ get_location_context (MMIfaceModemLocation *self)
/*****************************************************************************/
static GVariant *
-build_location_dictionary (MMLocation3gpp *location_3gpp)
+build_location_dictionary (GVariant *previous,
+ MMLocation3gpp *location_3gpp,
+ MMLocationGpsNmea *location_gps_nmea)
{
GVariant *location_3gpp_value = NULL;
+ GVariant *location_gps_nmea_value = NULL;
GVariantBuilder builder;
- if (location_3gpp)
- location_3gpp_value = mm_location_3gpp_get_string_variant (location_3gpp);
+ /* If a previous dictionary given, parse its values */
+ if (previous) {
+ guint source;
+ GVariant *value;
+ GVariantIter iter;
+
+ g_variant_iter_init (&iter, previous);
+ while (g_variant_iter_next (&iter, "{uv}", &source, &value)) {
+ switch (source) {
+ case MM_MODEM_LOCATION_SOURCE_3GPP_LAC_CI:
+ location_3gpp_value = value;
+ break;
+ case MM_MODEM_LOCATION_SOURCE_GPS_NMEA:
+ location_gps_nmea_value = value;
+ break;
+ default:
+ g_warn_if_reached ();
+ break;
+ }
+ }
+ }
+ /* Build the new one */
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{uv}"));
- if (location_3gpp_value)
+
+ /* If a new one given, use it */
+ if (location_3gpp) {
+ if (location_3gpp_value)
+ g_variant_unref (location_3gpp_value);
+ location_3gpp_value = mm_location_3gpp_get_string_variant (location_3gpp);
+ }
+
+ if (location_3gpp_value) {
g_variant_builder_add (&builder,
"{uv}",
MM_MODEM_LOCATION_SOURCE_3GPP_LAC_CI,
location_3gpp_value);
+ }
+
+ /* If a new one given, use it */
+ if (location_gps_nmea) {
+ if (location_gps_nmea_value)
+ g_variant_unref (location_gps_nmea_value);
+ location_gps_nmea_value = mm_location_gps_nmea_get_string_variant (location_gps_nmea);
+ }
+
+ if (location_gps_nmea_value)
+ g_variant_builder_add (&builder,
+ "{uv}",
+ MM_MODEM_LOCATION_SOURCE_GPS_NMEA,
+ location_gps_nmea_value);
+
return g_variant_builder_end (&builder);
}
+/*****************************************************************************/
+
+static void
+notify_gps_location_update (MMIfaceModemLocation *self,
+ MmGdbusModemLocation *skeleton,
+ MMLocationGpsNmea *location_gps_nmea)
+{
+ const gchar *dbus_path;
+
+ dbus_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (self));
+ mm_info ("Modem %s: GPS location updated",
+ dbus_path);
+
+ /* We only update the property if we are supposed to signal
+ * location */
+ if (mm_gdbus_modem_location_get_signals_location (skeleton))
+ mm_gdbus_modem_location_set_location (
+ skeleton,
+ build_location_dictionary (mm_gdbus_modem_location_get_location (skeleton),
+ NULL,
+ location_gps_nmea));
+}
+
+void
+mm_iface_modem_location_gps_update (MMIfaceModemLocation *self,
+ const gchar *nmea_trace)
+{
+ MmGdbusModemLocation *skeleton;
+ LocationContext *ctx;
+
+ ctx = get_location_context (self);
+ g_object_get (self,
+ MM_IFACE_MODEM_LOCATION_DBUS_SKELETON, &skeleton,
+ NULL);
+
+ if (mm_gdbus_modem_location_get_enabled (skeleton) & MM_MODEM_LOCATION_SOURCE_GPS_NMEA) {
+ g_assert (ctx->location_gps_nmea != NULL);
+ if (mm_location_gps_nmea_add_trace (ctx->location_gps_nmea, nmea_trace) &&
+ ctx->location_gps_last_time >= MM_LOCATION_GPS_REFRESH_TIME_SECS) {
+ ctx->location_gps_last_time = time (NULL);
+ notify_gps_location_update (self, skeleton, ctx->location_gps_nmea);
+ }
+ }
+
+ g_object_unref (skeleton);
+}
+
+/*****************************************************************************/
+
static void
-notify_location_update (MMIfaceModemLocation *self,
- MmGdbusModemLocation *skeleton,
- MMLocation3gpp *location_3gpp)
+notify_3gpp_location_update (MMIfaceModemLocation *self,
+ MmGdbusModemLocation *skeleton,
+ MMLocation3gpp *location_3gpp)
{
const gchar *dbus_path;
@@ -126,7 +228,9 @@ notify_location_update (MMIfaceModemLocation *self,
if (mm_gdbus_modem_location_get_signals_location (skeleton))
mm_gdbus_modem_location_set_location (
skeleton,
- build_location_dictionary (location_3gpp));
+ build_location_dictionary (mm_gdbus_modem_location_get_location (skeleton),
+ location_3gpp,
+ NULL));
}
void
@@ -151,7 +255,7 @@ mm_iface_modem_location_3gpp_update_mcc_mnc (MMIfaceModemLocation *self,
changed += mm_location_3gpp_set_mobile_network_code (ctx->location_3gpp,
mobile_network_code);
if (changed)
- notify_location_update (self, skeleton, ctx->location_3gpp);
+ notify_3gpp_location_update (self, skeleton, ctx->location_3gpp);
}
g_object_unref (skeleton);
@@ -179,7 +283,7 @@ mm_iface_modem_location_3gpp_update_lac_ci (MMIfaceModemLocation *self,
changed += mm_location_3gpp_set_cell_id (ctx->location_3gpp,
cell_id);
if (changed)
- notify_location_update (self, skeleton, ctx->location_3gpp);
+ notify_3gpp_location_update (self, skeleton, ctx->location_3gpp);
}
g_object_unref (skeleton);
@@ -205,7 +309,7 @@ mm_iface_modem_location_3gpp_clear (MMIfaceModemLocation *self)
changed += mm_location_3gpp_set_mobile_country_code (ctx->location_3gpp, 0);
changed += mm_location_3gpp_set_mobile_network_code (ctx->location_3gpp, 0);
if (changed)
- notify_location_update (self, skeleton, ctx->location_3gpp);
+ notify_3gpp_location_update (self, skeleton, ctx->location_3gpp);
}
g_object_unref (skeleton);
@@ -245,6 +349,13 @@ update_location_source_status (MMIfaceModemLocation *self,
} else
g_clear_object (&ctx->location_3gpp);
break;
+ case MM_MODEM_LOCATION_SOURCE_GPS_NMEA:
+ if (enabled) {
+ if (!ctx->location_gps_nmea)
+ ctx->location_gps_nmea = mm_location_gps_nmea_new ();
+ } else
+ g_clear_object (&ctx->location_gps_nmea);
+ break;
default:
break;
}
@@ -564,10 +675,16 @@ handle_setup_auth_ready (MMBaseModem *self,
ctx->signal_location ? "Enabling" : "Disabling");
mm_gdbus_modem_location_set_signals_location (ctx->skeleton,
ctx->signal_location);
- mm_gdbus_modem_location_set_location (ctx->skeleton,
- build_location_dictionary (ctx->signal_location ?
- location_ctx->location_3gpp :
- NULL));
+ if (ctx->signal_location)
+ mm_gdbus_modem_location_set_location (
+ ctx->skeleton,
+ build_location_dictionary (mm_gdbus_modem_location_get_location (ctx->skeleton),
+ location_ctx->location_3gpp,
+ location_ctx->location_gps_nmea));
+ else
+ mm_gdbus_modem_location_set_location (
+ ctx->skeleton,
+ build_location_dictionary (NULL, NULL, NULL));
}
str = mm_modem_location_source_build_string_from_mask (ctx->sources);
@@ -655,7 +772,9 @@ handle_get_location_auth_ready (MMBaseModem *self,
mm_gdbus_modem_location_complete_get_location (
ctx->skeleton,
ctx->invocation,
- build_location_dictionary (location_ctx->location_3gpp));
+ build_location_dictionary (NULL,
+ location_ctx->location_3gpp,
+ location_ctx->location_gps_nmea));
}
static gboolean
@@ -1123,7 +1242,7 @@ mm_iface_modem_location_initialize (MMIfaceModemLocation *self,
mm_gdbus_modem_location_set_enabled (skeleton, MM_MODEM_LOCATION_SOURCE_NONE);
mm_gdbus_modem_location_set_signals_location (skeleton, FALSE);
mm_gdbus_modem_location_set_location (skeleton,
- build_location_dictionary (NULL));
+ build_location_dictionary (NULL, NULL, NULL));
g_object_set (self,
MM_IFACE_MODEM_LOCATION_DBUS_SKELETON, skeleton,
diff --git a/src/mm-iface-modem-location.h b/src/mm-iface-modem-location.h
index 19f760e4d..ea64bb8f9 100644
--- a/src/mm-iface-modem-location.h
+++ b/src/mm-iface-modem-location.h
@@ -100,6 +100,10 @@ void mm_iface_modem_location_3gpp_update_lac_ci (MMIfaceModemLocation *self,
gulong location_area_code,
gulong cell_id);
+/* Update GPS location */
+void mm_iface_modem_location_gps_update (MMIfaceModemLocation *self,
+ const gchar *nmea_trace);
+
/* Bind properties for simple GetStatus() */
void mm_iface_modem_location_bind_simple_status (MMIfaceModemLocation *self,
MMSimpleStatus *status);