libmm-common: new helper `MMModemLocationGpsRaw' object
This commit is contained in:
@@ -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 \
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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 */
|
||||
Reference in New Issue
Block a user