diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2012-03-28 09:27:04 +0200 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2012-03-29 09:18:03 +0200 |
commit | 423c4a9d6712a5bc6e71bd77ddd6753b2f309570 (patch) | |
tree | da17cab04b4a115fbe7a9ee47bc918200b26f4fa | |
parent | bf4208246609a6b2a71d9c51696fbb9283871d55 (diff) | |
download | ModemManager-423c4a9d6712a5bc6e71bd77ddd6753b2f309570.tar.gz |
libmm-common: new helper `MMModemLocationGpsRaw' object
-rw-r--r-- | libmm-common/Makefile.am | 4 | ||||
-rw-r--r-- | libmm-common/libmm-common.h | 1 | ||||
-rw-r--r-- | libmm-common/mm-location-gps-raw.c | 334 | ||||
-rw-r--r-- | libmm-common/mm-location-gps-raw.h | 70 |
4 files changed, 409 insertions, 0 deletions
diff --git a/libmm-common/Makefile.am b/libmm-common/Makefile.am index bc4be0165..7ba047782 100644 --- a/libmm-common/Makefile.am +++ b/libmm-common/Makefile.am @@ -164,6 +164,7 @@ mm-bearer-properties.c: mm-errors-types.h mm-sms-properties.c: mm-errors-types.h mm-bearer-ip-config.c: mm-errors-types.h mm-location-3gpp.c: mm-errors-types.h +mm-location-gps-raw.c: mm-errors-types.h mm-location-gps-nmea.c: mm-errors-types.h mm-unlock-retries.c: mm-enums-types.h mm-network-timezone.c: mm-errors-types.h @@ -180,6 +181,7 @@ include_HEADERS = \ mm-bearer-ip-config.h \ mm-location-3gpp.h \ mm-location-gps-nmea.h \ + mm-location-gps-raw.h \ mm-unlock-retries.h \ mm-network-timezone.h \ mm-gdbus-manager.h \ @@ -207,6 +209,8 @@ libmm_common_la_SOURCES = \ mm-bearer-ip-config.c \ mm-location-3gpp.h \ mm-location-3gpp.c \ + mm-location-gps-raw.h \ + mm-location-gps-raw.c \ mm-location-gps-nmea.h \ mm-location-gps-nmea.c \ mm-unlock-retries.h \ diff --git a/libmm-common/libmm-common.h b/libmm-common/libmm-common.h index 5b6eb84b0..3f3a8f293 100644 --- a/libmm-common/libmm-common.h +++ b/libmm-common/libmm-common.h @@ -32,6 +32,7 @@ #include "mm-bearer-properties.h" #include "mm-bearer-ip-config.h" #include "mm-location-3gpp.h" +#include "mm-location-gps-raw.h" #include "mm-location-gps-nmea.h" #include "mm-unlock-retries.h" #include "mm-network-timezone.h" diff --git a/libmm-common/mm-location-gps-raw.c b/libmm-common/mm-location-gps-raw.c new file mode 100644 index 000000000..7269ca444 --- /dev/null +++ b/libmm-common/mm-location-gps-raw.c @@ -0,0 +1,334 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details: + * + * Copyright (C) 2012 Lanedo GmbH <aleksander@lanedo.com> + */ + +#include <string.h> +#include <ctype.h> +#include <stdlib.h> + +#include "mm-common-helpers.h" +#include "mm-errors-types.h" +#include "mm-location-gps-raw.h" + +G_DEFINE_TYPE (MMLocationGpsRaw, mm_location_gps_raw, G_TYPE_OBJECT); + +#define PROPERTY_UTC_TIME "utc-time" +#define PROPERTY_LATITUDE "latitude" +#define PROPERTY_LONGITUDE "longitude" +#define PROPERTY_ALTITUDE "altitude" + +struct _MMLocationGpsRawPrivate { + GRegex *gpgga_regex; + + gchar *utc_time; + gdouble latitude; + gdouble longitude; + gdouble altitude; +}; + +/*****************************************************************************/ + +const gchar * +mm_location_gps_raw_get_utc_time (MMLocationGpsRaw *self) +{ + g_return_val_if_fail (MM_IS_LOCATION_GPS_RAW (self), NULL); + + return self->priv->utc_time; +} + +gdouble +mm_location_gps_raw_get_longitude (MMLocationGpsRaw *self) +{ + g_return_val_if_fail (MM_IS_LOCATION_GPS_RAW (self), + MM_LOCATION_GPS_RAW_LONGITUDE_UNKNOWN); + + return self->priv->longitude; +} + +gdouble +mm_location_gps_raw_get_latitude (MMLocationGpsRaw *self) +{ + g_return_val_if_fail (MM_IS_LOCATION_GPS_RAW (self), + MM_LOCATION_GPS_RAW_LATITUDE_UNKNOWN); + + return self->priv->latitude; +} + +gdouble +mm_location_gps_raw_get_altitude (MMLocationGpsRaw *self) +{ + g_return_val_if_fail (MM_IS_LOCATION_GPS_RAW (self), + MM_LOCATION_GPS_RAW_ALTITUDE_UNKNOWN); + + return self->priv->altitude; +} + +/*****************************************************************************/ + +static gboolean +get_longitude_or_latitude_from_match_info (GMatchInfo *match_info, + guint32 match_index, + gdouble *out) +{ + gchar *aux; + gchar *s; + gboolean ret = FALSE; + gdouble minutes; + gdouble degrees; + + s = g_match_info_fetch (match_info, match_index); + if (!s) + goto out; + + /* 4533.35 is 45 degrees and 33.35 minutes */ + + aux = strchr (s, '.'); + if (!aux || ((aux - s) < 3)) + goto out; + + aux -= 2; + if (!mm_get_double_from_str (aux, &minutes)) + goto out; + + aux[0] = '\0'; + if (!mm_get_double_from_str (s, °rees)) + goto out; + + /* Include the minutes as part of the degrees */ + *out = degrees + (minutes / 60.0); + ret = TRUE; + +out: + g_free (s); + + return ret; +} + +gboolean +mm_location_gps_raw_add_trace (MMLocationGpsRaw *self, + const gchar *trace) +{ + GMatchInfo *match_info = NULL; + + /* Current implementation works only with $GPGGA traces */ + if (!g_str_has_prefix (trace, "$GPGGA")) + return FALSE; + + /* + * $GPGGA,hhmmss.ss,llll.ll,a,yyyyy.yy,a,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx*hh + * 1 = UTC of Position + * 2 = Latitude + * 3 = N or S + * 4 = Longitude + * 5 = E or W + * 6 = GPS quality indicator (0=invalid; 1=GPS fix; 2=Diff. GPS fix) + * 7 = Number of satellites in use [not those in view] + * 8 = Horizontal dilution of position + * 9 = Antenna altitude above/below mean sea level (geoid) + * 10 = Meters (Antenna height unit) + * 11 = Geoidal separation (Diff. between WGS-84 earth ellipsoid and + * mean sea level. -=geoid is below WGS-84 ellipsoid) + * 12 = Meters (Units of geoidal separation) + * 13 = Age in seconds since last update from diff. reference station + * 14 = Diff. reference station ID# + * 15 = Checksum + */ + if (G_UNLIKELY (!self->priv->gpgga_regex)) + self->priv->gpgga_regex = g_regex_new ("\\$GPGGA,(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*)\\*(.*).*", + G_REGEX_RAW | G_REGEX_OPTIMIZE, + 0, + NULL); + + if (g_regex_match (self->priv->gpgga_regex, trace, 0, &match_info)) { + /* UTC time */ + if (self->priv->utc_time) + g_free (self->priv->utc_time); + self->priv->utc_time = g_match_info_fetch (match_info, 1); + + /* Latitude */ + self->priv->latitude = MM_LOCATION_GPS_RAW_LATITUDE_UNKNOWN; + if (get_longitude_or_latitude_from_match_info (match_info, 2, &self->priv->latitude)) { + gchar *str; + + /* N/S */ + str = g_match_info_fetch (match_info, 3); + if (str && str[0] == 'S') + self->priv->latitude *= -1; + g_free (str); + } + + /* Longitude */ + self->priv->longitude = MM_LOCATION_GPS_RAW_LONGITUDE_UNKNOWN; + if (get_longitude_or_latitude_from_match_info (match_info, 4, &self->priv->longitude)) { + gchar *str; + + /* N/S */ + str = g_match_info_fetch (match_info, 5); + if (str && str[0] == 'W') + self->priv->longitude *= -1; + g_free (str); + } + + /* Altitude */ + self->priv->altitude = MM_LOCATION_GPS_RAW_ALTITUDE_UNKNOWN; + mm_get_double_from_match_info (match_info, 9, &self->priv->altitude); + } + + g_match_info_free (match_info); + + return TRUE; +} + +/*****************************************************************************/ + +GVariant * +mm_location_gps_raw_get_dictionary (MMLocationGpsRaw *self) +{ + GVariantBuilder builder; + + /* We do allow NULL */ + if (!self) + return NULL; + + g_return_val_if_fail (MM_IS_LOCATION_GPS_RAW (self), NULL); + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + + if (self->priv->utc_time && + self->priv->longitude != MM_LOCATION_GPS_RAW_LONGITUDE_UNKNOWN && + self->priv->latitude != MM_LOCATION_GPS_RAW_LATITUDE_UNKNOWN) { + g_variant_builder_add (&builder, + "{sv}", + PROPERTY_UTC_TIME, + g_variant_new_string (self->priv->utc_time)); + g_variant_builder_add (&builder, + "{sv}", + PROPERTY_LONGITUDE, + g_variant_new_double (self->priv->longitude)); + g_variant_builder_add (&builder, + "{sv}", + PROPERTY_LATITUDE, + g_variant_new_double (self->priv->latitude)); + + /* Altitude is optional */ + if (self->priv->altitude != MM_LOCATION_GPS_RAW_ALTITUDE_UNKNOWN) + g_variant_builder_add (&builder, + "{sv}", + PROPERTY_ALTITUDE, + g_variant_new_double (self->priv->altitude)); + } + + return g_variant_ref_sink (g_variant_builder_end (&builder)); +} + +/*****************************************************************************/ + +MMLocationGpsRaw * +mm_location_gps_raw_new_from_dictionary (GVariant *dictionary, + GError **error) +{ + GError *inner_error = NULL; + MMLocationGpsRaw *self; + GVariantIter iter; + gchar *key; + GVariant *value; + + self = mm_location_gps_raw_new (); + if (!dictionary) + return self; + + if (!g_variant_is_of_type (dictionary, G_VARIANT_TYPE ("a{sv}"))) { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_INVALID_ARGS, + "Cannot create GPS RAW location from dictionary: " + "invalid variant type received"); + g_object_unref (self); + return NULL; + } + + g_variant_iter_init (&iter, dictionary); + while (!inner_error && + g_variant_iter_next (&iter, "{sv}", &key, &value)) { + if (g_str_equal (key, PROPERTY_UTC_TIME)) + self->priv->utc_time = g_variant_dup_string (value, NULL); + else if (g_str_equal (key, PROPERTY_LONGITUDE)) + self->priv->longitude = g_variant_get_double (value); + else if (g_str_equal (key, PROPERTY_LATITUDE)) + self->priv->latitude = g_variant_get_double (value); + else if (g_str_equal (key, PROPERTY_ALTITUDE)) + self->priv->altitude = g_variant_get_double (value); + g_free (key); + g_variant_unref (value); + } + + /* If any of the mandatory parameters is missing, cleanup */ + if (!self->priv->utc_time || + !self->priv->longitude || + !self->priv->latitude) { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_INVALID_ARGS, + "Cannot create GPS RAW location from dictionary: " + "mandatory parameters missing " + "(utc-time: %s, longitude: %s, latitude: %s)", + self->priv->utc_time ? "yes" : "no", + self->priv->longitude ? "yes" : "no", + self->priv->latitude ? "yes" : "no"); + g_clear_object (&self); + } + + return self; +} + +/*****************************************************************************/ + +MMLocationGpsRaw * +mm_location_gps_raw_new (void) +{ + return (MM_LOCATION_GPS_RAW ( + g_object_new (MM_TYPE_LOCATION_GPS_RAW, NULL))); +} + +static void +mm_location_gps_raw_init (MMLocationGpsRaw *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self), + MM_TYPE_LOCATION_GPS_RAW, + MMLocationGpsRawPrivate); + + self->priv->utc_time = NULL; + self->priv->latitude = MM_LOCATION_GPS_RAW_LATITUDE_UNKNOWN; + self->priv->longitude = MM_LOCATION_GPS_RAW_LONGITUDE_UNKNOWN; + self->priv->altitude = MM_LOCATION_GPS_RAW_ALTITUDE_UNKNOWN; +} + +static void +finalize (GObject *object) +{ + MMLocationGpsRaw *self = MM_LOCATION_GPS_RAW (object); + + if (self->priv->gpgga_regex) + g_regex_unref (self->priv->gpgga_regex); + + G_OBJECT_CLASS (mm_location_gps_raw_parent_class)->finalize (object); +} + +static void +mm_location_gps_raw_class_init (MMLocationGpsRawClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (MMLocationGpsRawPrivate)); +} diff --git a/libmm-common/mm-location-gps-raw.h b/libmm-common/mm-location-gps-raw.h new file mode 100644 index 000000000..46f365806 --- /dev/null +++ b/libmm-common/mm-location-gps-raw.h @@ -0,0 +1,70 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details: + * + * Copyright (C) 2012 Lanedo GmbH <aleksander@lanedo.com> + */ + +#ifndef MM_LOCATION_GPS_RAW_H +#define MM_LOCATION_GPS_RAW_H + +#include <ModemManager.h> +#include <glib-object.h> + +G_BEGIN_DECLS + +#define MM_TYPE_LOCATION_GPS_RAW (mm_location_gps_raw_get_type ()) +#define MM_LOCATION_GPS_RAW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_LOCATION_GPS_RAW, MMLocationGpsRaw)) +#define MM_LOCATION_GPS_RAW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_LOCATION_GPS_RAW, MMLocationGpsRawClass)) +#define MM_IS_LOCATION_GPS_RAW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_LOCATION_GPS_RAW)) +#define MM_IS_LOCATION_GPS_RAW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_LOCATION_GPS_RAW)) +#define MM_LOCATION_GPS_RAW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_LOCATION_GPS_RAW, MMLocationGpsRawClass)) + + +/* Proper longitude values will fall in the [-180,180] range + * Proper latitude values will fall in the [-90,90] range + */ +#define MM_LOCATION_GPS_RAW_LONGITUDE_UNKNOWN G_MINDOUBLE +#define MM_LOCATION_GPS_RAW_LATITUDE_UNKNOWN G_MINDOUBLE +#define MM_LOCATION_GPS_RAW_ALTITUDE_UNKNOWN G_MINDOUBLE + +typedef struct _MMLocationGpsRaw MMLocationGpsRaw; +typedef struct _MMLocationGpsRawClass MMLocationGpsRawClass; +typedef struct _MMLocationGpsRawPrivate MMLocationGpsRawPrivate; + +struct _MMLocationGpsRaw { + GObject parent; + MMLocationGpsRawPrivate *priv; +}; + +struct _MMLocationGpsRawClass { + GObjectClass parent; +}; + +GType mm_location_gps_raw_get_type (void); + +MMLocationGpsRaw *mm_location_gps_raw_new (void); +MMLocationGpsRaw *mm_location_gps_raw_new_from_dictionary (GVariant *string, + GError **error); + +const gchar *mm_location_gps_raw_get_utc_time (MMLocationGpsRaw *self); +gdouble mm_location_gps_raw_get_longitude (MMLocationGpsRaw *self); +gdouble mm_location_gps_raw_get_latitude (MMLocationGpsRaw *self); +gdouble mm_location_gps_raw_get_altitude (MMLocationGpsRaw *self); + +gboolean mm_location_gps_raw_add_trace (MMLocationGpsRaw *self, + const gchar *trace); + +GVariant *mm_location_gps_raw_get_dictionary (MMLocationGpsRaw *self); + +G_END_DECLS + +#endif /* MM_LOCATION_GPS_RAW_H */ |