Commit bcba04e1 authored by Iqbal Inzamam's avatar Iqbal Inzamam

Get speed and heading from NMEA RMC sentences

fixes: #48
parent bc9e5f16
Pipeline #33864 passed with stage
in 1 minute and 49 seconds
......@@ -30,6 +30,7 @@
#define TIME_DIFF_THRESHOLD 60000000 /* 60 seconds */
#define EARTH_RADIUS_KM 6372.795
#define KNOTS_TO_MPS_FACTOR 0.51444
struct _GClueLocationPrivate {
char *description;
......@@ -656,6 +657,72 @@ out:
return location;
}
/**
* gclue_location_create_from_rmc:
* @rmc: NMEA RMC sentence
* @error: Place-holder for errors.
*
* Creates a new #GClueLocation object from an RMC sentence.
*
* Returns: a new #GClueLocation object, or %NULL on error. Unref using
* #g_object_unref() when done with it.
**/
GClueLocation *
gclue_location_create_from_rmc (const char *rmc,
GClueLocation *previous_location, GError **error)
{
GClueLocation *location = NULL;
gdouble latitude, longitude, accuracy, altitude, speed, heading;
guint64 timestamp;
char **parts;
parts = g_strsplit (rmc, ",", -1);
if (g_strv_length (parts) < 13) {
g_set_error_literal (error,
G_IO_ERROR,
G_IO_ERROR_INVALID_ARGUMENT,
"Invalid NMEA RMC sentence");
goto out;
}
/* For syntax of GGA sentences:
* http://www.gpsinformation.org/dale/nmea.htm#RMC
*/
timestamp = parse_nmea_timestamp (parts[1]);
latitude = parse_coordinate_string (parts[3], parts[4]);
longitude = parse_coordinate_string (parts[5], parts[6]);
if (latitude == INVALID_COORDINATE || longitude == INVALID_COORDINATE) {
g_set_error_literal (error,
G_IO_ERROR,
G_IO_ERROR_INVALID_ARGUMENT,
"Invalid NMEA RMC sentence");
goto out;
}
speed = g_ascii_strtod (parts[7], NULL) * KNOTS_TO_MPS_FACTOR;
heading = g_ascii_strtod (parts[8], NULL);
location = g_object_new (GCLUE_TYPE_LOCATION,
"latitude", latitude,
"longitude", longitude,
"timestamp", timestamp,
"speed", speed,
"heading", heading,
NULL);
if (previous_location != NULL) {
accuracy = gclue_location_get_accuracy (previous_location);
g_object_set (location, "accuracy", accuracy, NULL);
altitude = gclue_location_get_altitude (previous_location);
g_object_set (location, "altitude", altitude, NULL);
}
out:
g_strfreev (parts);
return location;
}
/**
* gclue_location_duplicate:
* @location: the #GClueLocation instance to duplicate.
......
......@@ -141,6 +141,11 @@ GClueLocation *gclue_location_create_from_gga
(const char *gga,
GError **error);
GClueLocation *gclue_location_create_from_rmc
(const char *rmc,
GClueLocation *previous_location,
GError **error);
GClueLocation *gclue_location_duplicate
(GClueLocation *location);
......
......@@ -210,23 +210,28 @@ gclue_modem_gps_get_singleton (void)
static void
on_fix_gps (GClueModem *modem,
const char *gga,
const char *rmc,
gpointer user_data)
{
GClueLocationSource *source = GCLUE_LOCATION_SOURCE (user_data);
GClueLocation *location;
GError *error = NULL;
GError *error = NULL, *error_rmc = NULL;
location = gclue_location_create_from_gga (gga, &error);
if (error != NULL) {
g_warning ("Error: %s", error->message);
g_clear_error (&error);
return;
}
gclue_location_source_set_location (source,
location);
location = gclue_location_create_from_rmc (rmc, location, &error_rmc);
if (error == NULL || error_rmc == NULL) {
gclue_location_source_set_location
(GCLUE_LOCATION_SOURCE (source), location);
} else if (error != NULL) {
g_warning ("Error: %s", error->message);
g_clear_error (&error);
} else {
g_warning ("Error: %s", error_rmc->message);
g_clear_error (&error_rmc);
}
return;
}
static gboolean
......
......@@ -383,7 +383,7 @@ on_get_gps_nmea_ready (GObject *source_object,
GClueModemManagerPrivate *priv = manager->priv;
MMModemLocation *modem_location = MM_MODEM_LOCATION (source_object);
MMLocationGpsNmea *location_nmea;
const char *gga;
const char *gga, *rmc;
GError *error = NULL;
location_nmea = mm_modem_location_get_gps_nmea_finish (modem_location,
......@@ -402,8 +402,9 @@ on_get_gps_nmea_ready (GObject *source_object,
}
gga = mm_location_gps_nmea_get_trace (location_nmea, "$GPGGA");
if (gga == NULL) {
g_debug ("No GGA trace");
rmc = mm_location_gps_nmea_get_trace (location_nmea, "$GPRMC");
if (gga == NULL && rmc == NULL) {
g_debug ("No GGA or RMC trace");
return;
}
......@@ -415,7 +416,8 @@ on_get_gps_nmea_ready (GObject *source_object,
priv->location_nmea = location_nmea;
g_debug ("New GPGGA trace: %s", gga);
g_signal_emit (manager, signals[FIX_GPS], 0, gga);
g_debug ("New GPRMC trace: %s", rmc);
g_signal_emit (manager, signals[FIX_GPS], 0, gga, rmc);
}
static void
......
......@@ -442,15 +442,44 @@ browse_callback (AvahiServiceBrowser *service_browser,
}
}
static gboolean
is_gga (char* message) {
if (!g_str_has_prefix (message, "$GAGGA") && /* Galieo */
!g_str_has_prefix (message, "$GBGGA") && /* BeiDou */
!g_str_has_prefix (message, "$BDGGA") && /* BeiDou */
!g_str_has_prefix (message, "$GLGGA") && /* GLONASS */
!g_str_has_prefix (message, "$GNGGA") && /* GNSS (combined) */
!g_str_has_prefix (message, "$GPGGA") && /* GPS, SBAS, QZSS */
!g_str_has_prefix (message, "$QZGGA")) /* QZSS */
return FALSE;
return TRUE;
}
static gboolean
is_rmc (char *message) {
if (!g_str_has_prefix (message, "$GARMC") && /* Galieo */
!g_str_has_prefix (message, "$GBRMC") && /* BeiDou */
!g_str_has_prefix (message, "$BDRMC") && /* BeiDou */
!g_str_has_prefix (message, "$GLRMC") && /* GLONASS */
!g_str_has_prefix (message, "$GNRMC") && /* GNSS (combined) */
!g_str_has_prefix (message, "$GPRMC") && /* GPS, SBAS, QZSS */
!g_str_has_prefix (message, "$QZRMC")) /* QZSS */
return FALSE;
return TRUE;
}
static void
on_read_gga_sentence (GObject *object,
on_read_nmea_sentence (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GClueNMEASource *source = GCLUE_NMEA_SOURCE (user_data);
GDataInputStream *data_input_stream = G_DATA_INPUT_STREAM (object);
GError *error = NULL;
GClueLocation *location;
GClueLocation *location = NULL;
gsize data_size = 0 ;
char *message;
......@@ -482,20 +511,18 @@ on_read_gga_sentence (GObject *object,
}
g_debug ("Network source sent: \"%s\"", message);
if (!g_str_has_prefix (message, "$GAGGA") && /* Galieo */
!g_str_has_prefix (message, "$GBGGA") && /* BeiDou */
!g_str_has_prefix (message, "$BDGGA") && /* BeiDou */
!g_str_has_prefix (message, "$GLGGA") && /* GLONASS */
!g_str_has_prefix (message, "$GNGGA") && /* GNSS (combined) */
!g_str_has_prefix (message, "$GPGGA") && /* GPS, SBAS, QZSS */
!g_str_has_prefix (message, "$QZGGA")) { /* QZSS */
g_debug ("Ignoring non-GGA sentence from NMEA source");
if (!(is_gga (message) || is_rmc (message))){
g_debug ("Search till either GGA or RMC sentence is found");
goto READ_NEXT_LINE;
}
location = gclue_location_create_from_gga (message, &error);
if (is_gga (message)) {
location = gclue_location_create_from_gga (message, &error);
} else {
location = gclue_location_create_from_rmc (message, NULL, &error);
}
if (error != NULL) {
g_warning ("Error: %s", error->message);
g_clear_error (&error);
......@@ -508,7 +535,7 @@ READ_NEXT_LINE:
g_data_input_stream_read_line_async (data_input_stream,
G_PRIORITY_DEFAULT,
source->priv->cancellable,
on_read_gga_sentence,
on_read_nmea_sentence,
source);
}
......@@ -543,7 +570,7 @@ on_connection_to_location_server (GObject *object,
g_data_input_stream_read_line_async (data_input_stream,
G_PRIORITY_DEFAULT,
source->priv->cancellable,
on_read_gga_sentence,
on_read_nmea_sentence,
source);
}
......@@ -727,3 +754,4 @@ gclue_nmea_source_stop (GClueLocationSource *source)
return TRUE;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment