From 31ab6b8f61c3c9508cdd8ecae554b7de90f300be Mon Sep 17 00:00:00 2001 From: Ankit Date: Sun, 14 Jun 2015 15:08:38 +0530 Subject: [PATCH] Create gclue_location_new_from_gga This patch creates gclue_location_new_from_gga function inside GClueLocation which will be able to construct a GClueLocation object out of a NMEA GGA sentence. https://bugs.freedesktop.org/show_bug.cgi?id=90974 --- src/gclue-location.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/gclue-location.h | 3 ++ src/gclue-modem-gps.c | 121 ++--------------------------------------------- 3 files changed, 136 insertions(+), 116 deletions(-) diff --git a/src/gclue-location.c b/src/gclue-location.c index 338d486..33a22b5 100644 --- a/src/gclue-location.c +++ b/src/gclue-location.c @@ -26,6 +26,8 @@ #include "gclue-location.h" #include +#define INVALID_COORDINATE -G_MAXDOUBLE + struct _GClueLocationPrivate { gdouble speed; gdouble heading; @@ -203,6 +205,132 @@ gclue_location_new_with_description (gdouble latitude, NULL); } +static gdouble +get_accuracy_from_hdop (gdouble hdop) +{ + /* FIXME: These are really just rough estimates based on: + * http://en.wikipedia.org/wiki/Dilution_of_precision_%28GPS%29#Meaning_of_DOP_Values + */ + if (hdop <= 1) + return 0; + else if (hdop <= 2) + return 1; + else if (hdop <= 5) + return 3; + else if (hdop <= 10) + return 50; + else if (hdop <= 20) + return 100; + else + return 300; +} + +static gdouble +parse_coordinate_string (const char *coordinate, + const char *direction) +{ + gdouble minutes, degrees, out; + gchar *degrees_str; + gchar *dot_str; + gint dot_offset; + + if (coordinate[0] == '\0' || + direction[0] == '\0' || + direction[0] == '\0') + return INVALID_COORDINATE; + + if (direction[0] != 'N' && + direction[0] != 'S' && + direction[0] != 'E' && + direction[0] != 'W') { + g_warning ("Unknown direction '%s' for coordinates, ignoring..", + direction); + return INVALID_COORDINATE; + } + + dot_str = g_strstr_len (coordinate, 6, "."); + if (dot_str == NULL) + return INVALID_COORDINATE; + dot_offset = dot_str - coordinate; + + degrees_str = g_strndup (coordinate, dot_offset - 2); + degrees = g_ascii_strtod (degrees_str, NULL); + g_free (degrees_str); + + minutes = g_ascii_strtod (coordinate + dot_offset - 2, NULL); + + /* Include the minutes as part of the degrees */ + out = degrees + (minutes / 60.0); + + if (direction[0] == 'S' || direction[0] == 'W') + out = 0 - out; + + return out; +} + +static gdouble +parse_altitude_string (const char *altitude, + const char *unit) +{ + if (altitude[0] == '\0' || unit[0] == '\0') + return GEOCODE_LOCATION_ALTITUDE_UNKNOWN; + + if (unit[0] != 'M') { + g_warning ("Unknown unit '%s' for altitude, ignoring..", + unit); + + return GEOCODE_LOCATION_ALTITUDE_UNKNOWN; + } + + return g_ascii_strtod (altitude, NULL); +} + +/** + * gclue_location_new_from_gga: + * @gga NMEA GGA sentence + * + * Creates a new #GClueLocation object from a GGA sentence. + * + * Returns: a new #GClueLocation object. Use g_object_unref() when done. + **/ +GClueLocation * +gclue_location_new_from_gga (const char *gga) +{ + GClueLocation *location = NULL; + gdouble latitude, longitude, accuracy, altitude; + gdouble hdop; /* Horizontal Dilution Of Precision */ + char **parts; + + parts = g_strsplit (gga, ",", -1); + if (g_strv_length (parts) < 14 ) { + g_warning ("Failed to parse NMEA GGA sentence:\n%s", gga); + + goto out; + } + + /* For syntax of GGA senentences: + * http://www.gpsinformation.org/dale/nmea.htm#GGA + */ + latitude = parse_coordinate_string (parts[2], parts[3]); + longitude = parse_coordinate_string (parts[4], parts[5]); + if (latitude == INVALID_COORDINATE || longitude == INVALID_COORDINATE) + goto out; + + altitude = parse_altitude_string (parts[9], parts[10]); + if (altitude == GEOCODE_LOCATION_ALTITUDE_UNKNOWN) + goto out; + + hdop = g_ascii_strtod (parts[8], NULL); + accuracy = get_accuracy_from_hdop (hdop); + + location = gclue_location_new (latitude, longitude, accuracy); + if (altitude != GEOCODE_LOCATION_ALTITUDE_UNKNOWN) + g_object_set (location, "altitude", altitude, NULL); +out: + g_strfreev (parts); + return location; +} + /** * gclue_location_get_speed: * @location: a #GClueLocation diff --git a/src/gclue-location.h b/src/gclue-location.h index 7cd0e7f..f2b9e3c 100644 --- a/src/gclue-location.h +++ b/src/gclue-location.h @@ -82,6 +82,9 @@ GClueLocation *gclue_location_new_with_description gdouble accuracy, const char *description); +GClueLocation *gclue_location_new_from_gga + (const char *gga); + void gclue_location_set_speed (GClueLocation *loc, gdouble speed); diff --git a/src/gclue-modem-gps.c b/src/gclue-modem-gps.c index 36c8b74..d34100c 100644 --- a/src/gclue-modem-gps.c +++ b/src/gclue-modem-gps.c @@ -21,7 +21,6 @@ #include #include -#include #include "gclue-modem-gps.h" #include "gclue-modem-manager.h" #include "gclue-location.h" @@ -187,128 +186,18 @@ gclue_modem_gps_get_singleton (void) return source; } -static gdouble -get_accuracy_from_hdop (gdouble hdop) -{ - /* FIXME: These are really just rough estimates based on: - * http://en.wikipedia.org/wiki/Dilution_of_precision_%28GPS%29#Meaning_of_DOP_Values - */ - if (hdop <= 1) - return 0; - else if (hdop <= 2) - return 1; - else if (hdop <= 5) - return 3; - else if (hdop <= 10) - return 50; - else if (hdop <= 20) - return 100; - else - return 300; -} - -#define INVALID_COORDINATE -G_MAXDOUBLE - -static gdouble -parse_coordinate_string (const char *coordinate, - const char *direction) -{ - gdouble minutes, degrees, out; - gchar *degrees_str; - gchar *dot_str; - gint dot_offset; - - if (coordinate[0] == '\0' || - direction[0] == '\0' || - direction[0] == '\0') - return INVALID_COORDINATE; - - if (direction[0] != 'N' && - direction[0] != 'S' && - direction[0] != 'E' && - direction[0] != 'W') { - g_warning ("Unknown direction '%s' for coordinates, ignoring..", - direction); - return INVALID_COORDINATE; - } - - dot_str = g_strstr_len (coordinate, 6, "."); - if (dot_str == NULL) - return INVALID_COORDINATE; - dot_offset = dot_str - coordinate; - - degrees_str = g_strndup (coordinate, dot_offset - 2); - degrees = g_ascii_strtod (degrees_str, NULL); - g_free (degrees_str); - - minutes = g_ascii_strtod (coordinate + dot_offset - 2, NULL); - - /* Include the minutes as part of the degrees */ - out = degrees + (minutes / 60.0); - - if (direction[0] == 'S' || direction[0] == 'W') - out = 0 - out; - - return out; -} - -static gdouble -parse_altitude_string (const char *altitude, - const char *unit) -{ - if (altitude[0] == '\0' || unit[0] == '\0') - return GEOCODE_LOCATION_ALTITUDE_UNKNOWN; - - if (unit[0] != 'M') { - g_warning ("Unknown unit '%s' for altitude, ignoring..", - unit); - - return GEOCODE_LOCATION_ALTITUDE_UNKNOWN; - } - - return g_ascii_strtod (altitude, NULL); -} - static void on_fix_gps (GClueModem *modem, const char *gga, gpointer user_data) { - GClueModemGPS *source = GCLUE_MODEM_GPS (user_data); + GClueLocationSource *source = GCLUE_LOCATION_SOURCE (user_data); GClueLocation *location; - gdouble latitude, longitude, accuracy, altitude; - gdouble hdop; /* Horizontal Dilution Of Precision */ - char **parts; - - parts = g_strsplit (gga, ",", -1); - if (g_strv_length (parts) < 14 ) { - g_warning ("Failed to parse NMEA GGA sentence:\n%s", gga); - - goto out; - } + location = gclue_location_new_from_gga (gga); - /* For sentax of GGA senentences: - * http://www.gpsinformation.org/dale/nmea.htm#GGA - */ - latitude = parse_coordinate_string (parts[2], parts[3]); - longitude = parse_coordinate_string (parts[4], parts[5]); - if (latitude == INVALID_COORDINATE || longitude == INVALID_COORDINATE) - goto out; - - altitude = parse_altitude_string (parts[9], parts[10]); - if (altitude == GEOCODE_LOCATION_ALTITUDE_UNKNOWN) - goto out; - - hdop = g_ascii_strtod (parts[8], NULL); - accuracy = get_accuracy_from_hdop (hdop); - - location = gclue_location_new (latitude, longitude, accuracy); - if (altitude != GEOCODE_LOCATION_ALTITUDE_UNKNOWN) - g_object_set (location, "altitude", altitude, NULL); - gclue_location_source_set_location (GCLUE_LOCATION_SOURCE (source), - location); -out: - g_strfreev (parts); + if (location != NULL) + gclue_location_source_set_location (source, + location); } static gboolean -- 2.1.0