pud: update nmealib to 3.0.0
authorFerry Huberts <ferry.huberts@pelagic.nl>
Tue, 19 Jul 2016 19:24:03 +0000 (21:24 +0200)
committerFerry Huberts <ferry.huberts@pelagic.nl>
Tue, 19 Jul 2016 19:24:03 +0000 (21:24 +0200)
Signed-off-by: Ferry Huberts <ferry.huberts@pelagic.nl>
58 files changed:
lib/httpinfo/src/olsrd_httpinfo.c
lib/jsoninfo/src/olsrd_jsoninfo.c
lib/pud/nmealib/.gitignore
lib/pud/nmealib/COPYRIGHT
lib/pud/nmealib/Makefile
lib/pud/nmealib/Makefile.inc
lib/pud/nmealib/doc/Makefile
lib/pud/nmealib/doc/nmea.doxygen
lib/pud/nmealib/include/nmea/context.h [deleted file]
lib/pud/nmealib/include/nmea/conversions.h [deleted file]
lib/pud/nmealib/include/nmea/generate.h [deleted file]
lib/pud/nmealib/include/nmea/generator.h [deleted file]
lib/pud/nmealib/include/nmea/gmath.h [deleted file]
lib/pud/nmealib/include/nmea/info.h [deleted file]
lib/pud/nmealib/include/nmea/parse.h [deleted file]
lib/pud/nmealib/include/nmea/parser.h [deleted file]
lib/pud/nmealib/include/nmea/sentence.h [deleted file]
lib/pud/nmealib/include/nmea/tok.h [deleted file]
lib/pud/nmealib/include/nmealib/context.h [new file with mode: 0644]
lib/pud/nmealib/include/nmealib/generator.h [new file with mode: 0644]
lib/pud/nmealib/include/nmealib/gpgga.h [new file with mode: 0644]
lib/pud/nmealib/include/nmealib/gpgsa.h [new file with mode: 0644]
lib/pud/nmealib/include/nmealib/gpgsv.h [new file with mode: 0644]
lib/pud/nmealib/include/nmealib/gprmc.h [new file with mode: 0644]
lib/pud/nmealib/include/nmealib/gpvtg.h [new file with mode: 0644]
lib/pud/nmealib/include/nmealib/info.h [new file with mode: 0644]
lib/pud/nmealib/include/nmealib/nmath.h [new file with mode: 0644]
lib/pud/nmealib/include/nmealib/parser.h [new file with mode: 0644]
lib/pud/nmealib/include/nmealib/sentence.h [new file with mode: 0644]
lib/pud/nmealib/include/nmealib/util.h [new file with mode: 0644]
lib/pud/nmealib/include/nmealib/validate.h [new file with mode: 0644]
lib/pud/nmealib/src/context.c
lib/pud/nmealib/src/conversions.c [deleted file]
lib/pud/nmealib/src/generate.c [deleted file]
lib/pud/nmealib/src/generator.c
lib/pud/nmealib/src/gmath.c [deleted file]
lib/pud/nmealib/src/gpgga.c [new file with mode: 0644]
lib/pud/nmealib/src/gpgsa.c [new file with mode: 0644]
lib/pud/nmealib/src/gpgsv.c [new file with mode: 0644]
lib/pud/nmealib/src/gprmc.c [new file with mode: 0644]
lib/pud/nmealib/src/gpvtg.c [new file with mode: 0644]
lib/pud/nmealib/src/info.c
lib/pud/nmealib/src/nmath.c [new file with mode: 0644]
lib/pud/nmealib/src/parse.c [deleted file]
lib/pud/nmealib/src/parser.c
lib/pud/nmealib/src/random.h [deleted file]
lib/pud/nmealib/src/sentence.c
lib/pud/nmealib/src/tok.c [deleted file]
lib/pud/nmealib/src/util.c [new file with mode: 0644]
lib/pud/nmealib/src/validate.c [new file with mode: 0644]
lib/pud/src/configuration.c
lib/pud/src/gpsConversion.c
lib/pud/src/gpsConversion.h
lib/pud/src/posAvg.c
lib/pud/src/posAvg.h
lib/pud/src/posFile.c
lib/pud/src/posFile.h
lib/pud/src/receiver.c

index 6cd0960..65df14a 100644 (file)
@@ -73,8 +73,8 @@
 #include "common/autobuf.h"
 #include <pud/src/receiver.h>
 #include <pud/src/pud.h>
-#include <nmea/info.h>
-#include <nmea/sentence.h>
+#include <nmealib/info.h>
+#include <nmealib/sentence.h>
 
 #include "olsrd_httpinfo.h"
 #include "admin_interface.h"
@@ -1148,8 +1148,8 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* utc */
        abuf_puts(abuf, "<tr><td>Date / Time</td><td></td><td>UTC</td><td></td><td id=\"utc\">");
-       datePresent = nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, UTCDATE);
-       timePresent = nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, UTCTIME);
+       datePresent = nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_UTCDATE);
+       timePresent = nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_UTCTIME);
        if (datePresent || timePresent) {
                if (datePresent) {
                        abuf_appendf(abuf, "%04d%02d%02d",
@@ -1179,8 +1179,8 @@ static void build_pud_body(struct autobuf *abuf) {
     bool printed = false;
     int i = 1;
     int count = 0;
-    while (i <= _nmeaINFO_FIELD_LAST) {
-      const char * s = nmea_INFO_field_to_string(i & present);
+    while (i <= NMEALIB_PRESENT_LAST) {
+      const char * s = nmeaInfoFieldToString(i & present);
       if (s) {
         if (printed) {
           if (count >= 8) {
@@ -1203,13 +1203,13 @@ static void build_pud_body(struct autobuf *abuf) {
 
   /* smask */
   abuf_puts(abuf, "<tr><td>Input Sentences</td><td></td><td></td><td></td><td id=\"smask\">");
-  if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, SMASK) //
-      && (txGpsInfo->txPosition.nmeaInfo.smask != GPNON)) {
+  if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_SMASK) //
+      && (txGpsInfo->txPosition.nmeaInfo.smask != NMEALIB_SENTENCE_GPNON)) {
     int smask = txGpsInfo->txPosition.nmeaInfo.smask;
     bool printed = false;
     int i = 1;
-    while (i <= _nmeaPACKTYPE_LAST) {
-      const char * s = nmea_INFO_smask_packtype_to_string(i & smask);
+    while (i <= NMEALIB_SENTENCE_LAST) {
+      const char * s = nmeaSentenceToPrefix(i & smask);
       if (s) {
         if (printed)
           abuf_puts(abuf, "&nbsp;");
@@ -1225,8 +1225,8 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* sig */
        abuf_puts(abuf, "<tr><td>Signal Strength</td><td></td><td></td><td></td><td id=\"sig\">");
-       if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, SIG)) {
-               const char * s = nmea_INFO_sig_to_string(txGpsInfo->txPosition.nmeaInfo.sig);
+       if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_SIG)) {
+               const char * s = nmeaInfoSignalToString(txGpsInfo->txPosition.nmeaInfo.sig);
                abuf_appendf(abuf, "%s (%d)", s, txGpsInfo->txPosition.nmeaInfo.sig);
        } else {
                abuf_puts(abuf, NA_STRING);
@@ -1235,8 +1235,8 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* fix */
        abuf_puts(abuf, "<tr><td>Fix</td><td></td><td></td><td></td><td id=\"fix\">");
-       if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, FIX)) {
-               const char * s = nmea_INFO_fix_to_string(txGpsInfo->txPosition.nmeaInfo.fix);
+       if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_FIX)) {
+               const char * s = nmeaInfoFixToString(txGpsInfo->txPosition.nmeaInfo.fix);
                abuf_appendf(abuf, "%s (%d)", s, txGpsInfo->txPosition.nmeaInfo.fix);
        } else {
                abuf_puts(abuf, NA_STRING);
@@ -1245,8 +1245,8 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* PDOP */
        abuf_puts(abuf, "<tr><td>PDOP</td><td></td><td></td><td></td><td id=\"pdop\">");
-       if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, PDOP)) {
-               abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.PDOP);
+       if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_PDOP)) {
+               abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.pdop);
        } else {
                abuf_puts(abuf, NA_STRING);
        }
@@ -1254,8 +1254,8 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* HDOP */
        abuf_puts(abuf, "<tr><td>HDOP</td><td></td><td></td><td></td><td id=\"hdop\">");
-       if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, HDOP)) {
-               abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.HDOP);
+       if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_HDOP)) {
+               abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.hdop);
        } else {
                abuf_puts(abuf, NA_STRING);
        }
@@ -1263,8 +1263,8 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* VDOP */
        abuf_puts(abuf, "<tr><td>VDOP</td><td></td><td></td><td></td><td id=\"vdop\">");
-       if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, VDOP)) {
-               abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.VDOP);
+       if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_VDOP)) {
+               abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.vdop);
        } else {
                abuf_puts(abuf, NA_STRING);
        }
@@ -1272,8 +1272,8 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* lat */
        abuf_puts(abuf, "<tr><td>Latitude</td><td></td><td>degrees</td><td></td><td id=\"lat\">");
-       if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, LAT)) {
-               abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.lat);
+       if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_LAT)) {
+               abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.latitude);
        } else {
                abuf_puts(abuf, NA_STRING);
        }
@@ -1281,8 +1281,8 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* lon */
        abuf_puts(abuf, "<tr><td>Longitude</td><td></td><td>degrees</td><td></td><td id=\"lon\">");
-       if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, LON)) {
-               abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.lon);
+       if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_LON)) {
+               abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.longitude);
        } else {
                abuf_puts(abuf, NA_STRING);
        }
@@ -1290,8 +1290,8 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* elv */
        abuf_puts(abuf, "<tr><td>Elevation</td><td></td><td>m</td><td></td><td id=\"elv\">");
-       if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, ELV)) {
-               abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.elv);
+       if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_ELV)) {
+               abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.elevation);
        } else {
                abuf_puts(abuf, NA_STRING);
        }
@@ -1299,7 +1299,7 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* speed */
        abuf_puts(abuf, "<tr><td>Speed</td><td></td><td>kph</td><td></td><td id=\"speed\">");
-       if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, SPEED)) {
+       if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_SPEED)) {
                abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.speed);
        } else {
                abuf_puts(abuf, NA_STRING);
@@ -1308,7 +1308,7 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* track */
        abuf_puts(abuf, "<tr><td>Track</td><td></td><td>degrees</td><td></td><td id=\"track\">");
-       if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, TRACK)) {
+       if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_TRACK)) {
                abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.track);
        } else {
                abuf_puts(abuf, NA_STRING);
@@ -1317,7 +1317,7 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* mtrack */
        abuf_puts(abuf, "<tr><td>Magnetic Track</td><td></td><td>degrees</td><td></td><td id=\"mtrack\">");
-       if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, MTRACK)) {
+       if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_MTRACK)) {
                abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.mtrack);
        } else {
                abuf_puts(abuf, NA_STRING);
@@ -1326,7 +1326,7 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* magvar */
        abuf_puts(abuf, "<tr><td>Magnetic Variation</td><td></td><td>degrees</td><td></td><td id=\"magvar\">");
-       if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, MAGVAR)) {
+       if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_MAGVAR)) {
                abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.magvar);
        } else {
                abuf_puts(abuf, NA_STRING);
@@ -1337,7 +1337,7 @@ static void build_pud_body(struct autobuf *abuf) {
        abuf_puts(abuf, "</table></p>\n");
 
        /* sats */
-       if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, SATINVIEW)) {
+       if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_SATINVIEW)) {
                int cnt = 0;
 
                abuf_puts(abuf, "<p>\n");
@@ -1347,20 +1347,20 @@ static void build_pud_body(struct autobuf *abuf) {
                abuf_puts(abuf,
                                "<tr><th>ID</th><th>In Use</th><th>Elevation (degrees)</th><th>Azimuth (degrees)</th><th>Signal (dB)</th></tr>\n");
 
-               if (txGpsInfo->txPosition.nmeaInfo.satinfo.inview) {
-                       int satIndex;
-                       for (satIndex = 0; satIndex < NMEA_MAXSAT; satIndex++) {
-                               nmeaSATELLITE * sat = &txGpsInfo->txPosition.nmeaInfo.satinfo.sat[satIndex];
-                               if (sat->id) {
+               if (txGpsInfo->txPosition.nmeaInfo.satellites.inViewCount) {
+                       size_t satIndex;
+                       for (satIndex = 0; satIndex < NMEALIB_MAX_SATELLITES; satIndex++) {
+                         NmeaSatellite * sat = &txGpsInfo->txPosition.nmeaInfo.satellites.inView[satIndex];
+                               if (sat->prn) {
                                        bool inuse = false;
                                        const char * inuseStr;
 
-                                       if (!nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, SATINUSE)) {
+                                       if (!nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_SATINUSE)) {
                                                inuseStr = NA_STRING;
                                        } else {
-                                               int inuseIndex;
-                                               for (inuseIndex = 0; inuseIndex < NMEA_MAXSAT; inuseIndex++) {
-                                                       if (txGpsInfo->txPosition.nmeaInfo.satinfo.in_use[inuseIndex] == sat->id) {
+                                               size_t inuseIndex;
+                                               for (inuseIndex = 0; inuseIndex < NMEALIB_MAX_SATELLITES; inuseIndex++) {
+                                                       if (txGpsInfo->txPosition.nmeaInfo.satellites.inUse[inuseIndex] == sat->prn) {
                                                                inuse = true;
                                                                break;
                                                        }
@@ -1372,8 +1372,8 @@ static void build_pud_body(struct autobuf *abuf) {
                                                }
                                        }
 
-                                       abuf_appendf(abuf, "<tr><td>%02d</td><td bgcolor=\"%s\">%s</td><td>%02d</td><td>%03d</td><td>%02d</td></tr>\n",
-                                                       sat->id, inuse ? SAT_INUSE_COLOR : SAT_NOTINUSE_COLOR, inuseStr, sat->elv, sat->azimuth, sat->sig);
+                                       abuf_appendf(abuf, "<tr><td>%02u</td><td bgcolor=\"%s\">%s</td><td>%02d</td><td>%03u</td><td>%02d</td></tr>\n",
+                                                       sat->prn, inuse ? SAT_INUSE_COLOR : SAT_NOTINUSE_COLOR, inuseStr, sat->elevation, sat->azimuth, sat->snr);
                                        cnt++;
                                }
                        }
@@ -1388,15 +1388,15 @@ static void build_pud_body(struct autobuf *abuf) {
        }
 
        /* add Google Maps and OpenStreetMap links when we have both lat and lon */
-       if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, LAT)
-                       && nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, LON)) {
+       if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_LAT)
+                       && nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_LON)) {
                const char * c = nodeId;
 
                abuf_appendf(abuf,
                        "<p>\n"
                        "<a href=\"http://maps.google.com/maps?q=%f,+%f+%%28",
-                       txGpsInfo->txPosition.nmeaInfo.lat,
-                       txGpsInfo->txPosition.nmeaInfo.lon
+                       txGpsInfo->txPosition.nmeaInfo.latitude,
+                       txGpsInfo->txPosition.nmeaInfo.longitude
                );
 
                while (*c != '\0') {
@@ -1413,8 +1413,8 @@ static void build_pud_body(struct autobuf *abuf) {
                abuf_appendf(abuf,
                        "<p>\n"
                        "<a href=\"http://www.openstreetmap.org/index.html?mlat=%f&amp;mlon=%f&amp;zoom=15&amp;layers=M\">Show on OpenStreetMap</a></p>\n",
-                       txGpsInfo->txPosition.nmeaInfo.lat,
-                       txGpsInfo->txPosition.nmeaInfo.lon
+                       txGpsInfo->txPosition.nmeaInfo.latitude,
+                       txGpsInfo->txPosition.nmeaInfo.longitude
                );
        }
 }
index 5ecdb42..4e3e495 100644 (file)
@@ -64,8 +64,8 @@
 #include "info/json_helpers.h"
 #include "gateway_default_handler.h"
 #include "egressTypes.h"
-#include "nmea/info.h"
-#include "nmea/sentence.h"
+#include "nmealib/info.h"
+#include "nmealib/sentence.h"
 
 #define UUIDLEN 256
 char uuid[UUIDLEN];
@@ -900,7 +900,7 @@ void ipc_print_pud_position(struct autobuf *abuf) {
   }
 
   /* utc */
-  if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, UTCDATE)) {
+  if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_UTCDATE)) {
     abuf_json_mark_object(&json_session, true, false, abuf, "date");
     abuf_json_int(&json_session, abuf, "year", txGpsInfo->txPosition.nmeaInfo.utc.year + 1900);
     abuf_json_int(&json_session, abuf, "month", txGpsInfo->txPosition.nmeaInfo.utc.mon + 1);
@@ -908,7 +908,7 @@ void ipc_print_pud_position(struct autobuf *abuf) {
     abuf_json_mark_object(&json_session, false, false, abuf, NULL);
   }
 
-  if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, UTCTIME)) {
+  if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_UTCTIME)) {
     abuf_json_mark_object(&json_session, true, false, abuf, "time");
     abuf_json_int(&json_session, abuf, "hour", txGpsInfo->txPosition.nmeaInfo.utc.hour);
     abuf_json_int(&json_session, abuf, "minute", txGpsInfo->txPosition.nmeaInfo.utc.min);
@@ -921,9 +921,9 @@ void ipc_print_pud_position(struct autobuf *abuf) {
   abuf_json_mark_object(&json_session, true, true, abuf, "present");
   {
     uint32_t present = txGpsInfo->txPosition.nmeaInfo.present;
-    int i = 1;
-    while (i <= _nmeaINFO_FIELD_LAST) {
-      const char * s = nmea_INFO_field_to_string(present & i);
+    size_t i = 1;
+    while (i <= NMEALIB_PRESENT_LAST) {
+      const char * s = nmeaInfoFieldToString(present & i);
       if (s) {
         abuf_json_string(&json_session, abuf, NULL, s);
       }
@@ -934,13 +934,13 @@ void ipc_print_pud_position(struct autobuf *abuf) {
   abuf_json_int(&json_session, abuf, "presentValue", txGpsInfo->txPosition.nmeaInfo.present);
 
   /* smask */
-  if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, SMASK)) {
+  if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_SMASK)) {
     int smask = txGpsInfo->txPosition.nmeaInfo.smask;
     abuf_json_mark_object(&json_session, true, true, abuf, "smask");
-    if (smask != GPNON) {
+    if (smask != NMEALIB_SENTENCE_GPNON) {
       int i = 1;
-      while (i <= _nmeaPACKTYPE_LAST) {
-        const char * s = nmea_INFO_smask_packtype_to_string(smask & i);
+      while (i <= NMEALIB_SENTENCE_LAST) {
+        const char * s = nmeaSentenceToPrefix(smask & i);
         if (s) {
           abuf_json_string(&json_session, abuf, NULL, s);
         }
@@ -952,103 +952,103 @@ void ipc_print_pud_position(struct autobuf *abuf) {
   }
 
   /* sig */
-  if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, SIG)) {
-    abuf_json_string(&json_session, abuf, "sig", nmea_INFO_sig_to_string(txGpsInfo->txPosition.nmeaInfo.sig));
+  if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_SIG)) {
+    abuf_json_string(&json_session, abuf, "sig", nmeaInfoSignalToString(txGpsInfo->txPosition.nmeaInfo.sig));
     abuf_json_int(&json_session, abuf, "sigValue", txGpsInfo->txPosition.nmeaInfo.sig);
   }
 
   /* fix */
-  if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, FIX)) {
-    abuf_json_string(&json_session, abuf, "fix", nmea_INFO_fix_to_string(txGpsInfo->txPosition.nmeaInfo.fix));
+  if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_FIX)) {
+    abuf_json_string(&json_session, abuf, "fix", nmeaInfoFixToString(txGpsInfo->txPosition.nmeaInfo.fix));
     abuf_json_int(&json_session, abuf, "fixValue", txGpsInfo->txPosition.nmeaInfo.fix);
   }
 
   /* PDOP */
-  if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, PDOP)) {
-    abuf_json_float(&json_session, abuf, "pdop", txGpsInfo->txPosition.nmeaInfo.PDOP);
+  if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_PDOP)) {
+    abuf_json_float(&json_session, abuf, "pdop", txGpsInfo->txPosition.nmeaInfo.pdop);
   }
 
   /* HDOP */
-  if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, HDOP)) {
-    abuf_json_float(&json_session, abuf, "hdop", txGpsInfo->txPosition.nmeaInfo.HDOP);
+  if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_HDOP)) {
+    abuf_json_float(&json_session, abuf, "hdop", txGpsInfo->txPosition.nmeaInfo.hdop);
   }
 
   /* VDOP */
-  if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, VDOP)) {
-    abuf_json_float(&json_session, abuf, "vdop", txGpsInfo->txPosition.nmeaInfo.VDOP);
+  if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_VDOP)) {
+    abuf_json_float(&json_session, abuf, "vdop", txGpsInfo->txPosition.nmeaInfo.vdop);
   }
 
   /* lat */
-  if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, LAT)) {
-    abuf_json_float(&json_session, abuf, "latitude", txGpsInfo->txPosition.nmeaInfo.lat);
+  if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_LAT)) {
+    abuf_json_float(&json_session, abuf, "latitude", txGpsInfo->txPosition.nmeaInfo.latitude);
   }
 
   /* lon */
-  if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, LON)) {
-    abuf_json_float(&json_session, abuf, "longitude", txGpsInfo->txPosition.nmeaInfo.lon);
+  if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_LON)) {
+    abuf_json_float(&json_session, abuf, "longitude", txGpsInfo->txPosition.nmeaInfo.longitude);
   }
 
   /* elv */
-  if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, ELV)) {
-    abuf_json_float(&json_session, abuf, "elevation", txGpsInfo->txPosition.nmeaInfo.elv);
+  if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_ELV)) {
+    abuf_json_float(&json_session, abuf, "elevation", txGpsInfo->txPosition.nmeaInfo.elevation);
   }
 
   /* speed */
-  if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, SPEED)) {
+  if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_SPEED)) {
     abuf_json_float(&json_session, abuf, "speed", txGpsInfo->txPosition.nmeaInfo.speed);
   }
 
   /* track */
-  if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, TRACK)) {
+  if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_TRACK)) {
     abuf_json_float(&json_session, abuf, "track", txGpsInfo->txPosition.nmeaInfo.track);
   }
 
   /* mtrack */
-  if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, MTRACK)) {
+  if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_MTRACK)) {
     abuf_json_float(&json_session, abuf, "magneticTrack", txGpsInfo->txPosition.nmeaInfo.mtrack);
   }
 
   /* magvar */
-  if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, MAGVAR)) {
+  if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_MAGVAR)) {
     abuf_json_float(&json_session, abuf, "magneticVariation", txGpsInfo->txPosition.nmeaInfo.magvar);
   }
 
   /* sats */
-  if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, SATINUSECOUNT | SATINUSE | SATINVIEW)) {
-    nmeaSATINFO * satinfo = &txGpsInfo->txPosition.nmeaInfo.satinfo;
-    int i = 0;
+  if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_SATINUSECOUNT | NMEALIB_PRESENT_SATINUSE | NMEALIB_PRESENT_SATINVIEW)) {
+    NmeaSatellites * satinfo = &txGpsInfo->txPosition.nmeaInfo.satellites;
+    size_t i = 0;
 
     abuf_json_mark_object(&json_session, true, false, abuf, "satellites");
 
-    if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, SATINUSECOUNT)) {
-      abuf_json_int(&json_session, abuf, "inUseCount", satinfo->inuse);
+    if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_SATINUSECOUNT)) {
+      abuf_json_int(&json_session, abuf, "inUseCount", satinfo->inUseCount);
     }
 
-    if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, SATINUSE)) {
+    if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_SATINUSE)) {
       abuf_json_mark_object(&json_session, true, true, abuf, "inUse");
-      for (i = 0; i < NMEA_MAXSAT; i++) {
-        int inuse = satinfo->in_use[i];
-        if (inuse) {
-          abuf_json_int(&json_session, abuf, NULL, inuse);
+      for (i = 0; i < NMEALIB_MAX_SATELLITES; i++) {
+        unsigned int prn = satinfo->inUse[i];
+        if (prn) {
+          abuf_json_int(&json_session, abuf, NULL, prn);
         }
       }
       abuf_json_mark_object(&json_session, false, true, abuf, NULL);
     }
 
-    if (nmea_INFO_is_present(txGpsInfo->txPosition.nmeaInfo.present, SATINVIEW)) {
-      abuf_json_int(&json_session, abuf, "inViewCount", satinfo->inview);
+    if (nmeaInfoIsPresentAll(txGpsInfo->txPosition.nmeaInfo.present, NMEALIB_PRESENT_SATINVIEW)) {
+      abuf_json_int(&json_session, abuf, "inViewCount", satinfo->inViewCount);
       abuf_json_mark_object(&json_session, true, true, abuf, "inView");
-      for (i = 0; i < NMEA_MAXSAT; i++) {
-        nmeaSATELLITE * sat = &satinfo->sat[i];
-        if (!sat->id) {
+      for (i = 0; i < NMEALIB_MAX_SATELLITES; i++) {
+        NmeaSatellite * sat = &satinfo->inView[i];
+        if (!sat->prn) {
           continue;
         }
 
         abuf_json_mark_object(&json_session, true, false, abuf, NULL);
-        abuf_json_int(&json_session, abuf, "id", sat->id);
-        abuf_json_int(&json_session, abuf, "elevation", sat->elv);
+        abuf_json_int(&json_session, abuf, "id", sat->prn);
+        abuf_json_int(&json_session, abuf, "elevation", sat->elevation);
         abuf_json_int(&json_session, abuf, "azimuth", sat->azimuth);
-        abuf_json_int(&json_session, abuf, "signal", sat->sig);
+        abuf_json_int(&json_session, abuf, "signal", sat->snr);
         abuf_json_mark_object(&json_session, false, false, abuf, NULL);
       }
       abuf_json_mark_object(&json_session, false, true, abuf, NULL);
index 8e0bc29..c508200 100644 (file)
@@ -1,2 +1,2 @@
 /build/
-/lib/
+/lib/
\ No newline at end of file
index b3e55da..fdfdec9 100644 (file)
@@ -6,5 +6,5 @@ Copyrights may apply to all sources or to parts, use our Git repository to
 find out which parts have copyrights by whom.
 
 * Copyright (c) 2008      Timur Sinitsyn
-* Copyright (c) 2011-2014 Ferry Huberts
+* Copyright (c) 2011-2016 Ferry Huberts
 * Copyright (c) 2014      Tobias Simon
\ No newline at end of file
index 201dc35..5823423 100644 (file)
@@ -11,22 +11,25 @@ include Makefile.inc
 # Settings
 #
 
-LIBNAME = libnmea.so
-LIBNAMESTATIC = libnmea.a
-
 DESTDIR ?=
 USRDIR ?= $(DESTDIR)/usr
 INCLUDEDIR ?= $(DESTDIR)/usr/include
 LIBDIR ?= $(USRDIR)/lib
 
+H_FILES = $(wildcard include/nmealib/*.h)
+C_FILES = $(wildcard src/*.c)
+
+MODULES = $(C_FILES:src/%.c=%)
 
-MODULES = context conversions generate generator gmath info parse parser sentence tok
 OBJ = $(MODULES:%=build/%.o)
 
 LIBRARIES = -lm
 INCLUDES = -I ./include
 
 
+.PRECIOUS: $(OBJ)
+
+
 #
 # Targets
 #
@@ -49,27 +52,35 @@ ifeq ($(VERBOSE),0)
 endif
        $(MAKECMDPREFIX)$(CC) $(LDFLAGS) -Wl,-soname=$(LIBNAME) -o "$@" $(LIBRARIES) $(OBJ)
 
-build/%.o: src/%.c Makefile Makefile.inc
+build/%.o: src/%.c $(H_FILES) Makefile Makefile.inc
 ifeq ($(VERBOSE),0)
        @echo "[CC] $<"
 endif
        $(MAKECMDPREFIX)$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
 
+full : all
+
 
 #
 # Phony Targets
 #
 
-.PHONY: all default_target all-before clean doc install install-headers uninstall uninstall-headers
+.PHONY: all-before clean doc doc-pdf doc-all doc-clean install install-headers uninstall uninstall-headers
 
 all-before:
        $(MAKECMDPREFIX)mkdir -p build lib
 
 clean:
        $(MAKECMDPREFIX)$(MAKE) -C doc clean
-       $(MAKECMDPREFIX)rm -frv build lib
+       $(MAKECMDPREFIX)rm -fr build lib
 
 doc:
+       $(MAKECMDPREFIX)$(MAKE) -C doc doc
+
+doc-pdf:
+       $(MAKECMDPREFIX)$(MAKE) -C doc doc-pdf
+
+doc-all:
        $(MAKECMDPREFIX)$(MAKE) -C doc all
 
 doc-clean:
@@ -83,8 +94,8 @@ install: all
 
 install-headers: all
        $(MAKECMDPREFIX)mkdir -v -p "$(INCLUDEDIR)"
-       $(MAKECMDPREFIX)rm -fr "$(INCLUDEDIR)/nmea"
-       $(MAKECMDPREFIX)cp -rv include/nmea "$(INCLUDEDIR)"
+       $(MAKECMDPREFIX)rm -fr "$(INCLUDEDIR)/nmealib"
+       $(MAKECMDPREFIX)cp -rv include/nmealib "$(INCLUDEDIR)"
 
 uninstall:
        $(MAKECMDPREFIX)rm -fv "$(LIBDIR)/$(LIBNAME)" "$(LIBDIR)/$(LIBNAME).$(VERSION)"
@@ -92,5 +103,6 @@ uninstall:
        $(MAKECMDPREFIX)rmdir -v -p --ignore-fail-on-non-empty "$(LIBDIR)"
 
 uninstall-headers:
-       $(MAKECMDPREFIX)rm -frv "$(INCLUDEDIR)/nmea"
+       $(MAKECMDPREFIX)rm -frv "$(INCLUDEDIR)/nmealib"
        $(MAKECMDPREFIX)rmdir -v -p --ignore-fail-on-non-empty "$(INCLUDEDIR)"
+
index 34d4f46..da20b93 100644 (file)
@@ -1,5 +1,15 @@
 ######################
 #
+# Settings
+#
+#
+
+LIBNAME = libnmea.so
+LIBNAMESTATIC = libnmea.a
+
+
+######################
+#
 # Highlevel configuration options for all
 #
 #
@@ -31,13 +41,13 @@ ifeq ($(DEBUG),0)
   STRIP ?=  :
   endif
 else
-STRIP ?=       :
+STRIP ?= :
 endif
 
 
 # we expect the version to be like 'v0.5.3-27-g0c2727a' and then strip the 'v',
 # and the '-27-g0c2727a' parts
-VERSION=2.0.0
+VERSION=3.0.0
 
 # protect against no version number
 ifeq ($(strip $(VERSION)),)
@@ -45,29 +55,60 @@ VERSION=0.0.0
 endif
 
 CC ?= gcc
-CFLAGS ?= -Wall -Wextra -Wold-style-definition -Wdeclaration-after-statement -Wmissing-prototypes -Wstrict-prototypes \
-          -Wmissing-declarations -Wsign-compare -Waggregate-return -Wmissing-noreturn -Wmissing-format-attribute \
-          -Wno-multichar -Wno-deprecated-declarations -Wendif-labels -Wwrite-strings -Wbad-function-cast \
-          -Wpointer-arith -Wcast-qual -Wshadow -Wformat -Wsequence-point -Wcast-align -Wnested-externs \
-          -Winline -Wdisabled-optimization -finline-functions-called-once -funit-at-a-time -fearly-inlining \
-          -finline-limit=350 -fPIC -ggdb -Wformat=2 -Winit-self -Wmissing-include-dirs \
-          -Wswitch-default -Wswitch-enum
 
-ifeq ($(DEBUG),0)
-CFLAGS+= -O2
+GCCVERSIONGTEQ6 := $(shell expr `$(CC) -dumpversion | cut -f1 -d.` \>= 6)
+
+COMMONCFLAGS += -Wall -Wextra -Wold-style-definition -Wdeclaration-after-statement -Wmissing-prototypes \
+                -Wstrict-prototypes -Wmissing-declarations -Wsign-compare -Waggregate-return -Wmissing-noreturn \
+                -Wmissing-format-attribute -Wno-multichar -Wno-deprecated-declarations -Wendif-labels -Wwrite-strings \
+                -Wbad-function-cast -Wpointer-arith -Wcast-qual -Wshadow -Wformat -Wsequence-point -Wcast-align \
+                -Wnested-externs -Winline -Wdisabled-optimization -funit-at-a-time -fPIC -ggdb -Wformat=2 -Winit-self \
+                -Wmissing-include-dirs -Wswitch-default -Wswitch-enum -Wconversion -Wdouble-promotion \
+                -Werror=format-security -Wformat-security -Wformat-y2k -Wredundant-decls -Wundef -Wunreachable-code \
+                -Wunused-parameter
+
+GCCCFLAGS    += $(COMMONCFLAGS) -fearly-inlining -finline-functions-called-once -finline-limit=350 -Wtrampolines \
+                -Wsync-nand -Wlogical-op -Wjump-misses-init -Werror
+
+ifeq "$(GCCVERSIONGTEQ6)" "1"
+GCCCFLAGS   += -Wnull-dereference -Wshift-negative-value -Wshift-overflow -Wtautological-compare
+GCCCFLAGS   += -Wmisleading-indentation -Wduplicated-cond
+endif
+
+CLANGCFLAGS := $(COMMONCFLAGS)
+
+ifdef COV
+CFLAGS += -fprofile-arcs -ftest-coverage
+LDFLAG += -lgov
+endif
+
+ifneq ($(CC),clang)
+CFLAGS += $(GCCCFLAGS)
 else
-CFLAGS+= -O0
+CFLAGS += $(CLANGCFLAGS)
 endif
 
+ifeq ($(DEBUG),0)
+CFLAGS += -O2
+else
+CFLAGS += -O0
+endif
 
 LDFLAGS = -shared -Wl,--warn-common -fPIC
 
 # 32/64 cross compilation
 ifdef M32
-CFLAGS +=      -m32
-LDFLAGS +=     -m32
+CFLAGS += -m32
+LDFLAGS += -m32
 endif
 ifdef M64
-CFLAGS +=      -m64
-LDFLAGS +=     -m64
+CFLAGS += -m64
+LDFLAGS += -m64
 endif
+
+
+export COV
+export DEBUG
+export M32
+export M64
+export VERBOSE
index 923ed7c..89c217f 100644 (file)
@@ -1,29 +1,33 @@
 include ../Makefile.inc
 
-.PHONY: all clean
+GITVERSION = $(shell git describe --dirty='-dirty')
+
+.PHONY: all clean version doc doc-pdf
+
+all: clean nmea.doxygen doc doc-pdf
 
 clean:
        $(MAKECMDPREFIX)rm -fr html latex man nmealib.pdf
 
-all: clean nmea.doxygen
+version:
 ifeq ($(VERBOSE),0)
        @echo "Updating version..."
 endif
        $(MAKECMDPREFIX)sed -r "s/^([[:space:]]*PROJECT_NUMBER[[:space:]]*=).*/\1 $(GITVERSION)/" nmea.doxygen > nmea.doxygen.temp
+
+doc: version
 ifeq ($(VERBOSE),0)
        @echo "Generating HTML and man pages..."
 endif
        $(MAKECMDPREFIX)doxygen nmea.doxygen.temp
        $(MAKECMDPREFIX)rm nmea.doxygen.temp
-#ifeq ($(VERBOSE),0)
-#      @echo "Generating PDF..."
-#      @$(MAKE) -C latex -s > /dev/null 2>&1
-#else
-#      $(MAKE) -C latex
-#endif
-#      $(MAKECMDPREFIX)mv latex/refman.pdf nmealib.pdf
-#      $(MAKECMDPREFIX)rm -fr latex
+
+doc-pdf: doc
 ifeq ($(VERBOSE),0)
-       @echo "Done"
+       @echo "Generating PDF..."
+       @$(MAKE) -C latex -s > /dev/null 2>&1
+else
+       $(MAKE) -C latex
 endif
-
+       $(MAKECMDPREFIX)mv latex/refman.pdf nmealib.pdf
+       $(MAKECMDPREFIX)rm -fr latex
\ No newline at end of file
index 8eba25f..c9261d3 100644 (file)
@@ -759,7 +759,7 @@ WARN_LOGFILE           =
 # Note: If this tag is empty the current directory is searched.
 
 INPUT                  = ../src \
-                         ../include/nmea
+                         ../include/nmealib
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
diff --git a/lib/pud/nmealib/include/nmea/context.h b/lib/pud/nmealib/include/nmea/context.h
deleted file mode 100644 (file)
index 73ce64f..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * This file is part of nmealib.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __NMEA_CONTEXT_H__
-#define __NMEA_CONTEXT_H__
-
-/** the default size for the temporary buffers */
-#define NMEA_DEF_PARSEBUFF  1024
-
-/** the minimum size for the temporary buffers */
-#define NMEA_MIN_PARSEBUFF  256
-
-#ifdef  __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-/**
- * Function type definition for tracing
- *
- * @param str the string to trace
- * @param str_size the length of the string
- */
-typedef void (*nmeaTraceFunc)(const char *str, int str_size);
-
-/**
- * Function type definition for error logging
- *
- * @param str the string to log
- * @param str_size the length of the string
- */
-typedef void (*nmeaErrorFunc)(const char *str, int str_size);
-
-void nmea_context_set_trace_func(nmeaTraceFunc func);
-void nmea_context_set_error_func(nmeaErrorFunc func);
-void nmea_context_set_buffer_size(int buff_size);
-int nmea_context_get_buffer_size(void);
-
-void nmea_trace(const char *str, ...) __attribute__ ((format(printf, 1, 2)));
-void nmea_trace_buff(const char *buff, int buff_size);
-void nmea_error(const char *str, ...) __attribute__ ((format(printf, 1, 2)));
-
-#ifdef  __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __NMEA_CONTEXT_H__ */
diff --git a/lib/pud/nmealib/include/nmea/conversions.h b/lib/pud/nmealib/include/nmea/conversions.h
deleted file mode 100644 (file)
index 55cc4ad..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * This file is part of nmealib.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __NMEA_CONVERSIONS_H__
-#define __NMEA_CONVERSIONS_H__
-
-#include <nmea/sentence.h>
-#include <nmea/info.h>
-
-#ifdef  __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-int nmea_gsv_npack(int sat_count);
-
-void nmea_GPGGA2info(const nmeaGPGGA *pack, nmeaINFO *info);
-void nmea_info2GPGGA(const nmeaINFO *info, nmeaGPGGA *pack);
-
-void nmea_GPGSA2info(const nmeaGPGSA *pack, nmeaINFO *info);
-void nmea_info2GPGSA(const nmeaINFO *info, nmeaGPGSA *pack);
-
-void nmea_GPGSV2info(const nmeaGPGSV *pack, nmeaINFO *info);
-void nmea_info2GPGSV(const nmeaINFO *info, nmeaGPGSV *pack, int pack_idx);
-
-void nmea_GPRMC2info(const nmeaGPRMC *pack, nmeaINFO *info);
-void nmea_info2GPRMC(const nmeaINFO *info, nmeaGPRMC *pack);
-
-void nmea_GPVTG2info(const nmeaGPVTG *pack, nmeaINFO *info);
-void nmea_info2GPVTG(const nmeaINFO *info, nmeaGPVTG *pack);
-
-#ifdef  __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __NMEA_CONVERSIONS_H__ */
diff --git a/lib/pud/nmealib/include/nmea/generate.h b/lib/pud/nmealib/include/nmea/generate.h
deleted file mode 100644 (file)
index 4c9af70..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * This file is part of nmealib.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __NMEA_GENERATE_H__
-#define __NMEA_GENERATE_H__
-
-#include <nmea/sentence.h>
-
-#ifdef  __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-int nmea_gen_GPGGA(char *s, const int len, const nmeaGPGGA *pack);
-int nmea_gen_GPGSA(char *s, const int len, const nmeaGPGSA *pack);
-int nmea_gen_GPGSV(char *s, const int len, const nmeaGPGSV *pack);
-int nmea_gen_GPRMC(char *s, const int len, const nmeaGPRMC *pack);
-int nmea_gen_GPVTG(char *s, const int len, const nmeaGPVTG *pack);
-
-int nmea_generate(char *s, const int len, const nmeaINFO *info, const int generate_mask);
-
-#ifdef  __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __NMEA_GENERATE_H__ */
diff --git a/lib/pud/nmealib/include/nmea/generator.h b/lib/pud/nmealib/include/nmea/generator.h
deleted file mode 100644 (file)
index b214dfc..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * This file is part of nmealib.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __NMEA_GENERATOR_H__
-#define __NMEA_GENERATOR_H__
-
-#include <nmea/info.h>
-
-#ifdef  __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-/* forward declaration */
-struct _nmeaGENERATOR;
-
-/**
- * Generator type enum
- */
-enum nmeaGENTYPE {
-       NMEA_GEN_NOISE = 0,
-       NMEA_GEN_STATIC,
-       NMEA_GEN_ROTATE,
-       NMEA_GEN_SAT_STATIC,
-       NMEA_GEN_SAT_ROTATE,
-       NMEA_GEN_POS_RANDMOVE,
-       NMEA_GEN_LAST
-};
-
-struct _nmeaGENERATOR * nmea_create_generator(const int type, nmeaINFO *info);
-int nmea_generate_from(char *buff, int buff_sz, nmeaINFO *info, struct _nmeaGENERATOR *gen, int generate_mask);
-
-/**
- * Generator initialiser function definition.
- *
- * @param gen a pointer to the generator
- * @param info a pointer to an nmeaINFO structure to use during generation
- * @return 1 (true) on success, 0 (false) otherwise
- */
-typedef int (*nmeaNMEA_GEN_INIT)(struct _nmeaGENERATOR *gen, nmeaINFO *info);
-
-/**
- * Generator loop function definition.
- *
- * @param gen a pointer to the generator
- * @param info a pointer to an nmeaINFO structure to use during generation
- * @return 1 (true) on success, 0 (false) otherwise
- */
-typedef int (*nmeaNMEA_GEN_LOOP)(struct _nmeaGENERATOR *gen, nmeaINFO *info);
-
-/**
- * Generator reset function definition.
- *
- * @param gen a pointer to the generator
- * @param info a pointer to an nmeaINFO structure to use during generation
- * @return 1 (true) on success, 0 (false) otherwise
- */
-typedef int (*nmeaNMEA_GEN_RESET)(struct _nmeaGENERATOR *gen, nmeaINFO *info);
-
-/**
- * Generator destroy function definition.
- *
- * @param gen a pointer to the generator
- * @return 1 (true) on success, 0 (false) otherwise
- */typedef int (*nmeaNMEA_GEN_DESTROY)(struct _nmeaGENERATOR *gen);
-
-/**
- * Generator structure
- */
-typedef struct _nmeaGENERATOR {
-       void *gen_data;                    /**< generator data */
-       nmeaNMEA_GEN_INIT init_call;       /**< initialiser function */
-       nmeaNMEA_GEN_LOOP loop_call;       /**< loop function */
-       nmeaNMEA_GEN_RESET reset_call;     /**< reset function */
-       nmeaNMEA_GEN_DESTROY destroy_call; /**< destroy function */
-       struct _nmeaGENERATOR *next;       /**< the next generator */
-} nmeaGENERATOR;
-
-int nmea_gen_init(nmeaGENERATOR *gen, nmeaINFO *info);
-int nmea_gen_loop(nmeaGENERATOR *gen, nmeaINFO *info);
-int nmea_gen_reset(nmeaGENERATOR *gen, nmeaINFO *info);
-void nmea_gen_destroy(nmeaGENERATOR *gen);
-void nmea_gen_add(nmeaGENERATOR *to, nmeaGENERATOR *gen);
-
-#ifdef  __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __NMEA_GENERATOR_H__ */
diff --git a/lib/pud/nmealib/include/nmea/gmath.h b/lib/pud/nmealib/include/nmea/gmath.h
deleted file mode 100644 (file)
index 0c24725..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * This file is part of nmealib.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __NMEA_GMATH_H__
-#define __NMEA_GMATH_H__
-
-#include <nmea/info.h>
-
-#define NMEA_TUD_YARDS              (1.0936133)                     /**< Yards, meter * NMEA_TUD_YARDS = yard */
-#define NMEA_TUD_KNOTS              (1.852)                         /**< Knots, kilometer / NMEA_TUD_KNOTS = knot */
-#define NMEA_TUD_MILES              (1.609344)                      /**< Miles, kilometer / NMEA_TUD_MILES = mile */
-#define NMEA_TUS_MS                 (3.6)                           /**< Meters per seconds, (k/h) / NMEA_TUS_MS= (m/s) */
-#define NMEA_PI                     (3.141592653589793)             /**< PI value */
-#define NMEA_PI180                  (NMEA_PI / 180)                 /**< PI division by 180 */
-#define NMEA_EARTHRADIUS_KM         (6378)                          /**< Earth's mean radius in km */
-#define NMEA_EARTHRADIUS_M          (NMEA_EARTHRADIUS_KM * 1000)    /**< Earth's mean radius in m */
-#define NMEA_EARTH_SEMIMAJORAXIS_M  (6378137.0)                     /**< Earth's semi-major axis in m according WGS84 */
-#define NMEA_EARTH_SEMIMAJORAXIS_KM (NMEA_EARTHMAJORAXIS_KM / 1000) /**< Earth's semi-major axis in km according WGS 84 */
-#define NMEA_EARTH_FLATTENING       (1 / 298.257223563)             /**< Earth's flattening according WGS 84 */
-#define NMEA_DOP_FACTOR             (5)                             /**< Factor for translating DOP to meters */
-
-#ifdef  __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-/*
- * degree VS radian
- */
-
-double nmea_degree2radian(const double val);
-double nmea_radian2degree(const double val);
-
-/*
- * NDEG (NMEA degree)
- */
-
-double nmea_ndeg2degree(const double val);
-double nmea_degree2ndeg(const double val);
-
-double nmea_ndeg2radian(const double val);
-double nmea_radian2ndeg(const double val);
-
-/*
- * DOP
- */
-
-double nmea_calc_pdop(const double hdop, const double vdop);
-double nmea_dop2meters(const double dop);
-double nmea_meters2dop(const double meters);
-
-/*
- * positions work
- */
-
-void nmea_info2pos(const nmeaINFO *info, nmeaPOS *pos);
-void nmea_pos2info(const nmeaPOS *pos, nmeaINFO *info);
-
-double nmea_distance(const nmeaPOS *from_pos, const nmeaPOS *to_pos);
-
-double nmea_distance_ellipsoid(const nmeaPOS *from_pos, const nmeaPOS *to_pos, double *from_azimuth,
-               double *to_azimuth);
-
-int nmea_move_horz(const nmeaPOS *start_pos, nmeaPOS *end_pos, double azimuth, double distance);
-
-int nmea_move_horz_ellipsoid(const nmeaPOS *start_pos, nmeaPOS *end_pos, double azimuth, double distance,
-               double *end_azimuth);
-
-#ifdef  __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __NMEA_GMATH_H__ */
diff --git a/lib/pud/nmealib/include/nmea/info.h b/lib/pud/nmealib/include/nmea/info.h
deleted file mode 100644 (file)
index 88f1b93..0000000
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * This file is part of nmealib.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __NMEA_INFO_H__
-#define __NMEA_INFO_H__
-
-#include <stdint.h>
-#include <stddef.h>
-#include <stdbool.h>
-
-#ifdef  __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#ifndef INLINE
-#define INLINE inline __attribute__((always_inline))
-#endif
-
-/**
- * @file
- * The table below describes which fields are present in the sentences that are
- * supported by the library.
- <pre>
- field/sentence       GPGGA   GPGSA   GPGSV   GPRMC   GPVTG
- present:               x       x       x       x       x
- smask:                 x       x       x       x       x
- utc (date):                                    x
- utc (time):            x                       x
- sig:                   x                       x1
- fix:                           x               x1
- PDOP:                          x
- HDOP:                  x       x
- VDOP:                          x
- lat:                   x                       x
- lon:                   x                       x
- elv:                   x
- speed:                                         x       x
- track:                                         x       x
- mtrack:                                                x
- magvar:                                        x
- satinfo (inuse count): x       x1
- satinfo (inuse):               x
- satinfo (inview):                      x
-
- x1 = not present in the sentence but the library sets it up.
- </pre>
- */
-
-#define NMEA_SIG_FIRST (NMEA_SIG_BAD)
-#define NMEA_SIG_BAD   (0)
-#define NMEA_SIG_LOW   (1)
-#define NMEA_SIG_MID   (2)
-#define NMEA_SIG_HIGH  (3)
-#define NMEA_SIG_RTKIN (4)
-#define NMEA_SIG_FLRTK (5)
-#define NMEA_SIG_ESTIM (6)
-#define NMEA_SIG_MAN   (7)
-#define NMEA_SIG_SIM   (8)
-#define NMEA_SIG_LAST  (NMEA_SIG_SIM)
-
-static INLINE const char * nmea_INFO_sig_to_string(int sig) {
-  switch (sig) {
-    case NMEA_SIG_BAD:
-      return "INVALID";
-    case NMEA_SIG_LOW:
-      return "FIX";
-    case NMEA_SIG_MID:
-      return "DIFFERENTIAL";
-    case NMEA_SIG_HIGH:
-      return "SENSITIVE";
-    case NMEA_SIG_RTKIN:
-      return "REAL TIME KINEMATIC";
-    case NMEA_SIG_FLRTK:
-      return "FLOAT RTK";
-    case NMEA_SIG_ESTIM:
-      return "ESTIMATED (DEAD RECKONING)";
-    case NMEA_SIG_MAN:
-      return "MANUAL INPUT MODE";
-    case NMEA_SIG_SIM:
-      return "SIMULATION MODE";
-    default:
-      return NULL;
-  }
-}
-
-#define NMEA_FIX_FIRST (NMEA_FIX_BAD)
-#define NMEA_FIX_BAD   (1)
-#define NMEA_FIX_2D    (2)
-#define NMEA_FIX_3D    (3)
-#define NMEA_FIX_LAST  (NMEA_FIX_3D)
-
-static INLINE const char * nmea_INFO_fix_to_string(int fix) {
-  if (!fix) {
-    return NULL;
-  }
-
-  switch (fix) {
-    case NMEA_FIX_BAD:
-      return "BAD";
-    case NMEA_FIX_2D:
-      return "2D";
-    case NMEA_FIX_3D:
-      return "3D";
-    default:
-      return NULL;
-  }
-}
-
-#define NMEA_MAXSAT    (64)
-#define NMEA_SATINPACK (4)
-#define NMEA_NSATPACKS (NMEA_MAXSAT / NMEA_SATINPACK)
-
-#define NMEA_DEF_LAT   (0.0)
-#define NMEA_DEF_LON   (0.0)
-
-/**
- * Date and time data
- * @see nmea_time_now
- */
-typedef struct _nmeaTIME {
-       int year;                                               /**< Years since 1900 */
-       int mon;                                                /**< Months since January - [0,11] */
-       int day;                                                /**< Day of the month - [1,31] */
-       int hour;                                               /**< Hours since midnight - [0,23] */
-       int min;                                                /**< Minutes after the hour - [0,59] */
-       int sec;                                                /**< Seconds after the minute - [0,59] */
-       int hsec;                                               /**< Hundredth part of second - [0,99] */
-} nmeaTIME;
-
-/**
- * Position data in fractional degrees or radians
- */
-typedef struct _nmeaPOS {
-       double lat;                                             /**< Latitude */
-       double lon;                                             /**< Longitude */
-} nmeaPOS;
-
-/**
- * Information about satellite
- * @see nmeaSATINFO
- * @see nmeaGPGSV
- */
-typedef struct _nmeaSATELLITE {
-       int id;                                                 /**< Satellite PRN number */
-       int elv;                                                /**< Elevation in degrees, 90 maximum */
-       int azimuth;                                    /**< Azimuth, degrees from true north, 000 to 359 */
-       int sig;                                                /**< Signal, 00-99 dB */
-} nmeaSATELLITE;
-
-/**
- * Information about all satellites in view
- * @see nmeaINFO
- * @see nmeaGPGSV
- */
-typedef struct _nmeaSATINFO {
-       int inuse;                                              /**< Number of satellites in use (not those in view) */
-       int in_use[NMEA_MAXSAT];                /**< IDs of satellites in use (not those in view) */
-       int inview;                                             /**< Total number of satellites in view */
-       nmeaSATELLITE sat[NMEA_MAXSAT]; /**< Satellites information (in view) */
-} nmeaSATINFO;
-
-/**
- * Summary GPS information from all parsed packets,
- * used also for generating NMEA stream
- * @see nmea_parse
- * @see nmea_GPGGA2info,  nmea_...2info
- */
-typedef struct _nmeaINFO {
-       uint32_t present;                               /**< Mask specifying which fields are present */
-
-       int smask;                                              /**< Mask specifying from which sentences data has been obtained */
-
-       nmeaTIME utc;                                   /**< UTC of position */
-
-       int sig;                                                /**< GPS quality indicator: 0 = Invalid
-                                                                   1 = Fix;
-                                                                                                           2 = Differential
-                                                                                                           3 = Sensitive
-                                                                                                           4 = Real Time Kinematic
-                                                                                                           5 = Float RTK,
-                                                                                                           6 = estimated (dead reckoning) (v2.3)
-                                                                                                           7 = Manual input mode
-                                                                                                           8 = Simulation mode) */
-
-       int fix;                                                /**< Operating mode, used for navigation: 1 = Fix not available
-                                                                                 2 = 2D
-                                                                                 3 = 3D) */
-
-       double PDOP;                                    /**< Position Dilution Of Precision */
-       double HDOP;                                    /**< Horizontal Dilution Of Precision */
-       double VDOP;                                    /**< Vertical Dilution Of Precision */
-
-       double lat;                                             /**< Latitude in NDEG:  +/-[degree][min].[sec/60] */
-       double lon;                                             /**< Longitude in NDEG: +/-[degree][min].[sec/60] */
-       double elv;                                             /**< Antenna altitude above/below mean sea level (geoid) in meters */
-       double speed;                                   /**< Speed over the ground in kph */
-       double track;                                   /**< Track angle in degrees True */
-       double mtrack;                                  /**< Magnetic Track angle in degrees True */
-       double magvar;                                  /**< Magnetic variation degrees */
-
-       nmeaSATINFO satinfo;                    /**< Satellites information */
-} nmeaINFO;
-
-/**
- * Enumeration for the fields names of a nmeaINFO structure.
- * The values are used in the 'present' mask.
- */
-typedef enum _nmeaINFO_FIELD {
-  SMASK         = (1u << 0),  /* 0x00001 */
-  UTCDATE       = (1u << 1),  /* 0x00002 */
-  UTCTIME       = (1u << 2),  /* 0x00004 */
-  SIG           = (1u << 3),  /* 0x00008 */
-  FIX           = (1u << 4),  /* 0x00010 */
-  PDOP          = (1u << 5),  /* 0x00020 */
-  HDOP          = (1u << 6),  /* 0x00040 */
-  VDOP          = (1u << 7),  /* 0x00080 */
-  LAT           = (1u << 8),  /* 0x00100 */
-  LON           = (1u << 9),  /* 0x00200 */
-  ELV           = (1u << 10), /* 0x00400 */
-  SPEED         = (1u << 11), /* 0x00800 */
-  TRACK         = (1u << 12), /* 0x01000 */
-  MTRACK        = (1u << 13), /* 0x02000 */
-  MAGVAR        = (1u << 14), /* 0x04000 */
-  SATINUSECOUNT = (1u << 15), /* 0x08000 */
-  SATINUSE      = (1u << 16), /* 0x10000 */
-  SATINVIEW     = (1u << 17), /* 0x20000 */
-  _nmeaINFO_FIELD_LAST = SATINVIEW
-} nmeaINFO_FIELD;
-
-#define NMEA_INFO_PRESENT_MASK ((_nmeaINFO_FIELD_LAST << 1) - 1)
-
-static INLINE const char * nmea_INFO_field_to_string(nmeaINFO_FIELD field) {
-  if (!field) {
-    return NULL;
-  }
-
-  switch (field) {
-    case SMASK:
-      return "SMASK";
-    case UTCDATE:
-      return "UTCDATE";
-    case UTCTIME:
-      return "UTCTIME";
-    case SIG:
-      return "SIG";
-    case FIX:
-      return "FIX";
-    case PDOP:
-      return "PDOP";
-    case HDOP:
-      return "HDOP";
-    case VDOP:
-      return "VDOP";
-    case LAT:
-      return "LAT";
-    case LON:
-      return "LON";
-    case ELV:
-      return "ELV";
-    case SPEED:
-      return "SPEED";
-    case TRACK:
-      return "TRACK";
-    case MTRACK:
-      return "MTRACK";
-    case MAGVAR:
-      return "MAGVAR";
-    case SATINUSECOUNT:
-      return "SATINUSECOUNT";
-    case SATINUSE:
-      return "SATINUSE";
-    case SATINVIEW:
-      return "SATINVIEW";
-    default:
-      return NULL;
-  }
-}
-
-void nmea_time_now(nmeaTIME *utc, uint32_t * present);
-void nmea_zero_INFO(nmeaINFO *info);
-
-bool nmea_INFO_is_present_smask(int smask, nmeaINFO_FIELD fieldName);
-
-/**
- * Determine if a nmeaINFO structure has a certain field
- *
- * @param present the presence field
- * @param fieldName use a name from nmeaINFO_FIELD
- * @return a boolean, true when the structure has the requested field
- */
-static INLINE bool nmea_INFO_is_present(uint32_t present, nmeaINFO_FIELD fieldName) {
-  return ((present & fieldName) != 0);
-}
-
-void nmea_INFO_set_present(uint32_t * present, nmeaINFO_FIELD fieldName);
-void nmea_INFO_unset_present(uint32_t * present, nmeaINFO_FIELD fieldName);
-
-void nmea_INFO_sanitise(nmeaINFO *nmeaInfo);
-
-void nmea_INFO_unit_conversion(nmeaINFO * nmeaInfo);
-
-#ifdef  __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __NMEA_INFO_H__ */
diff --git a/lib/pud/nmealib/include/nmea/parse.h b/lib/pud/nmealib/include/nmea/parse.h
deleted file mode 100644 (file)
index c2fb093..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * This file is part of nmealib.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __NMEA_PARSE_H__
-#define __NMEA_PARSE_H__
-
-#include <nmea/sentence.h>
-
-#include <stdbool.h>
-#include <stddef.h>
-
-#ifdef  __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-const char * isInvalidNMEACharacter(const char * c);
-const char * nmea_parse_sentence_has_invalid_chars(const char * s, const size_t len);
-
-enum nmeaPACKTYPE nmea_parse_get_sentence_type(const char *s, const int len);
-
-int nmea_parse_GPGGA(const char *s, const int len, bool has_checksum, nmeaGPGGA *pack);
-int nmea_parse_GPGSA(const char *s, const int len, bool has_checksum, nmeaGPGSA *pack);
-int nmea_parse_GPGSV(const char *s, const int len, bool has_checksum, nmeaGPGSV *pack);
-int nmea_parse_GPRMC(const char *s, const int len, bool has_checksum, nmeaGPRMC *pack);
-int nmea_parse_GPVTG(const char *s, const int len, bool has_checksum, nmeaGPVTG *pack);
-
-#ifdef  __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __NMEA_PARSE_H__ */
diff --git a/lib/pud/nmealib/include/nmea/parser.h b/lib/pud/nmealib/include/nmea/parser.h
deleted file mode 100644 (file)
index 54be995..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * This file is part of nmealib.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __NMEA_PARSER_H__
-#define __NMEA_PARSER_H__
-
-#include <nmea/info.h>
-#include <nmea/sentence.h>
-
-#ifdef  __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#ifdef NMEA_MAX_SENTENCE_LENGTH
-  /* override the default maximum sentence length */
-  #define SENTENCE_SIZE (NMEA_MAX_SENTENCE_LENGTH)
-#else
-  /* we need to be able to parse much longer sentences than specified in the (original) specification */
-  #define SENTENCE_SIZE (4096 * 1)
-#endif
-
-typedef enum _sentence_parser_state {
-  SKIP_UNTIL_START,
-  READ_SENTENCE,
-  READ_CHECKSUM,
-  READ_EOL
-} sentence_parser_state;
-
-/**
- * NMEA frame parser structure
- */
-typedef struct _sentencePARSER {
-    int sentence_checksum;
-    int calculated_checksum;
-
-    char sentence_checksum_chars[2];
-    char sentence_checksum_chars_count;
-
-    char sentence_eol_chars_count;
-
-    bool has_checksum;
-
-    sentence_parser_state state;
-} sentencePARSER;
-
-/**
- * parsed NMEA data and frame parser state
- */
-typedef struct _nmeaPARSER {
-    struct {
-        unsigned int length;
-        char buffer[SENTENCE_SIZE];
-    } buffer;
-
-    union {
-        nmeaGPGGA gpgga;
-        nmeaGPGSA gpgsa;
-        nmeaGPGSV gpgsv;
-        nmeaGPRMC gprmc;
-        nmeaGPVTG gpvtg;
-    } sentence;
-
-    sentencePARSER sentence_parser;
-} nmeaPARSER;
-
-int nmea_parser_init(nmeaPARSER *parser);
-int nmea_parse(nmeaPARSER * parser, const char * s, int len, nmeaINFO * info);
-
-#ifdef  __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __NMEA_PARSER_H__ */
diff --git a/lib/pud/nmealib/include/nmea/sentence.h b/lib/pud/nmealib/include/nmea/sentence.h
deleted file mode 100644 (file)
index 30d1890..0000000
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * This file is part of nmealib.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * Extended descriptions of sentences are taken from
- *   http://www.gpsinformation.org/dale/nmea.htm
- */
-
-#ifndef __NMEA_SENTENCE_H__
-#define __NMEA_SENTENCE_H__
-
-#include <nmea/info.h>
-
-#include <stdint.h>
-#include <stddef.h>
-
-#ifdef  __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-/**
- * NMEA packets type which parsed and generated by library
- */
-enum nmeaPACKTYPE {
-       GPNON = 0,                      /**< Unknown packet type. */
-       GPGGA = (1u << 0),      /**< GGA - Essential fix data which provide 3D location and accuracy data. */
-       GPGSA = (1u << 1),      /**< GSA - GPS receiver operating mode, SVs used for navigation, and DOP values. */
-       GPGSV = (1u << 2),      /**< GSV - Number of SVs in view, PRN numbers, elevation, azimuth & SNR values. */
-       GPRMC = (1u << 3),      /**< RMC - Recommended Minimum Specific GPS/TRANSIT Data. */
-       GPVTG = (1u << 4),      /**< VTG - Actual track made good and speed over ground. */
-       _nmeaPACKTYPE_LAST = GPVTG
-};
-
-static INLINE const char * nmea_INFO_smask_packtype_to_string(enum nmeaPACKTYPE packType) {
-  switch(packType) {
-      case GPGGA:
-        return "GPGGA";
-      case GPGSA:
-        return "GPGSA";
-      case GPGSV:
-        return "GPGSV";
-      case GPRMC:
-        return "GPRMC";
-      case GPVTG:
-        return "GPVTG";
-      case GPNON:
-      default:
-        return NULL;
-  }
-}
-
-/**
- * GGA packet information structure (Global Positioning System Fix Data)
- *
- * <pre>
- * GGA - essential fix data which provide 3D location and accuracy data.
- *
- * $GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
- *
- * Where:
- *      GGA          Global Positioning System Fix Data
- *      123519       Fix taken at 12:35:19 UTC
- *      4807.038,N   Latitude 48 deg 07.038' N
- *      01131.000,E  Longitude 11 deg 31.000' E
- *      1            Signal quality: 0 = invalid
- *                                   1 = GPS fix (SPS)
- *                                   2 = DGPS fix
- *                                   3 = PPS fix
- *                                              4 = Real Time Kinematic
- *                                              5 = Float RTK
- *                                   6 = estimated (dead reckoning) (2.3 feature)
- *                                              7 = Manual input mode
- *                                              8 = Simulation mode
- *      08           Number of satellites being tracked
- *      0.9          Horizontal dilution of position
- *      545.4,M      Altitude, Meters, above mean sea level
- *      46.9,M       Height of geoid (mean sea level) above WGS84
- *                       ellipsoid
- *      (empty field) time in seconds since last DGPS update
- *      (empty field) DGPS station ID number
- *      *47          the checksum data, always begins with *
- *
- * If the height of geoid is missing then the altitude should be suspect. Some
- * non-standard implementations report altitude with respect to the ellipsoid
- * rather than geoid altitude. Some units do not report negative altitudes at
- * all. This is the only sentence that reports altitude.
- * </pre>
- */
-typedef struct _nmeaGPGGA {
-       uint32_t present;                       /**< Mask specifying which fields are present, same as in nmeaINFO */
-       nmeaTIME utc;                           /**< UTC of position (just time) */
-       double lat;                                     /**< Latitude in NDEG - [degree][min].[sec/60] */
-       char ns;                                        /**< [N]orth or [S]outh */
-       double lon;                                     /**< Longitude in NDEG - [degree][min].[sec/60] */
-       char ew;                                        /**< [E]ast or [W]est */
-       int sig;                                        /**< GPS quality indicator (0 = Invalid; 1 = Fix; 2 = Differential, 3 = Sensitive) */
-       int satinuse;                           /**< Number of satellites in use (not those in view) */
-       double HDOP;                            /**< Horizontal dilution of precision */
-       double elv;                                     /**< Antenna altitude above/below mean sea level (geoid) */
-       char elv_units;                         /**< [M]eters (Antenna height unit) */
-       double diff;                            /**< Geoidal separation (Diff. between WGS-84 earth ellipsoid and mean sea level. '-' = geoid is below WGS-84 ellipsoid) */
-       char diff_units;                        /**< [M]eters (Units of geoidal separation) */
-       double dgps_age;                        /**< Time in seconds since last DGPS update */
-       int dgps_sid;                           /**< DGPS station ID number */
-} nmeaGPGGA;
-
-/**
- * GSA packet information structure (Satellite status)
- *
- * <pre>
- * GSA - GPS DOP and active satellites.
- *
- * This sentence provides details on the nature of the fix. It includes the
- * numbers of the satellites being used in the current solution and the DOP.
- *
- * DOP (dilution of precision) is an indication of the effect of satellite
- * geometry on the accuracy of the fix. It is a unitless number where smaller
- * is better. For 3D fixes using 4 satellites a 1.0 would be considered to be
- * a perfect number, however for overdetermined solutions it is possible to see
- * numbers below 1.0.
- *
- * There are differences in the way the PRN's are presented which can effect the
- * ability of some programs to display this data. For example, in the example
- * shown below there are 5 satellites in the solution and the null fields are
- * scattered indicating that the almanac would show satellites in the null
- * positions that are not being used as part of this solution. Other receivers
- * might output all of the satellites used at the beginning of the sentence with
- * the null field all stacked up at the end. This difference accounts for some
- * satellite display programs not always being able to display the satellites
- * being tracked. Some units may show all satellites that have ephemeris data
- * without regard to their use as part of the solution but this is non-standard.
- *
- * $GPGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39
- *
- * Where:
- *      GSA      Satellite status
- *      A        Auto selection of 2D or 3D fix (M = manual)
- *      3        3D fix - values include: 1 = no fix
- *                                        2 = 2D fix
- *                                        3 = 3D fix
- *      04,05... PRNs of satellites used for fix (space for 12)
- *      2.5      PDOP (dilution of precision)
- *      1.3      Horizontal dilution of precision (HDOP)
- *      2.1      Vertical dilution of precision (VDOP)
- *      *39      the checksum data, always begins with *
- * </pre>
- */
-typedef struct _nmeaGPGSA {
-       uint32_t present;                       /**< Mask specifying which fields are present, same as in nmeaINFO */
-       char fix_mode;                          /**< Mode (M = Manual, forced to operate in 2D or 3D; A = Automatic, 3D/2D) */
-       int fix_type;                           /**< Type, used for navigation (1 = Fix not available; 2 = 2D; 3 = 3D) */
-       int sat_prn[NMEA_MAXSAT];       /**< PRNs of satellites used in position fix (0 for unused fields) */
-       double PDOP;                            /**< Dilution of precision */
-       double HDOP;                            /**< Horizontal dilution of precision */
-       double VDOP;                            /**< Vertical dilution of precision */
-} nmeaGPGSA;
-
-/**
- * GSV packet information structure (Satellites in view)
- *
- * <pre>
- * GSV - Satellites in View
- *
- * Shows data about the satellites that the unit might be able to find based on
- * its viewing mask and almanac data. It also shows current ability to track
- * this data. Note that one GSV sentence only can provide data for up to 4
- * satellites and thus there may need to be 3 sentences for the full
- * information. It is reasonable for the GSV sentence to contain more satellites
- * than GGA might indicate since GSV may include satellites that are not used as
- * part of the solution. It is not a requirement that the GSV sentences all
- * appear in sequence. To avoid overloading the data bandwidth some receivers
- * may place the various sentences in totally different samples since each
- * sentence identifies which one it is.
- *
- * The field called SNR (Signal to Noise Ratio) in the NMEA standard is often
- * referred to as signal strength. SNR is an indirect but more useful value than
- * raw signal strength. It can range from 0 to 99 and has units of dB according
- * to the NMEA standard, but the various manufacturers send different ranges of
- * numbers with different starting numbers so the values themselves cannot
- * necessarily be used to evaluate different units. The range of working values
- * in a given gps will usually show a difference of about 25 to 35 between the
- * lowest and highest values, however 0 is a special case and may be shown on
- * satellites that are in view but not being tracked.
- *
- * $GPGSV,2,1,08,01,40,083,46,02,17,308,41,12,07,344,39,14,22,228,45*75
- *
- * Where:
- *      GSV          Satellites in view
- *      2            Number of sentences for full data
- *      1            sentence 1 of 2
- *      08           Number of satellites in view
- *
- *      01           Satellite PRN number
- *      40           Elevation, degrees
- *      083          Azimuth, degrees
- *      46           SNR - higher is better
- *           for up to 4 satellites per sentence
- *
- *      *75          the checksum data, always begins with *
- * </pre>
- */
-typedef struct _nmeaGPGSV {
-       uint32_t present;                       /**< Mask specifying which fields are present, same as in nmeaINFO */
-       int pack_count;                         /**< Total number of messages of this type in this cycle */
-       int pack_index;                         /**< Message number */
-       int sat_count;                          /**< Total number of satellites in view */
-       nmeaSATELLITE sat_data[NMEA_SATINPACK];
-} nmeaGPGSV;
-
-/**
- * RMC -packet information structure (Recommended Minimum sentence C)
- *
- * <pre>
- * RMC - Recommended Minimum sentence C
- *
- * NMEA has its own version of essential gps pvt (position, velocity,
- * time) data. It is called RMC, the Recommended Minimum, which will look
- * similar to:
- *
- * $GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A
- * $GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W,A*6A (v2.3)
- *
- * Where:
- *      RMC          Recommended Minimum sentence C
- *      123519       Fix taken at 12:35:19 UTC
- *      A            Status A=active or V=Void.
- *      4807.038,N   Latitude 48 deg 07.038' N
- *      01131.000,E  Longitude 11 deg 31.000' E
- *      022.4        Speed over the ground in knots
- *      084.4        Track angle in degrees True
- *      230394       Date - 23rd of March 1994
- *      003.1,W      Magnetic Variation
- *      A            Mode A=autonomous, D=differential, E=Estimated,
- *                        N=not valid, S=Simulator (NMEA v2.3)
- *      *6A          The checksum data, always begins with *
- * </pre>
- */
-typedef struct _nmeaGPRMC {
-       uint32_t present;                       /**< Mask specifying which fields are present, same as in nmeaINFO */
-       nmeaTIME utc;                           /**< UTC of position */
-       char status;                            /**< Status (A = active or V = void) */
-       double lat;                                     /**< Latitude in NDEG - [degree][min].[sec/60] */
-       char ns;                                        /**< [N]orth or [S]outh */
-       double lon;                                     /**< Longitude in NDEG - [degree][min].[sec/60] */
-       char ew;                                        /**< [E]ast or [W]est */
-       double speed;                           /**< Speed over the ground in knots */
-       double track;                           /**< Track angle in degrees True */
-       double magvar;                          /**< Magnetic variation degrees (Easterly var. subtracts from true course) */
-       char magvar_ew;                         /**< [E]ast or [W]est */
-       char mode;                                      /**< Mode indicator of fix type (A=autonomous, D=differential, E=Estimated, N=not valid, S=Simulator) */
-} nmeaGPRMC;
-
-/**
- * VTG packet information structure (Track made good and ground speed)
- *
- * <pre>
- * VTG - Velocity made good.
- *
- * The gps receiver may use the LC prefix instead of GP if it is emulating
- * Loran output.
- *
- * $GPVTG,054.7,T,034.4,M,005.5,N,010.2,K*48
- *
- * where:
- *      VTG          Track made good and ground speed
- *      054.7,T      True track made good (degrees)
- *      034.4,M      Magnetic track made good
- *      005.5,N      Ground speed, knots
- *      010.2,K      Ground speed, Kilometers per hour
- *      *48          Checksum
- * </pre>
- */
-typedef struct _nmeaGPVTG {
-       uint32_t present;                       /**< Mask specifying which fields are present, same as in nmeaINFO */
-       double track;                           /**< True track made good (degrees) */
-       char track_t;                           /**< Fixed text 'T' indicates that track made good is relative to true north */
-       double mtrack;                          /**< Magnetic track made good */
-       char mtrack_m;                          /**< Fixed text 'M' */
-       double spn;                                     /**< Ground speed, knots */
-       char spn_n;                                     /**< Fixed text 'N' indicates that speed over ground is in knots */
-       double spk;                                     /**< Ground speed, kilometers per hour */
-       char spk_k;                                     /**< Fixed text 'K' indicates that speed over ground is in kilometers/hour */
-} nmeaGPVTG;
-
-void nmea_zero_GPGGA(nmeaGPGGA *pack);
-void nmea_zero_GPGSA(nmeaGPGSA *pack);
-void nmea_zero_GPGSV(nmeaGPGSV *pack);
-void nmea_zero_GPRMC(nmeaGPRMC *pack);
-void nmea_zero_GPVTG(nmeaGPVTG *pack);
-
-#ifdef  __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __NMEA_SENTENCE_H__ */
diff --git a/lib/pud/nmealib/include/nmea/tok.h b/lib/pud/nmealib/include/nmea/tok.h
deleted file mode 100644 (file)
index 20c66d6..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * This file is part of nmealib.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __NMEA_TOK_H__
-#define __NMEA_TOK_H__
-
-#ifdef  __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-int nmea_calc_crc(const char *s, const int len);
-int nmea_atoi(const char *s, const int len, const int radix);
-double nmea_atof(const char *s, const int len);
-int nmea_printf(char *s, int len, const char *format, ...) __attribute__ ((format(printf, 3, 4)));
-int nmea_scanf(const char *s, int len, const char *format, ...);
-
-#ifdef  __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __NMEA_TOK_H__ */
diff --git a/lib/pud/nmealib/include/nmealib/context.h b/lib/pud/nmealib/include/nmealib/context.h
new file mode 100644 (file)
index 0000000..7d82cb9
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * This file is part of nmealib.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __NMEALIB_CONTEXT_H__
+#define __NMEALIB_CONTEXT_H__
+
+#include <stddef.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * Function type definition for tracing and error logging functions
+ *
+ * @param s The string to trace or log an error with
+ * @param sz The length of the string
+ */
+typedef void (*NmeaContextPrintFunction)(const char *s, size_t sz);
+
+/**
+ * Set the trace function
+ *
+ * Note that only 1 trace function is accepted, it will overwrite
+ * any trace function that was previously set, so use the return value
+ * for function chaining.
+ *
+ * Setting the function to NULL disables tracing.
+ *
+ * The function can be set at any time.
+ *
+ * @param function The trace function
+ * @return The overwritten trace function
+ */
+NmeaContextPrintFunction nmeaContextSetTraceFunction(NmeaContextPrintFunction function);
+
+/**
+ * Set the error logging function
+ *
+ * Note that only 1 error logging function is accepted, it will overwrite
+ * any error logging function that was previously set, so use the return value
+ * for function chaining.
+ *
+ * Setting the function to NULL disables error logging.
+ *
+ * The function can be set at any time.
+ *
+ * @param function The error logging function
+ * @return The overwritten error logging function
+ */
+NmeaContextPrintFunction nmeaContextSetErrorFunction(NmeaContextPrintFunction function);
+
+/**
+ * Trace a buffer (a sized string)
+ *
+ * @param s The buffer (sized string)
+ * @param sz The size of the buffer (length of the size string)
+ */
+void nmeaContextTraceBuffer(const char *s, size_t sz);
+
+/**
+ * Trace a formatted string
+ *
+ * @param s The formatted string to trace
+ */
+void nmeaContextTrace(const char *s, ...) __attribute__ ((format(printf, 1, 2)));
+
+/**
+ * Log a formatted string as an error
+ *
+ * @param s The formatted string to log as an error
+ */
+void nmeaContextError(const char *s, ...) __attribute__ ((format(printf, 1, 2)));
+
+#ifdef  __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __NMEALIB_CONTEXT_H__ */
diff --git a/lib/pud/nmealib/include/nmealib/generator.h b/lib/pud/nmealib/include/nmealib/generator.h
new file mode 100644 (file)
index 0000000..6334b17
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * This file is part of nmealib.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __NMEALIB_GENERATOR_H__
+#define __NMEALIB_GENERATOR_H__
+
+#include <nmealib/info.h>
+#include <nmealib/sentence.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* Forward declaration */
+typedef struct _NmeaGenerator NmeaGenerator;
+
+/**
+ * Generator Type
+ */
+typedef enum _NmeaGeneratorType {
+  NMEALIB_GENERATOR_NOISE        = 0u,
+  NMEALIB_GENERATOR_FIRST        = NMEALIB_GENERATOR_NOISE,
+  NMEALIB_GENERATOR_STATIC       = 1u,
+  NMEALIB_GENERATOR_ROTATE       = 2u,
+  NMEALIB_GENERATOR_SAT_STATIC   = 3u,
+  NMEALIB_GENERATOR_SAT_ROTATE   = 4u,
+  NMEALIB_GENERATOR_POS_RANDMOVE = 5u,
+  NMEALIB_GENERATOR_LAST         = NMEALIB_GENERATOR_POS_RANDMOVE
+} NmeaGeneratorType;
+
+/**
+ * Generator initialiser function definition
+ *
+ * @param gen The generator
+ * @param info The info structure to use during generation
+ * @return True on success
+ */
+typedef bool (*NmeaGeneratorInit)(NmeaGenerator *gen, NmeaInfo *info);
+
+/**
+ * Generator invoke function definition
+ *
+ * @param gen The generator
+ * @param info The info structure to use during generation
+ * @return True on success
+ */
+typedef bool (*NmeaGeneratorInvoke)(NmeaGenerator *gen, NmeaInfo *info);
+
+/**
+ * Generator reset function definition
+ *
+ * @param gen The generator
+ * @param info The info structure to use during generation
+ * @return True on success
+ */
+typedef bool (*NmeaGeneratorReset)(NmeaGenerator *gen, NmeaInfo *info);
+
+/**
+ * Generator structure
+ */
+typedef struct _NmeaGenerator {
+    NmeaGeneratorInit     init;   /**< initialiser function */
+    NmeaGeneratorInvoke   invoke; /**< invoke function      */
+    NmeaGeneratorReset    reset;  /**< reset function       */
+    NmeaGenerator        *next;   /**< the next generator   */
+} NmeaGenerator;
+
+/**
+ * Create a generator and initialise it
+ *
+ * Allocates memory for the generator.
+ *
+ * @param type The type of the generator to create
+ * @param info The info structure to use during generation
+ * @return The generator, or NULL on failure
+ */
+NmeaGenerator *nmeaGeneratorCreate(NmeaGeneratorType type, NmeaInfo *info);
+
+/**
+ * Destroy the generator
+ *
+ * Frees the allocated generator memory too.
+ *
+ * @param gen The generator
+ */
+void nmeaGeneratorDestroy(NmeaGenerator *gen);
+
+/**
+ * Initialise the generator
+ *
+ * @param gen The generator
+ * @param info The info structure to use during generation
+ * @return True on success
+ */
+bool nmeaGeneratorInit(NmeaGenerator *gen, NmeaInfo *info);
+
+/**
+ * Invoke the generator
+ *
+ * @param gen The generator
+ * @param info The info structure to use during generation
+ * @return True on success
+ */
+bool nmeaGeneratorInvoke(NmeaGenerator *gen, NmeaInfo *info);
+
+/**
+ * Reset the generator
+ *
+ * @param gen The generator
+ * @param info The info structure to use during generation
+ * @return True on success
+ */
+bool nmeaGeneratorReset(NmeaGenerator *gen, NmeaInfo *info);
+
+/**
+ * Append a generator to another generator
+ *
+ * @param to The generator to add to
+ * @param gen The generator to add
+ */
+void nmeaGeneratorAppend(NmeaGenerator *to, NmeaGenerator *gen);
+
+/**
+ * Invoke the generator and generate sentences from the result
+ *
+ * Allocates memory for the generated sentences.
+ *
+ * @param buf The allocated buffer (do read the comments of NmeaMallocedBuffer)
+ * @param info The info structure to use during generation
+ * @param gen The generator
+ * @param mask The mask (smask) of sentences to generate
+ * @return The total length of the generated sentences
+ */
+size_t nmeaGeneratorGenerateFrom(NmeaMallocedBuffer *buf, NmeaInfo *info, NmeaGenerator *gen, NmeaSentence mask);
+
+#ifdef  __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __NMEALIB_GENERATOR_H__ */
diff --git a/lib/pud/nmealib/include/nmealib/gpgga.h b/lib/pud/nmealib/include/nmealib/gpgga.h
new file mode 100644 (file)
index 0000000..a02ac4a
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * This file is part of nmealib.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * Extended descriptions of sentences are taken from
+ *   http://www.gpsinformation.org/dale/nmea.htm
+ */
+
+#ifndef __NMEALIB_GPGGA_H__
+#define __NMEALIB_GPGGA_H__
+
+#include <nmealib/info.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** The NMEA prefix */
+#define NMEALIB_GPGGA_PREFIX "GPGGA"
+
+/**
+ * GPGGA packet information structure (Global Positioning System Fix Data)
+ *
+ * Essential fix data which provide 3D location and accuracy data.
+ *
+ * <pre>
+ * $GPGGA,time,latitude,ns,longitude,ew,signal,satellites,hdop,elv,elv unit,height,height unit,dgps age,dgps id*checksum
+ * </pre>
+ *
+ * | Field       | Description                                            | present        |
+ * | :---------: | ------------------------------------------------------ | :------------: |
+ * | $GPGGA      | NMEA prefix                                            | -              |
+ * | time        | Fix time (UTC) (5)                                     | UTCTIME        |
+ * | latitude    | Latitude, in NDEG (DDMM.SSS)                           | LAT (1)        |
+ * | ns          | North or South ('N' or 'S')                            | LAT (1)        |
+ * | longitude   | Longitude, in NDEG (DDDMM.SSS)                         | LON (2)        |
+ * | ew          | East or West ('E' or 'W')                              | LON (2)        |
+ * | signal      | Signal quality (see the NMEALIB_SIG_* defines)         | SIG            |
+ * | satellites  | Number of satellites being tracked                     | SATINVIEWCOUNT |
+ * | hdop        | Horizontal dilution of position                        | HDOP           |
+ * | elv         | Elevation above mean sea level, in meters              | ELV (3)        |
+ * | elv unit    | Unit of elevation ('M')                                | ELV (3)        |
+ * | height      | Height of geoid (mean sea level) above WGS84 ellipsoid | - (4)          |
+ * | height unit | Unit of height ('M')                                   | - (4)          |
+ * | dgps age    | Time since last DGPS update, in seconds                | - (4)          |
+ * | dgps id     | DGPS station ID number                                 | - (4)          |
+ * | checksum    | NMEA checksum                                          | -              |
+ *
+ * (1) These fields are both required for a valid latitude<br/>
+ * (2) These fields are both required for a valid longitude<br/>
+ * (3) These fields are both required for a valid elevation<br/>
+ * (4) Not supported yet<br/>
+ * (5) Supported formats: HHMMSS, HHMMSS.t, HHMMSS.hh, HHMMSS.mmm<br/>
+ *
+ * Example:
+ *
+ * <pre>
+ * $GPGGA,123519.43,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
+ * </pre>
+ *
+ * Note that if the height of geoid is missing then the elevation should be
+ * suspect. Some non-standard implementations report elevation with respect to
+ * the ellipsoid rather than geoid elevation. Some units do not report negative
+ * elevations at all. This is the only sentence that reports elevation.
+ */
+typedef struct _NmeaGPGGA {
+  uint32_t     present;
+  NmeaTime     utc;
+  double       latitude;
+  char         latitudeNS;
+  double       longitude;
+  char         longitudeEW;
+  NmeaSignal   sig;
+  unsigned int inViewCount;
+  double       hdop;
+  double       elevation;
+  char         elevationM;
+  double       height;
+  char         heightM;
+  double       dgpsAge;
+  unsigned int dgpsSid;
+} NmeaGPGGA;
+
+/**
+ * Parse a GPGGA sentence
+ *
+ * @param s The sentence
+ * @param sz The length of the sentence
+ * @param pack Where the result should be stored
+ * @return True on success
+ */
+bool nmeaGPGGAParse(const char *s, const size_t sz, NmeaGPGGA *pack);
+
+/**
+ * Update an unsanitised NmeaInfo structure from a GPGGA packet structure
+ *
+ * @param pack The GPGGA packet structure
+ * @param info The unsanitised NmeaInfo structure
+ */
+void nmeaGPGGAToInfo(const NmeaGPGGA *pack, NmeaInfo *info);
+
+/**
+ * Convert a sanitised NmeaInfo structure into a NmeaGPGGA structure
+ *
+ * @param info The sanitised NmeaInfo structure
+ * @param pack The NmeaGPGGA structure
+ */
+void nmeaGPGGAFromInfo(const NmeaInfo *info, NmeaGPGGA *pack);
+
+/**
+ * Generate a GPGGA sentence
+ *
+ * @param s The buffer to generate the sentence in
+ * @param sz The size of the buffer
+ * @param pack The NmeaGPGGA structure
+ * @return The length of the generated sentence; less than zero on failure,
+ * larger than sz when the size of the buffer is too small to generate the
+ * sentence in
+ */
+size_t nmeaGPGGAGenerate(char *s, const size_t sz, const NmeaGPGGA *pack);
+
+#ifdef  __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __NMEALIB_GPGGA_H__ */
diff --git a/lib/pud/nmealib/include/nmealib/gpgsa.h b/lib/pud/nmealib/include/nmealib/gpgsa.h
new file mode 100644 (file)
index 0000000..767505c
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * This file is part of nmealib.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * Extended descriptions of sentences are taken from
+ *   http://www.gpsinformation.org/dale/nmea.htm
+ */
+
+#ifndef __NMEALIB_GPGSA_H__
+#define __NMEALIB_GPGSA_H__
+
+#include <nmealib/info.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** The NMEA prefix */
+#define NMEALIB_GPGSA_PREFIX "GPGSA"
+
+/** The number of satellite PRNs in the sentence */
+#define NMEALIB_GPGSA_SATS_IN_SENTENCE (12)
+
+/**
+ * GPGSA packet information structure (Satellite status)
+ *
+ * GPS DOP and active satellites.
+ *
+ * <pre>
+ * $GPGSA,sig,fix,prn1,prn2,prn3,,,,,,,,,prn12,pdop,hdop,vdop*checksum
+ * </pre>
+ *
+ * | Field       | Description                                      | present                       |
+ * | :---------: | ------------------------------------------------ | :---------------------------: |
+ * | $GPGSA      | NMEA prefix                                      | -                             |
+ * | sig         | Selection of 2D or 3D fix (A = auto, M = manual) | SIG                           |
+ * | fix         | Fix, see NMEALIB_FIX_* defines                   | FIX                           |
+ * | prn1..prn12 | PRNs of satellites used for fix (12 PRNs)        | SATINUSE \| SATINUSECOUNT (1) |
+ * | pdop        | Dilution of position                             | PDOP                          |
+ * | hdop        | Horizontal dilution of position                  | HDOP                          |
+ * | vdop        | Vertical dilution of position                    | VDOP                          |
+ * | checksum    | NMEA checksum                                    | -                             |
+ *
+ * (1) Also sets SATINUSECOUNT when parsing and when converting from NmeaGPGSA
+ *     to NmeaInfo. SATINUSECOUNT is <b>not</b> used when converting from
+ *     NmeaInfo to NmeaGPGSA nor when generating.<br/>
+ *
+ * This sentence provides details on the nature of the fix. It includes the
+ * numbers of the satellites being used in the current solution and the DOP.
+ *
+ * DOP (dilution of precision) is an indication of the effect of satellite
+ * geometry on the accuracy of the fix. It is a unit-less number where smaller
+ * is better. For 3D fixes using 4 satellites a 1.0 would be considered to be
+ * a perfect number, however for over-determined solutions it is possible to see
+ * numbers below 1.0.
+ *
+ * There are differences in the way the PRN's are presented which can effect the
+ * ability of some programs to display this data. For example, in the example
+ * shown below there are 5 satellites in the solution and the null fields are
+ * scattered indicating that the almanac would show satellites in the null
+ * positions that are not being used as part of this solution. Other receivers
+ * might output all of the satellites used at the beginning of the sentence with
+ * the null field all stacked up at the end. This difference accounts for some
+ * satellite display programs not always being able to display the satellites
+ * being tracked. Some units may show all satellites that have ephemeral data
+ * without regard to their use as part of the solution but this is non-standard.
+ *
+ * Example:
+ *
+ * <pre>
+ * $GPGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39
+ * </pre>
+ */
+typedef struct _NmeaGPGSA {
+  uint32_t     present;
+  char         sig;
+  NmeaFix      fix;
+  unsigned int prn[NMEALIB_GPGSA_SATS_IN_SENTENCE];
+  double       pdop;
+  double       hdop;
+  double       vdop;
+} NmeaGPGSA;
+
+/**
+ * Parse a GPGSA sentence
+ *
+ * @param s The sentence
+ * @param sz The length of the sentence
+ * @param pack Where the result should be stored
+ * @return True on success
+ */
+bool nmeaGPGSAParse(const char *s, const size_t sz, NmeaGPGSA *pack);
+
+/**
+ * Update an unsanitised NmeaInfo structure from a GPGSA packet structure
+ *
+ * @param pack The GPGSA packet structure
+ * @param info The unsanitised NmeaInfo structure
+ */
+void nmeaGPGSAToInfo(const NmeaGPGSA *pack, NmeaInfo *info);
+
+/**
+ * Convert a sanitised NmeaInfo structure into a NmeaGPGSA structure
+ *
+ * @param info The sanitised NmeaInfo structure
+ * @param pack The NmeaGPGSA structure
+ */
+void nmeaGPGSAFromInfo(const NmeaInfo *info, NmeaGPGSA *pack);
+
+/**
+ * Generate a GPGSA sentence
+ *
+ * @param s The buffer to generate the sentence in
+ * @param sz The size of the buffer
+ * @param pack The NmeaGPGSA structure
+ * @return The length of the generated sentence; less than zero on failure,
+ * larger than sz when the size of the buffer is too small to generate the
+ * sentence in
+ */
+size_t nmeaGPGSAGenerate(char *s, const size_t sz, const NmeaGPGSA *pack);
+
+#ifdef  __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __NMEALIB_GPGSA_H__ */
diff --git a/lib/pud/nmealib/include/nmealib/gpgsv.h b/lib/pud/nmealib/include/nmealib/gpgsv.h
new file mode 100644 (file)
index 0000000..03ea4b4
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * This file is part of nmealib.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * Extended descriptions of sentences are taken from
+ *   http://www.gpsinformation.org/dale/nmea.htm
+ */
+
+#ifndef __NMEALIB_GPGSV_H__
+#define __NMEALIB_GPGSV_H__
+
+#include <nmealib/info.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** The NMEA prefix */
+#define NMEALIB_GPGSV_PREFIX "GPGSV"
+
+/** The maximum number of satellites per sentence (must be a power of 2) */
+#define NMEALIB_GPGSV_MAX_SATS_PER_SENTENCE (4u)
+
+/** The maximum number of satellites per sentence, expressed as shift */
+#define NMEALIB_GPGSV_MAX_SATS_PER_SENTENCE_SHIFT (2u)
+
+/** The maximum number of satellites per sentence modulo mask */
+#define NMEALIB_GPGSV_MAX_SATS_PER_SENTENCE_MOD_MASK (NMEALIB_GPGSV_MAX_SATS_PER_SENTENCE - 1)
+
+/** The maximum number of GPGSV sentences (depends on the maximum number of satellites tracked) */
+#define NMEALIB_GPGSV_MAX_SENTENCES (NMEALIB_MAX_SATELLITES >> NMEALIB_GPGSV_MAX_SATS_PER_SENTENCE_SHIFT)
+
+/**
+ * GPGSV packet information structure (Satellites in view)
+ *
+ * <pre>
+ * $GPGSV,sentences,sentence,satellites,prn1,elevation1,azimuth1,snr1,prn2,elevation2,azimuth2,snr2,prn3,elevation3,azimuth3,snr3,prn4,elevation4,azimuth4,snr4*checksum
+ * </pre>
+ *
+ * | Field       | Description                                      | present        |
+ * | :---------: | ------------------------------------------------ | :------------: |
+ * | $GPGSV      | NMEA prefix                                      | -              |
+ * | sentences   | The number of sentences for full data            | -              |
+ * | sentence    | The current sentence number                      | -              |
+ * | satellites  | The number of satellites in view                 | SATINVIEWCOUNT |
+ * | prn1        | Satellite PRN number                             | SATINVIEW      |
+ * | elevation1  | Elevation, in degrees                            | SATINVIEW      |
+ * | azimuth1    | Azimuth, in degrees                              | SATINVIEW      |
+ * | snr1        | Signal-Noise-Ratio, in dB                        | SATINVIEW      |
+ * | prn2        | Satellite PRN number                             | SATINVIEW      |
+ * | elevation2  | Elevation, in degrees                            | SATINVIEW      |
+ * | azimuth2    | Azimuth, in degrees                              | SATINVIEW      |
+ * | snr2        | Signal-Noise-Ratio, in dB                        | SATINVIEW      |
+ * | prn3        | Satellite PRN number                             | SATINVIEW      |
+ * | elevation3  | Elevation, in degrees                            | SATINVIEW      |
+ * | azimuth3    | Azimuth, in degrees                              | SATINVIEW      |
+ * | snr3        | Signal-Noise-Ratio, in dB                        | SATINVIEW      |
+ * | prn4        | Satellite PRN number                             | SATINVIEW      |
+ * | elevation4  | Elevation, in degrees                            | SATINVIEW      |
+ * | azimuth4    | Azimuth, in degrees                              | SATINVIEW      |
+ * | snr4        | Signal-Noise-Ratio, in dB                        | SATINVIEW      |
+ * | checksum    | NMEA checksum                                    | -              |
+ *
+ * Shows data about the satellites that the unit might be able to find based on
+ * its viewing mask and almanac data. It also shows current ability to track
+ * this data. Note that one GPGSV sentence only can provide data for up to 4
+ * satellites and thus there may need to be multiple sentences for the full
+ * information. It is reasonable for the GPGSV sentence to contain more satellites
+ * than GPGGA might indicate since GPGSV may include satellites that are not used as
+ * part of the solution. It is not a requirement that the GPGSV sentences all
+ * appear in sequence. To avoid overloading the data bandwidth some receivers
+ * may place the various sentences in totally different samples since each
+ * sentence identifies which one it is.
+ *
+ * The field called SNR (Signal to Noise Ratio) in the NMEA standard is often
+ * referred to as signal strength. SNR is an indirect but more useful value than
+ * raw signal strength. It can range from 0 to 99 and has units of dB according
+ * to the NMEA standard, but the various manufacturers send different ranges of
+ * numbers with different starting numbers so the values themselves cannot
+ * necessarily be used to evaluate different units. The range of working values
+ * in a given gps will usually show a difference of about 25 to 35 between the
+ * lowest and highest values, however 0 is a special case and may be shown on
+ * satellites that are in view but not being tracked.
+ *
+ * Example:
+ *
+ * <pre>
+ * $GPGSV,2,1,08,01,40,083,46,02,17,308,41,12,07,344,39,14,22,228,45*75
+ * </pre>
+ */
+typedef struct _NmeaGPGSV {
+  uint32_t      present;
+  unsigned int  sentenceCount;
+  unsigned int  sentence;
+  unsigned int  inViewCount;
+  NmeaSatellite inView[NMEALIB_GPGSV_MAX_SATS_PER_SENTENCE];
+} NmeaGPGSV;
+
+/**
+ * Determine the number of GPGSV sentences needed for the specified number of
+ * satellites
+ *
+ * @param satellites The number of satellites
+ * @return The number of GPGSV sentences needed (at least 1)
+ */
+size_t nmeaGPGSVsatellitesToSentencesCount(const size_t satellites);
+
+/**
+ * Parse a GPGSV sentence
+ *
+ * @param s The sentence
+ * @param sz The length of the sentence
+ * @param pack Where the result should be stored
+ * @return True on success
+ */
+bool nmeaGPGSVParse(const char *s, const size_t sz, NmeaGPGSV *pack);
+
+/**
+ * Update an unsanitised NmeaInfo structure from a GPGSV packet structure
+ *
+ * @param pack The GPGSV packet structure
+ * @param info The unsanitised NmeaInfo structure
+ */
+void nmeaGPGSVToInfo(const NmeaGPGSV *pack, NmeaInfo *info);
+
+/**
+ * Convert a sanitised NmeaInfo structure into a NmeaGPGSV structure
+ *
+ * @param info The sanitised NmeaInfo structure
+ * @param pack The NmeaGPGSV structure
+ * @param sentence The sentence index of the NmeaGPGSV structure (zero based)
+ */
+void nmeaGPGSVFromInfo(const NmeaInfo *info, NmeaGPGSV *pack, size_t sentence);
+
+/**
+ * Generate a GPGSV sentence
+ *
+ * @param s The buffer to generate the sentence in
+ * @param sz The size of the buffer
+ * @param pack The NmeaGPGSV structure
+ * @return The length of the generated sentence; less than zero on failure,
+ * larger than sz when the size of the buffer is too small to generate the
+ * sentence in
+ */
+size_t nmeaGPGSVGenerate(char *s, const size_t sz, const NmeaGPGSV *pack);
+
+#ifdef  __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __NMEALIB_GPGSV_H__ */
diff --git a/lib/pud/nmealib/include/nmealib/gprmc.h b/lib/pud/nmealib/include/nmealib/gprmc.h
new file mode 100644 (file)
index 0000000..ef4b011
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * This file is part of nmealib.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * Extended descriptions of sentences are taken from
+ *   http://www.gpsinformation.org/dale/nmea.htm
+ */
+
+#ifndef __NMEALIB_GPRMC_H__
+#define __NMEALIB_GPRMC_H__
+
+#include <nmealib/info.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** The NMEA prefix */
+#define NMEALIB_GPRMC_PREFIX "GPRMC"
+
+/**
+ * GPRMC -packet information structure (Recommended Minimum sentence C)
+ *
+ * <pre>
+ * $GPRMC,time,sig,lat,ns,lon,ew,speed,track,date,magvar,magvar ew,mode*checksum
+ * </pre>
+ *
+ * | Field       | Description                                    | present    |
+ * | :---------: | ---------------------------------------------- | :--------: |
+ * | $GPRMC      | NMEA prefix                                    | -          |
+ * | time        | Fix time, in the format HHMMSS.hh (UTC)        | UTCTIME    |
+ * | sig         | Selection of 2D or 3D fix (A = auto, V = void) | SIG        |
+ * | lat         | Latitude, in NDEG (DDMM.SSS)                   | LAT (1)    |
+ * | ns          | North or south ('N' or 'S')                    | LAT (1)    |
+ * | lon         | Longitude, in NDEG (DDDMM.SSS)                 | LON (2)    |
+ * | ew          | East or west ('E' or 'W')                      | LON (2)    |
+ * | speed       | Speed over the ground, in knots                | SPEED      |
+ * | track       | Track angle, in degrees true north             | TRACK      |
+ * | date        | Fix date, in the format DDMMYY (UTC)           | UTCDATE    |
+ * | magvar      | Magnetic variation                             | MAGVAR (3) |
+ * | magvar ew   | Magnetic variation east or west ('E' or 'W')   | MAGVAR (3) |
+ * | mode        | Mode, N=not valid, or [ADPRFEMS]               | SIG (4)    |
+ * | checksum    | NMEA checksum                                  | -          |
+ *
+ * (1) These fields are both required for a valid latitude<br/>
+ * (2) These fields are both required for a valid longitude<br/>
+ * (3) These fields are both required for a valid magnetic variation<br/>
+ * (4) This field is only present in NMEA sentences with version v2.3 (and above).
+ *     If present, then the selection field and this field are both required for a valid signal<br/>
+ *
+ * Example:
+ *
+ * <pre>
+ * $GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A
+ * $GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W,A*6A (v2.3)
+ * </pre>
+ */
+typedef struct _NmeaGPRMC {
+  bool     v23;
+  uint32_t present;
+  NmeaTime utc;
+  char     sigSelection;
+  double   latitude;
+  char     latitudeNS;
+  double   longitude;
+  char     longitudeEW;
+  double   speed;
+  double   track;
+  double   magvar;
+  char     magvarEW;
+  char     sig;
+} NmeaGPRMC;
+
+/**
+ * Parse a GPRMC sentence
+ *
+ * @param s The sentence
+ * @param sz The length of the sentence
+ * @param pack Where the result should be stored
+ * @return True on success
+ */
+bool nmeaGPRMCParse(const char *s, const size_t sz, NmeaGPRMC *pack);
+
+/**
+ * Update an unsanitised NmeaInfo structure from a GPRMC packet structure
+ *
+ * @param pack The GPRMC packet structure
+ * @param info The unsanitised NmeaInfo structure
+ */
+void nmeaGPRMCToInfo(const NmeaGPRMC *pack, NmeaInfo *info);
+
+/**
+ * Convert a sanitised NmeaInfo structure into a NmeaGPRMC structure
+ *
+ * @param info The sanitised NmeaInfo structure
+ * @param pack The NmeaGPRMC structure
+ */
+void nmeaGPRMCFromInfo(const NmeaInfo *info, NmeaGPRMC *pack);
+
+/**
+ * Generate a GPRMC sentence
+ *
+ * @param s The buffer to generate the sentence in
+ * @param sz The size of the buffer
+ * @param pack The NmeaGPRMC structure
+ * @return The length of the generated sentence; less than zero on failure,
+ * larger than sz when the size of the buffer is too small to generate the
+ * sentence in
+ */
+size_t nmeaGPRMCGenerate(char *s, const size_t sz, const NmeaGPRMC *pack);
+
+#ifdef  __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __NMEALIB_GPRMC_H__ */
diff --git a/lib/pud/nmealib/include/nmealib/gpvtg.h b/lib/pud/nmealib/include/nmealib/gpvtg.h
new file mode 100644 (file)
index 0000000..26c9bd8
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * This file is part of nmealib.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * Extended descriptions of sentences are taken from
+ *   http://www.gpsinformation.org/dale/nmea.htm
+ */
+
+#ifndef __NMEALIB_GPVTG_H__
+#define __NMEALIB_GPVTG_H__
+
+#include <nmealib/info.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** The NMEA prefix */
+#define NMEALIB_GPVTG_PREFIX "GPVTG"
+
+/**
+ * GPVTG packet information structure (Track made good and ground speed)
+ *
+ * <pre>
+ * $GPVTG,track,T,mtrack,M,speedN,N,speedK,K*checksum
+ * </pre>
+ *
+ * | Field       | Description                           | present   |
+ * | :---------: | ------------------------------------- | :-------: |
+ * | $GPVTG      | NMEA prefix                           | -         |
+ * | track       | Track, in degress true north          | TRACK (1) |
+ * | T           | Track indicator (True north)          | TRACK (1) |
+ * | mtrack      | Magnetic track made good              | TRACK (2) |
+ * | M           | Magnetic track indicator (Made good)  | TRACK (2) |
+ * | speedN      | Ground speed, in knots                | SPEED (3) |
+ * | N           | Ground speed unit (kNots)             | SPEED (3) |
+ * | speedk      | Ground speed, in kph                  | SPEED (4) |
+ * | K           | Ground speed unit (Kph)               | SPEED (4) |
+ * | checksum    | NMEA checksum                         | -         |
+ *
+ * (1) These fields are both required for a valid track<br/>
+ * (2) These fields are both required for a valid magnetic track<br/>
+ * (3) These fields are both required for a valid speed in knots<br/>
+ * (4) These fields are both required for a valid speed in kph<br/>
+ *
+ * Example:
+ *
+ * <pre>
+ * $GPVTG,054.7,T,034.4,M,005.5,N,010.2,K*48
+ * </pre>
+ */
+typedef struct _NmeaGPVTG {
+  uint32_t present;
+  double   track;
+  char     trackT;
+  double   mtrack;
+  char     mtrackM;
+  double   spn;
+  char     spnN;
+  double   spk;
+  char     spkK;
+} NmeaGPVTG;
+
+/**
+ * Parse a GPVTG sentence
+ *
+ * @param s The sentence
+ * @param sz The length of the sentence
+ * @param pack Where the result should be stored
+ * @return True on success
+ */
+bool nmeaGPVTGParse(const char *s, const size_t sz, NmeaGPVTG *pack);
+
+/**
+ * Update an unsanitised NmeaInfo structure from a GPVTG packet structure
+ *
+ * @param pack The GPVTG packet structure
+ * @param info The unsanitised NmeaInfo structure
+ */
+void nmeaGPVTGToInfo(const NmeaGPVTG *pack, NmeaInfo *info);
+
+/**
+ * Convert a sanitised NmeaInfo structure into a NmeaGPVTG structure
+ *
+ * @param info The sanitised NmeaInfo structure
+ * @param pack The NmeaGPVTG structure
+ */
+void nmeaGPVTGFromInfo(const NmeaInfo *info, NmeaGPVTG *pack);
+
+/**
+ * Generate a GPVTG sentence
+ *
+ * @param s The buffer to generate the sentence in
+ * @param sz The size of the buffer
+ * @param pack The NmeaGPVTG structure
+ * @return The length of the generated sentence; less than zero on failure,
+ * larger than sz when the size of the buffer is too small to generate the
+ * sentence in
+ */
+size_t nmeaGPVTGGenerate(char *s, const size_t sz, const NmeaGPVTG *pack);
+
+#ifdef  __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __NMEALIB_GPVTG_H__ */
diff --git a/lib/pud/nmealib/include/nmealib/info.h b/lib/pud/nmealib/include/nmealib/info.h
new file mode 100644 (file)
index 0000000..d0a12ff
--- /dev/null
@@ -0,0 +1,539 @@
+/*
+ * This file is part of nmealib.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __NMEALIB_INFO_H__
+#define __NMEALIB_INFO_H__
+
+#include <nmealib/util.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/time.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/*
+ * SIG
+ */
+
+/**
+ * Enumeration for the signal names
+ *
+ * The values are used in the 'sig' field.
+ */
+typedef enum _NmeaSignal {
+  NMEALIB_SIG_INVALID      = 0u,
+  NMEALIB_SIG_FIRST        = NMEALIB_SIG_INVALID,
+  NMEALIB_SIG_FIX          = 1u,
+  NMEALIB_SIG_DIFFERENTIAL = 2u,
+  NMEALIB_SIG_SENSITIVE    = 3u,
+  NMEALIB_SIG_RTKIN        = 4u,
+  NMEALIB_SIG_FLOAT_RTK    = 5u,
+  NMEALIB_SIG_ESTIMATED    = 6u,
+  NMEALIB_SIG_MANUAL       = 7u,
+  NMEALIB_SIG_SIMULATION   = 8u,
+  NMEALIB_SIG_LAST         = NMEALIB_SIG_SIMULATION
+} NmeaSignal;
+
+/**
+ * Convert a NMEALIB_SIG_* signal into a string
+ *
+ * @param sig The NMEALIB_SIG_* signal
+ * @return The corresponding string, or NULL when the signal is unknown
+ */
+static INLINE const char *nmeaInfoSignalToString(NmeaSignal sig) {
+  switch (sig) {
+    case NMEALIB_SIG_INVALID:
+      return "INVALID";
+
+    case NMEALIB_SIG_FIX:
+      return "FIX";
+
+    case NMEALIB_SIG_DIFFERENTIAL:
+      return "DIFFERENTIAL";
+
+    case NMEALIB_SIG_SENSITIVE:
+      return "SENSITIVE";
+
+    case NMEALIB_SIG_RTKIN:
+      return "REAL TIME KINEMATIC";
+
+    case NMEALIB_SIG_FLOAT_RTK:
+      return "FLOAT REAL TIME KINEMATIC";
+
+    case NMEALIB_SIG_ESTIMATED:
+      return "ESTIMATED (DEAD RECKONING)";
+
+    case NMEALIB_SIG_MANUAL:
+      return "MANUAL";
+
+    case NMEALIB_SIG_SIMULATION:
+      return "SIMULATION";
+
+    default:
+      return NULL;
+  }
+}
+
+/**
+ * Convert a mode character into the corresponding NMEALIB_SIG_* signal
+ *
+ * @param mode The mode character
+ * @return The corresponding NMEALIB_SIG_* signal, or NMEALIB_SIG_INVALID when the
+ * mode is unknown
+ */
+NmeaSignal nmeaInfoModeToSignal(char mode);
+
+/**
+ * Convert a NMEALIB_SIG_* signal into the corresponding mode character
+ *
+ * @param sig The NMEALIB_SIG_* signal
+ * @return The corresponding mode character, or 'N' when the NMEALIB_SIG_* signal
+ * is unknown
+ */
+char nmeaInfoSignalToMode(NmeaSignal sig);
+
+/*
+ * FIX
+ */
+
+typedef enum _NmeaFix {
+  NMEALIB_FIX_BAD   = 1u,
+  NMEALIB_FIX_FIRST = NMEALIB_FIX_BAD,
+  NMEALIB_FIX_2D    = 2u,
+  NMEALIB_FIX_3D    = 3u,
+  NMEALIB_FIX_LAST  = NMEALIB_FIX_3D
+} NmeaFix;
+
+/**
+ * Convert a NMEALIB_FIX_* fix into a string
+ *
+ * @param fix The NMEALIB_FIX_* fix
+ * @return The corresponding string, or NULL when the NMEALIB_FIX_* fix is
+ * unknown
+ */
+static INLINE const char *nmeaInfoFixToString(NmeaFix fix) {
+  switch (fix) {
+    case NMEALIB_FIX_BAD:
+      return "BAD";
+
+    case NMEALIB_FIX_2D:
+      return "2D";
+
+    case NMEALIB_FIX_3D:
+      return "3D";
+
+    default:
+      return NULL;
+  }
+}
+
+/*
+ * Limits and defaults
+ */
+
+/** The maximum number of satellites (must be a multiple of NMEALIB_GPGSV_MAX_SATS_PER_SENTENCE) */
+#define NMEALIB_MAX_SATELLITES              (72u)
+
+/** The default latitude */
+#define NMEALIB_LATITUDE_DEFAULT_NDEG       (0.0)
+
+/** The default longitude */
+#define NMEALIB_LONGITUDE_DEFAULT_NDEG      (0.0)
+
+/**
+ * Date and time data
+ */
+typedef struct _NmeaTime {
+  unsigned int year; /**< Years                    - [1900, 2089]                 */
+  unsigned int mon;  /**< Months                   - [   1,   12]                 */
+  unsigned int day;  /**< Day of the month         - [   1,   31]                 */
+  unsigned int hour; /**< Hours since midnight     - [   0,   23]                 */
+  unsigned int min;  /**< Minutes after the hour   - [   0,   59]                 */
+  unsigned int sec;  /**< Seconds after the minute - [   0,   60] (1 leap second) */
+  unsigned int hsec; /**< Hundredth part of second - [   0,   99]                 */
+} NmeaTime;
+
+/**
+ * Parse a NMEA time into a NmeaTime structure (time only, no date).
+ *
+ * The format that is used (HHMMSS, HHMMSS.t, HHMMSS.hh or HHMMSS.mmm) is
+ * determined by the length of the string.
+ *
+ * @param s The time
+ * @param time The structure in which to store the parsed time
+ * @return True on success
+ */
+bool nmeaTimeParseTime(const char *s, NmeaTime *time);
+
+/**
+ * Parse a NMEA date into a NmeaTime structure (date only, no time).
+ *
+ * @param s The date (DDMMYY)
+ * @param date The structure in which to store the parsed date
+ * @return True on success
+ */
+bool nmeaTimeParseDate(const char *s, NmeaTime *date);
+
+/**
+ * Position data in decimal degrees or radians
+ */
+typedef struct _NmeaPosition {
+  double lat; /**< Latitude  */
+  double lon; /**< Longitude */
+} NmeaPosition;
+
+/**
+ * Information about satellite
+ */
+typedef struct _NmeaSatellite {
+  unsigned int prn;       /**< Satellite PRN number             - [1, inf) */
+  int          elevation; /**< Elevation, in degrees            - [0,  90] */
+  unsigned int azimuth;   /**< Azimuth, degrees from true north - [0, 359] */
+  unsigned int snr;       /**< Signal-to-Noise-Ratio            - [0,  99] */
+} NmeaSatellite;
+
+/**
+ * Information about all tracked satellites
+ */
+typedef struct _NmeaSatellites {
+  unsigned int  inUseCount;                     /**< The number of satellites in use (not those in view) */
+  unsigned int  inUse[NMEALIB_MAX_SATELLITES];  /**< The PRNs of satellites in use   (not those in view) */
+  unsigned int  inViewCount;                    /**< The number of satellites in view                    */
+  NmeaSatellite inView[NMEALIB_MAX_SATELLITES]; /**< Satellites information (in view)                    */
+} NmeaSatellites;
+
+/**
+ * Information about progress on non-atomic sentences
+ */
+typedef struct _NmeaProgress {
+  bool gpgsvInProgress; /**< true when gpgsv is in progress */
+} NmeaProgress;
+
+/**
+ * GPS information from all supported sentences
+ */
+typedef struct _NmeaInfo {
+  uint32_t       present;    /**< Bit-mask specifying which fields are present                    */
+  uint32_t       smask;      /**< Bit-mask specifying from which sentences data has been obtained */
+  NmeaTime       utc;        /**< UTC of the position data                                        */
+  NmeaSignal     sig;        /**< Signal quality, see NMEALIB_SIG_* signals                       */
+  NmeaFix        fix;        /**< Operating mode, see NMEALIB_FIX_* fixes                         */
+  double         pdop;       /**< Position Dilution Of Precision                                  */
+  double         hdop;       /**< Horizontal Dilution Of Precision                                */
+  double         vdop;       /**< Vertical Dilution Of Precision                                  */
+  double         latitude;   /**< Latitude,  in NDEG: +/-[degree][min].[sec/60]                   */
+  double         longitude;  /**< Longitude, in NDEG: +/-[degree][min].[sec/60]                   */
+  double         elevation;  /**< Elevation above/below mean sea level (geoid), in meters         */
+  double         height;     /**< Height of geoid (elevation) above WGS84 ellipsoid, in meters    */
+  double         speed;      /**< Speed over the ground in kph                                    */
+  double         track;      /**< Track angle in degrees true north                               */
+  double         mtrack;     /**< Magnetic Track angle in degrees true north                      */
+  double         magvar;     /**< Magnetic variation in degrees                                   */
+  double         dgpsAge;    /**< Time since last DGPS update, in seconds                         */
+  unsigned int   dgpsSid;    /**< DGPS station ID number                                          */
+  NmeaSatellites satellites; /**< Satellites information                                          */
+  NmeaProgress   progress;   /**< Progress information                                            */
+  bool           metric;     /**< When true then units are metric                                 */
+} NmeaInfo;
+
+/**
+ * Enumeration for the fields names of a NmeaInfo structure
+ *
+ * The values are used in the 'present' bit-mask.
+ */
+typedef enum _NmeaPresence {
+  NMEALIB_PRESENT_SMASK          = (1u << 0),  /* 0x00000001 */
+  NMEALIB_PRESENT_FIRST          = NMEALIB_PRESENT_SMASK,
+  NMEALIB_PRESENT_UTCDATE        = (1u << 1),  /* 0x00000002 */
+  NMEALIB_PRESENT_UTCTIME        = (1u << 2),  /* 0x00000004 */
+  NMEALIB_PRESENT_SIG            = (1u << 3),  /* 0x00000008 */
+
+  NMEALIB_PRESENT_FIX            = (1u << 4),  /* 0x00000010 */
+  NMEALIB_PRESENT_PDOP           = (1u << 5),  /* 0x00000020 */
+  NMEALIB_PRESENT_HDOP           = (1u << 6),  /* 0x00000040 */
+  NMEALIB_PRESENT_VDOP           = (1u << 7),  /* 0x00000080 */
+
+  NMEALIB_PRESENT_LAT            = (1u << 8),  /* 0x00000100 */
+  NMEALIB_PRESENT_LON            = (1u << 9),  /* 0x00000200 */
+  NMEALIB_PRESENT_ELV            = (1u << 10), /* 0x00000400 */
+  NMEALIB_PRESENT_SPEED          = (1u << 11), /* 0x00000800 */
+
+  NMEALIB_PRESENT_TRACK          = (1u << 12), /* 0x00001000 */
+  NMEALIB_PRESENT_MTRACK         = (1u << 13), /* 0x00002000 */
+  NMEALIB_PRESENT_MAGVAR         = (1u << 14), /* 0x00004000 */
+  NMEALIB_PRESENT_SATINUSECOUNT  = (1u << 15), /* 0x00008000 */
+
+  NMEALIB_PRESENT_SATINUSE       = (1u << 16), /* 0x00010000 */
+  NMEALIB_PRESENT_SATINVIEWCOUNT = (1u << 17), /* 0x00020000 */
+  NMEALIB_PRESENT_SATINVIEW      = (1u << 18), /* 0x00040000 */
+  NMEALIB_PRESENT_HEIGHT         = (1u << 19), /* 0x00080000 */
+
+  NMEALIB_PRESENT_DGPSAGE        = (1u << 20), /* 0x00100000 */
+  NMEALIB_PRESENT_DGPSSID        = (1u << 21), /* 0x00200000 */
+
+  NMEALIB_PRESENT_LAST           = NMEALIB_PRESENT_DGPSSID
+} NmeaPresence;
+
+/** The bit-mask of all supported field name bits */
+#define NMEALIB_INFO_PRESENT_MASK (NMEALIB_PRESENT_LAST | (NMEALIB_PRESENT_LAST  - 1))
+
+/**
+ * Convert a NmeaPresence into a string
+ *
+ * @param field The NmeaPresence
+ * @return The corresponding string, or NULL when the NmeaPresence is unknown
+ */
+static INLINE const char *nmeaInfoFieldToString(NmeaPresence field) {
+  switch (field) {
+    case NMEALIB_PRESENT_SMASK:
+      return "SMASK";
+
+    case NMEALIB_PRESENT_UTCDATE:
+      return "UTCDATE";
+
+    case NMEALIB_PRESENT_UTCTIME:
+      return "UTCTIME";
+
+    case NMEALIB_PRESENT_SIG:
+      return "SIG";
+
+    case NMEALIB_PRESENT_FIX:
+      return "FIX";
+
+    case NMEALIB_PRESENT_PDOP:
+      return "PDOP";
+
+    case NMEALIB_PRESENT_HDOP:
+      return "HDOP";
+
+    case NMEALIB_PRESENT_VDOP:
+      return "VDOP";
+
+    case NMEALIB_PRESENT_LAT:
+      return "LAT";
+
+    case NMEALIB_PRESENT_LON:
+      return "LON";
+
+    case NMEALIB_PRESENT_ELV:
+      return "ELV";
+
+    case NMEALIB_PRESENT_HEIGHT:
+      return "HEIGHT";
+
+    case NMEALIB_PRESENT_SPEED:
+      return "SPEED";
+
+    case NMEALIB_PRESENT_TRACK:
+      return "TRACK";
+
+    case NMEALIB_PRESENT_MTRACK:
+      return "MTRACK";
+
+    case NMEALIB_PRESENT_MAGVAR:
+      return "MAGVAR";
+
+    case NMEALIB_PRESENT_SATINUSECOUNT:
+      return "SATINUSECOUNT";
+
+    case NMEALIB_PRESENT_SATINUSE:
+      return "SATINUSE";
+
+    case NMEALIB_PRESENT_SATINVIEWCOUNT:
+      return "SATINVIEWCOUNT";
+
+    case NMEALIB_PRESENT_SATINVIEW:
+      return "SATINVIEW";
+
+    case NMEALIB_PRESENT_DGPSAGE:
+      return "DGPSAGE";
+
+    case NMEALIB_PRESENT_DGPSSID:
+      return "DGPSSID";
+
+    default:
+      return NULL;
+  }
+}
+
+/**
+ * Determine if a 'present' bit-mask indicates presence of all of the
+ * indicated NmeaPresence field names
+ *
+ * @param present The 'present' field
+ * @param fieldName The NmeaPresence to check for presence
+ * @return True when all of the NmeaPresence field names are present
+ */
+static INLINE bool nmeaInfoIsPresentAll(uint32_t present, NmeaPresence fieldName) {
+  return ((present & fieldName) == fieldName);
+}
+
+/**
+ * Determine if a 'present' bit-mask indicates presence of any of the
+ * indicated NmeaPresence field names
+ *
+ * @param present The 'present' field
+ * @param fieldName The NmeaPresence bit-mask to check for presence
+ * @return True when any of the NmeaPresence field names are present
+ */
+static INLINE bool nmeaInfoIsPresentAny(uint32_t present, NmeaPresence fieldName) {
+  return ((present & fieldName) != 0);
+}
+
+/**
+ * Adjust a 'present' bit-mask to indicate presence of a certain
+ * NmeaPresence
+ *
+ * @param present The 'present' field
+ * @param fieldName The NmeaPresence to indicate presence of
+ */
+static INLINE void nmeaInfoSetPresent(uint32_t *present, NmeaPresence fieldName) {
+  if (present) {
+    *present |= fieldName;
+  }
+}
+
+/**
+ * Adjust a 'present' bit-mask to indicate absence of a certain NmeaPresence
+ *
+ * @param present The 'present' field
+ * @param fieldName The NmeaPresence to absence presence of
+ */
+static INLINE void nmeaInfoUnsetPresent(uint32_t *present, NmeaPresence fieldName) {
+  if (present) {
+    *present &= ~fieldName;
+  }
+}
+
+/**
+ * Reset the time to now
+ *
+ * @param utc The time
+ * @param present The 'present' field (when non-NULL then the UTCDATE and
+ * UTCTIME flags are set in it)
+ * @param timeval If non-NULL then use this provided time, otherwise the
+ * 'gettimeofday' c-library function is used to obtain it
+ */
+void nmeaTimeSet(NmeaTime *utc, uint32_t *present, struct timeval *timeval);
+
+/**
+ * Clear an info structure.
+ *
+ * Sets up the signal as NMEALIB_SIG_INVALID, the FIX as
+ * NMEALIB_FIX_BAD, and signals presence of these fields.
+ *
+ * Resets all other fields to 0.
+ *
+ * @param info The info structure
+ */
+void nmeaInfoClear(NmeaInfo *info);
+
+/**
+ * Sanitise the NMEA info, make sure that:
+ * - all information is in the original units
+ * - utc date is set to the current date when not present
+ * - utc time is set to the current time when not present
+ * - sig is in the range [NMEALIB_SIG_FIRST, NMEALIB_SIG_LAST],
+ *   if this is not the case then sig is set to NMEALIB_SIG_INVALID
+ * - fix is in the range [NMEALIB_FIX_FIRST, NMEALIB_FIX_LAST],
+ *   if this is not the case then fix is set to NMEALIB_FIX_BAD
+ * - DOPs are positive
+ * - latitude is in the range [-9000, 9000]
+ * - longitude is in the range [-18000, 18000]
+ * - speed is positive
+ * - track is in the range [0, 360>
+ * - mtrack is in the range [0, 360>
+ * - magvar is in the range [0, 360>
+ * - dgpsAge is positive
+ * - dgpsSid is positive
+ * - satinfo:
+ *   - inuseCount is positive
+ *   - each inUse satellite has a positive PRN
+ *   - inUse satellites are compacted (satellites with a zero PRN last)
+ *   - inViewCount is positive
+ *   - inView (only when GPGSV is not 'in progress'):
+ *     - prn is positive
+ *     - elevation is in the range [-90, 90]
+ *     - azimuth is in the range [0, 359]
+ *     - snr is in the range [0, 99]
+ *
+ * Fields are reset to their defaults when not signalled as being present.
+ *
+ * @param info The NMEA info structure to sanitise
+ */
+void nmeaInfoSanitise(NmeaInfo *info);
+
+/**
+ * Converts the position fields to degrees and DOP fields to meters so that
+ * all fields use normal metric units or original units.
+ *
+ * If the NmeaInfo information is already in the requested format then
+ * this function does nothing.
+ *
+ * @param info The NmeaInfo
+ * @param toMetric Convert to metric units (from original units) when true,
+ * convert to original units (from metric units) when false
+ */
+void nmeaInfoUnitConversion(NmeaInfo *info, bool toMetric);
+
+/**
+ * Compare 2 satellite PRNs and put zeroes last
+ *
+ * @param p1 The first satellite PRN
+ * @param p2 The second satellite PRN
+ * @return 0 when both are equal, a negative value when PRN1 < PRN2, a
+ * positive value otherwise
+ */
+int nmeaQsortPRNCompare(const void *p1, const void *p2);
+
+/**
+ * Compact 2 satellite PRNs (do not reorder) and put zeroes last
+ *
+ * @param p1 The first satellite PRN
+ * @param p2 The second satellite PRN
+ * @return 0 when both are non-zero or are equal, a negative value when
+ * PRN1 < PRN2, a positive value otherwise
+ */
+int nmeaQsortPRNCompact(const void *p1, const void *p2);
+
+/**
+ * Compare 2 satellite PRNs and put zeroes last
+ *
+ * @param s1 The first satellite
+ * @param s2 The second satellite
+ * @return 0 when both are equal, a negative value when PRN1 < PRN2, a
+ * positive value otherwise
+ */
+int nmeaQsortSatelliteCompare(const void *s1, const void *s2);
+
+/**
+ * Compact 2 satellite PRNs (do not reorder) and put zeroes last
+ *
+ * @param s1 The first satellite
+ * @param s2 The second satellite
+ * @return 0 when both are non-zero or are equal, a negative value when
+ * PRN1 < PRN2, a positive value otherwise
+ */
+int nmeaQsortSatelliteCompact(const void *s1, const void *s2);
+
+#ifdef  __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __NMEALIB_INFO_H__ */
diff --git a/lib/pud/nmealib/include/nmealib/nmath.h b/lib/pud/nmealib/include/nmealib/nmath.h
new file mode 100644 (file)
index 0000000..41783ea
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * This file is part of nmealib.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __NMEALIB_MATH_H__
+#define __NMEALIB_MATH_H__
+
+#include <nmealib/info.h>
+#include <stdbool.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define NMEALIB_KNOT_TO_KPH           (1.852)
+#define NMEALIB_KPH_TO_KNOT           (0.5399568034557234996739794041786808520)
+#define NMEALIB_DEGREE_TO_RADIAN      (0.0174532925199432957692369076848861271)
+#define NMEALIB_RADIAN_TO_DEGREE      (57.2957795130823208767981548141051703)
+#define NMEALIB_DOP_TO_METER          (5.0)
+#define NMEALIB_METER_TO_DOP          (0.2)
+#define NMEALIB_MPS_TO_KPH            (3.6)
+#define NMEALIB_PI                    (3.1415926535897932384626433832795029)
+#define NMEALIB_EARTHRADIUS_KM        (6378.137)
+#define NMEALIB_EARTHRADIUS_M         (6378137)
+#define NMEALIB_EARTH_SEMIMAJORAXIS_M (6356752.3142)
+#define NMEALIB_EARTH_FLATTENING      (1.0 / 298.257223563)
+
+/*
+ * Degrees and Radians
+ */
+
+/**
+ * Convert decimal degrees to radians
+ *
+ * @param v Degrees
+ * @return Radians
+ */
+double nmeaMathDegreeToRadian(const double v);
+
+/**
+ * Convert radians to decimal degrees
+ *
+ * @param v Radians
+ * @return Degrees
+ */
+double nmeaMathRadianToDegree(const double v);
+
+/*
+ * NDEG (NMEA degree)
+ */
+
+/**
+ * Convert NDEG (NMEA degrees) to decimal degrees
+ *
+ * @param v NDEG (NMEA degrees)
+ * @return Decimal degrees
+ */
+double nmeaMathNdegToDegree(const double v);
+
+/**
+ * Convert decimal degrees to NDEG (NMEA degrees)
+ *
+ * @param v Decimal degrees
+ * @return NDEG (NMEA degrees)
+ */
+double nmeaMathDegreeToNdeg(const double v);
+
+/**
+ * Convert NDEG (NMEA degrees) to radians
+ *
+ * @param v NDEG (NMEA degrees)
+ * @return Radians
+ */
+double nmeaMathNdegToRadian(const double v);
+
+/**
+ * Convert radians to NDEG (NMEA degrees)
+ *
+ * @param v Radians
+ * @return NDEG (NMEA degrees)
+ */
+double nmeaMathRadianToNdeg(const double v);
+
+/*
+ * DOP
+ */
+
+/**
+ * Calculate PDOP (Position Dilution Of Precision) from HDOP and VDOP
+ *
+ * @param hdop HDOP
+ * @param vdop VDOP
+ * @return PDOP
+ */
+double nmeaMathPdopCalculate(const double hdop, const double vdop);
+
+/**
+ * Convert DOP to meters, using the NMEALIB_DOP_FACTOR factor
+ *
+ * @param dop The DOP
+ * @return The DOP in meters
+ */
+double nmeaMathDopToMeters(const double dop);
+
+/**
+ * Convert DOP in meters to plain DOP, using the NMEALIB_DOP_FACTOR factor
+ *
+ * @param meters The DOP in meters
+ * @return The plain DOP
+ */
+double nmeaMathMetersToDop(const double meters);
+
+/*
+ * Positions
+ */
+
+/**
+ * Convert a NmeaInfo position to a radians position
+ *
+ * @param info The NmeaInfo position
+ * @param pos The radians position
+ */
+void nmeaMathInfoToPosition(const NmeaInfo *info, NmeaPosition *pos);
+
+/**
+ * Convert a radians position to a NmeaInfo position
+ *
+ * @param pos The radians position
+ * @param info The NmeaInfo position
+ */
+void nmeaMathPositionToInfo(const NmeaPosition *pos, NmeaInfo *info);
+
+/**
+ * Calculate the distance between two points
+ *
+ * @param from The 'from' position (in radians)
+ * @param to The 'to' position (in radians)
+ * @return Distance in meters
+ */
+double nmeaMathDistance(const NmeaPosition *from, const NmeaPosition *to);
+
+/**
+ * Calculate the distance between two points
+ *
+ * This function uses an algorithm for an oblate spheroid earth model.
+ * The algorithm is described here:
+ *   http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
+ *
+ * @param from The 'from' position (in radians)
+ * @param to The 'to' position (in radians)
+ * @param fromAzimuth The azimuth at 'from' position (in radians)
+ * @param toAzimuth The azimuth at 'to' position (in radians)
+ * @return Distance in meters
+ */
+double nmeaMathDistanceEllipsoid(const NmeaPosition *from, const NmeaPosition *to, double *fromAzimuth,
+    double *toAzimuth);
+
+/**
+ * Perform a flat (horizontal) move.
+ *
+ * @param from The 'from' position (in radians)
+ * @param to The 'to' position (in radians)
+ * @param azimuth Azimuth (in degrees, [0, 359])
+ * @param distance The distance (in km)
+ * @return True on success
+ */
+bool nmeaMathMoveFlat(const NmeaPosition *from, NmeaPosition *to, double azimuth, double distance);
+
+/**
+ * Perform a flat (horizontal) move against the ellipsoid.
+ *
+ * This function uses an algorithm for an oblate spheroid earth model.
+ * The algorithm is described here:
+ *   http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
+ *
+ * @param from The 'from' position (in radians)
+ * @param to The 'to' position (in radians)
+ * @param azimuth Azimuth (in radians)
+ * @param distance The distance (in km)
+ * @param toAzimuth Azimuth at end position (in radians)
+ * @return True on success
+ */
+bool nmeaMathMoveFlatEllipsoid(const NmeaPosition *from, NmeaPosition *to, double azimuth, double distance,
+    double *toAzimuth);
+
+#ifdef  __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __NMEALIB_MATH_H__ */
diff --git a/lib/pud/nmealib/include/nmealib/parser.h b/lib/pud/nmealib/include/nmealib/parser.h
new file mode 100644 (file)
index 0000000..c4e5288
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * This file is part of nmealib.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __NMEALIB_PARSER_H__
+#define __NMEALIB_PARSER_H__
+
+#include <nmealib/info.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifdef NMEALIB_MAX_SENTENCE_LENGTH
+  #define NMEALIB_PARSER_SENTENCE_SIZE (NMEALIB_MAX_SENTENCE_LENGTH)
+#else
+  #define NMEALIB_PARSER_SENTENCE_SIZE (NMEALIB_BUFFER_CHUNK_SIZE)
+#endif
+
+typedef enum _NmeaParserSentenceState {
+  NMEALIB_SENTENCE_STATE_SKIP_UNTIL_START,
+  NMEALIB_SENTENCE_STATE_READ_SENTENCE,
+  NMEALIB_SENTENCE_STATE_READ_CHECKSUM,
+  NMEALIB_SENTENCE_STATE_READ_EOL
+} NmeaParserSentenceState;
+
+/**
+ * NMEA frame parser structure
+ */
+typedef struct _NmeaParserSentence {
+    NmeaParserSentenceState state;
+
+    bool checksumPresent;
+
+    char checksumCharacters[2];
+    char checksumCharactersCount;
+
+    int checksumRead;
+    int checksumCalculated;
+
+    unsigned char eolCharactersCount;
+} NmeaParserSentence;
+
+/**
+ * parsed NMEA data and frame parser state
+ */
+typedef struct _NmeaParser {
+    NmeaParserSentence sentence;
+    size_t bufferLength;
+    char *buffer;
+    size_t bufferSize;
+} NmeaParser;
+
+/**
+ * Initialise the parser
+ *
+ * Allocates memory for the parse buffer.
+ *
+ * @param parser The parser
+ * @param sz The size for the allocated parse buffer, If zero then
+ * NMEALIB_PARSER_SENTENCE_SIZE is used
+ * @return True on success
+ */
+bool nmeaParserInit(NmeaParser *parser, size_t sz);
+
+/**
+ * Destroy the parser
+ *
+ * Frees memory of the parse buffer.
+ *
+ * @param parser The parser
+ * @return True on success
+ */
+bool nmeaParserDestroy(NmeaParser *parser);
+
+/**
+ * Parse NMEA sentences from a (string) buffer and store the results in the
+ * info structure
+ *
+ * @param parser The parser
+ * @param s The (string) buffer
+ * @param sz The length of the string in the buffer
+ * @param info The info structure in which to store the information
+ * @return The number of sentences that were parsed
+ */
+size_t nmeaParserParse(NmeaParser *parser, const char *s, size_t sz, NmeaInfo *info);
+
+#ifdef  __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __NMEALIB_PARSER_H__ */
diff --git a/lib/pud/nmealib/include/nmealib/sentence.h b/lib/pud/nmealib/include/nmealib/sentence.h
new file mode 100644 (file)
index 0000000..ac7919c
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * This file is part of nmealib.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * @file
+ * NMEA Sentences
+ *
+ * The table below describes which NmeaInfo fields are present in the
+ * sentences that are supported by the library.
+ *
+ * | NmeaInfo field       | GPGGA | GPGSA | GPGSV | GPRMC | GPVTG |
+ * | :------------------- | :---: | :---: | :---: | :---: | :---: |
+ * | present              | x     | x     | x     | x     | x     |
+ * | smask                | x     | x     | x     | x     | x     |
+ * | utc (date)           |       |       |       | x     |       |
+ * | utc (time)           | x     |       |       | x     |       |
+ * | sig                  | x     | x (1) |       | x (3) |       |
+ * | fix                  |       | x     |       |       |       |
+ * | PDOP                 |       | x     |       |       |       |
+ * | HDOP                 | x     | x     |       |       |       |
+ * | VDOP                 |       | x     |       |       |       |
+ * | lat                  | x     |       |       | x     |       |
+ * | lon                  | x     |       |       | x     |       |
+ * | elv                  | x     |       |       |       |       |
+ * | height               | x     |       |       |       |       |
+ * | speed                |       |       |       | x     | x     |
+ * | track                |       |       |       | x     | x     |
+ * | mtrack               |       |       |       |       | x     |
+ * | magvar               |       |       |       | x     |       |
+ * | dgps_age             | x     |       |       |       |       |
+ * | dgps_sid             | x     |       |       |       |       |
+ * | satinfo inuse count  |       | x (2) |       |       |       |
+ * | satinfo inuse        |       | x     |       |       |       |
+ * | satinfo inview count | x     |       | x     |       |       |
+ * | satinfo inview       |       |       | x     |       |       |
+ *
+ * (1) Only sets the NmeaInfo sig when it is not set yet.<br/>
+ * (2) Not present in the sentence but the library sets it up.<br/>
+ * (3) If the sentence is a v2.3+ sentence then the NmeaInfo sig is set
+ *     normally, otherwise the NmeaInfo sig is only set when it is not
+ *     set yet.
+ */
+
+#ifndef __NMEALIB_SENTENCE_H__
+#define __NMEALIB_SENTENCE_H__
+
+#include <nmealib/gpgga.h>
+#include <nmealib/gpgsa.h>
+#include <nmealib/gpgsv.h>
+#include <nmealib/gprmc.h>
+#include <nmealib/gpvtg.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * Supported NMEA sentences
+ */
+typedef enum _NmeaSentence {
+  NMEALIB_SENTENCE_GPNON = 0u,
+  NMEALIB_SENTENCE_FIRST = NMEALIB_SENTENCE_GPNON,
+  NMEALIB_SENTENCE_GPGGA = (1u << 0),
+  NMEALIB_SENTENCE_GPGSA = (1u << 1),
+  NMEALIB_SENTENCE_GPGSV = (1u << 2),
+  NMEALIB_SENTENCE_GPRMC = (1u << 3),
+  NMEALIB_SENTENCE_GPVTG = (1u << 4),
+  NMEALIB_SENTENCE_LAST = NMEALIB_SENTENCE_GPVTG
+} NmeaSentence;
+
+/** The bit-mask with all NmeaSentence entries */
+#define NMEALIB_SENTENCE_MASK (NMEALIB_SENTENCE_LAST | (NMEALIB_SENTENCE_LAST - 1))
+
+/** The fixed length of a NMEA prefix */
+#define NMEALIB_PREFIX_LENGTH 5
+
+/**
+ * The type definition for an entry mapping a NMEA sentence prefix to a sentence type
+ */
+typedef struct _NmeaSentencePrefixToType {
+  const char *prefix;
+  const NmeaSentence sentence;
+} NmeaSentencePrefixToType;
+
+/**
+ * The map from NMEA sentence prefix to sentence type
+ */
+static const NmeaSentencePrefixToType nmealibSentencePrefixToType[] = {
+    {
+        .prefix = NMEALIB_GPGGA_PREFIX, //
+        .sentence = NMEALIB_SENTENCE_GPGGA //
+    },
+    {
+        .prefix = NMEALIB_GPGSA_PREFIX, //
+        .sentence = NMEALIB_SENTENCE_GPGSA //
+    },
+    {
+        .prefix = NMEALIB_GPGSV_PREFIX, //
+        .sentence = NMEALIB_SENTENCE_GPGSV //
+    },
+    {
+        .prefix = NMEALIB_GPRMC_PREFIX, //
+        .sentence = NMEALIB_SENTENCE_GPRMC //
+    },
+    {
+        .prefix = NMEALIB_GPVTG_PREFIX, //
+        .sentence = NMEALIB_SENTENCE_GPVTG //
+    },
+    {
+        .prefix = NULL, //
+        .sentence = NMEALIB_SENTENCE_GPNON //
+    }//
+};
+
+/**
+ * A malloced buffer and its size.
+ *
+ * This type is used in functions that need allocated memory of variable
+ * size: the function can allocate memory and reallocate it if needed.
+ *
+ * Using this type allows for the users of the functions to decide for
+ * themselves whether or not to re-use (previously) allocated memory or
+ * to treat the allocated memory as once-off.
+ *
+ * When handing this type to a function, one of the following 2 cases
+ * MUST be used (the function will check for these):
+ * 1- buffer is NULL and bufferSize is zero: this indicates that
+ *    the function should allocate memory and can reallocate memory
+ *    to increase the allocated size if needed.
+ * 2- buffer is not NULL and bufferSize is not zero: this indicates that
+ *    the user has already allocated memory so the function should not
+ *    (initially) allocate memory. However, the function can reallocate
+ *    memory to increase the allocated size if needed.
+ */
+typedef struct _NmeaMallocedBuffer {
+  char *buffer;
+  size_t bufferSize;
+} NmeaMallocedBuffer;
+
+/**
+ * Determine the NMEA prefix from the sentence type.
+ *
+ * @param sentence The sentence type
+ * @return The NMEA prefix, or NULL when the sentence type is unknown
+ */
+static INLINE const char *nmeaSentenceToPrefix(NmeaSentence sentence) {
+  size_t i = 0;
+
+  while (nmealibSentencePrefixToType[i].prefix) {
+    if (nmealibSentencePrefixToType[i].sentence == sentence) {
+      return nmealibSentencePrefixToType[i].prefix;
+    }
+
+    i++;
+  }
+
+  return NULL;
+}
+
+/**
+ * Determine the sentence type from the start of the specified NMEA
+ * sentence
+ *
+ * If the first character of the string is equal to the NMEA start-of-line
+ * character ('$') then that character is skipped.
+ *
+ * @param s The NMEA sentence
+ * @param sz The length of the NMEA sentence
+ * @return The packet type, or GPNON when it could not be determined
+ */
+NmeaSentence nmeaSentenceFromPrefix(const char *s, const size_t sz);
+
+/**
+ * Parse a NMEA sentence into an unsanitised NmeaInfo structure
+ *
+ * @param s The NMEA sentence
+ * @param sz The length of the NMEA sentence
+ * @param info The unsanitised NmeaInfo structure in which to stored the information
+ * @return True when successful
+ */
+bool nmeaSentenceToInfo(const char *s, const size_t sz, NmeaInfo *info);
+
+/**
+ * Generate NMEA sentences from a sanitised NmeaInfo structure.
+ *
+ * Allocates memory as needed.
+ *
+ * @param buf The allocated buffer (do read the comments of NmeaMallocedBuffer)
+ * @param info The sanitised NmeaInfo structure
+ * @param mask The bit-mask of sentences to generate
+ * @return The total length of the generated sentences
+ */
+size_t nmeaSentenceFromInfo(NmeaMallocedBuffer *buf, const NmeaInfo *info, const NmeaSentence mask);
+
+#ifdef  __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __NMEALIB_SENTENCE_H__ */
diff --git a/lib/pud/nmealib/include/nmealib/util.h b/lib/pud/nmealib/include/nmealib/util.h
new file mode 100644 (file)
index 0000000..44d2fbf
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * This file is part of nmealib.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __NMEALIB_TOK_H__
+#define __NMEALIB_TOK_H__
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifndef INLINE
+#define INLINE inline __attribute__((always_inline))
+#endif
+
+#ifndef MAX
+#define MAX(x,y) (((x) >= (y)) ? (x) : (y))
+#endif
+
+#ifndef MIN
+#define MIN(x,y) (((x) <= (y)) ? (x) : (y))
+#endif
+
+/** The power-of-2 chunk size of a buffer allocation */
+#define NMEALIB_BUFFER_CHUNK_SIZE (4096UL)
+
+/** NaN that is a double (and not a float) */
+#define NaN strtod("NAN()", NULL)
+
+/** isnan for doubles and floats alike */
+#define isNaN(x) (x != x)
+
+/**
+ * Initialise the random number generation
+ */
+void nmeaRandomInit(void);
+
+/**
+ * Generate a random number
+ *
+ * @param min The minimum value of the generated random number
+ * @param max The maximum value of the generated random number
+ * @return A random number in the range [min, max]
+ */
+double nmeaRandom(const double min, const double max);
+
+/**
+ * Trim a string of whitespace
+ *
+ * @param s The location of the string variable
+ * @return The length of the trimmed string
+ */
+size_t nmeaStringTrim(const char **s);
+
+/**
+ * Determine whether a string contains whitespace
+ *
+ * @param s The string to check for whitespace
+ * @param sz The length of the string
+ * @return True when the string contains whitespace
+ */
+bool nmeaStringContainsWhitespace(const char *s, size_t sz);
+
+/**
+ * Calculate the NMEA (CRC-8) checksum of a NMEA sentence.
+ *
+ * If the string starts with the NMEA start-of-line character '$' then that
+ * character is skipped as per the NMEA spec.
+ *
+ * @param s The NMEA sentence
+ * @param sz The length of the NMEA sentence
+ * @return The NMEA checksum
+ */
+unsigned int nmeaCalculateCRC(const char *s, const size_t sz);
+
+/**
+ * Convert a string to an integer
+ *
+ * @param s The string
+ * @param sz The length of the string
+ * @param radix The radix of the numbers in the string
+ * @return The converted number, or 0 on failure
+ */
+int nmeaStringToInteger(const char *s, const size_t sz, const int radix);
+
+/**
+ * Convert a string to an unsigned integer
+ *
+ * @param s The string
+ * @param sz The length of the string
+ * @param radix The radix of the numbers in the string
+ * @return The converted number, or 0 on failure
+ */
+unsigned int nmeaStringToUnsignedInteger(const char *s, size_t sz, int radix);
+
+/**
+ * Convert string to a long integer
+ *
+ * @param s The string
+ * @param sz The length of the string
+ * @param radix The radix of the numbers in the string
+ * @return The converted number, or 0 on failure
+ */
+long nmeaStringToLong(const char *s, size_t sz, int radix);
+
+/**
+ * Convert string to an unsigned long integer
+ *
+ * @param s The string
+ * @param sz The length of the string
+ * @param radix The radix of the numbers in the string
+ * @return The converted number, or 0 on failure
+ */
+unsigned long nmeaStringToUnsignedLong(const char *s, size_t sz, int radix);
+
+/**
+ * Convert string to a floating point number
+ *
+ * @param s The string
+ * @param sz The length of the string
+ * @return The converted number, or 0.0 on failure
+ */
+double nmeaStringToDouble(const char *s, const size_t sz);
+
+/**
+ * Append a NMEA checksum to the string in the buffer
+ *
+ * @param s The buffer containing the string
+ * @param sz The size of the buffer
+ * @param len The length of the string in the buffer
+ * @return The number of printed characters, -1 on error
+ */
+int nmeaAppendChecksum(char *s, size_t sz, size_t len);
+
+/**
+ * Format a string (with vsnprintf) and add the NMEA checksum
+ *
+ * @param s The buffer
+ * @param sz The size of the buffer
+ * @param format The string format to use
+ * @return The number of printed characters, -1 on error
+ */
+int nmeaPrintf(char *s, size_t sz, const char *format, ...) __attribute__ ((format(printf, 3, 4)));
+
+/**
+ * Analyse a string (specific for NMEA sentences)
+ *
+ * @param s the string
+ * @param sz the length of the string
+ * @param format the string format to use
+ * @return the number of scanned tokens
+ */
+size_t nmeaScanf(const char *s, size_t sz, const char *format, ...);
+
+#ifdef  __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __NMEALIB_TOK_H__ */
diff --git a/lib/pud/nmealib/include/nmealib/validate.h b/lib/pud/nmealib/include/nmealib/validate.h
new file mode 100644 (file)
index 0000000..35c4b7c
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * This file is part of nmealib.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __NMEALIB_VALIDATE_H__
+#define __NMEALIB_VALIDATE_H__
+
+#include <nmealib/info.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * The type definition for an invalid NMEA character/description pair
+ */
+typedef struct _NmeaInvalidCharacter {
+  const char  character;
+  const char *description;
+} NmeaInvalidCharacter;
+
+/**
+ * Determine whether the given character is not allowed in an NMEA string
+ *
+ * @param c The character to check
+ *
+ * @return The invalid character character/description pair when the string
+ * has invalid characters, NULL otherwise
+ */
+const NmeaInvalidCharacter *nmeaValidateIsInvalidCharacter(const char c);
+
+/**
+ * Determine whether the specified string contains characters that are not
+ * allowed in an NMEA string
+ *
+ * @param s The string to check
+ * @param sz The length of the string to check
+ *
+ * @return The invalid character character/description pair when the string
+ * has invalid characters, NULL otherwise
+ */
+const NmeaInvalidCharacter *nmeaValidateSentenceHasInvalidCharacters(const char *s, const size_t sz);
+
+/**
+ * Validate the time fields in an NmeaTime structure.
+ *
+ * Expects:
+ * <pre>
+ *   hour [0, 23]
+ *   min  [0, 59]
+ *   sec  [0, 60] (1 leap second)
+ *   hsec [0, 99]
+ * </pre>
+ *
+ * @param t The structure
+ * @param prefix The NMEA prefix
+ * @param s The NMEA sentence
+ * @return True when valid, false otherwise
+ */
+bool nmeaValidateTime(const NmeaTime *t, const char *prefix, const char *s);
+
+/**
+ * Validate the date fields in an NmeaTime structure.
+ *
+ * Expects:
+ * <pre>
+ *   year  [90, 189]
+ *   month [ 0,  11]
+ *   day   [ 1,  31]
+ * </pre>
+ *
+ * @param t a pointer to the structure
+ * @param prefix The NMEA prefix
+ * @param s The NMEA sentence
+ * @return true when valid, false otherwise
+ */
+bool nmeaValidateDate(const NmeaTime *t, const char *prefix, const char *s);
+
+/**
+ * Validate north/south or east/west and upper-case it.
+ *
+ * Expects:
+ * <pre>
+ *   c in { N, S } (for north/south)
+ *   c in { E, W } (for east/west)
+ * </pre>
+ *
+ * @param c The character
+ * @param ns Evaluate north/south when true, evaluate east/west otherwise
+ * @param prefix The NMEA prefix
+ * @param s The NMEA sentence
+ * @return True when valid, false otherwise
+ */
+bool nmeaValidateNSEW(char c, const bool ns, const char *prefix, const char *s);
+
+/**
+ * Validate a fix.
+ *
+ * Expects:
+ * <pre>
+ *   fix in [NMEALIB_FIX_FIRST, NMEALIB_FIX_LAST]
+ * </pre>
+ *
+ * @param fix The fix
+ * @param prefix The NMEA prefix
+ * @param s The NMEA sentence
+ * @return True when valid, false otherwise
+ */
+bool nmeaValidateFix(NmeaFix fix, const char *prefix, const char *s);
+
+/**
+ * Validate a signal.
+ *
+ * Expects:
+ * <pre>
+ *   sig in [NMEALIB_SIG_FIRST, NMEALIB_SIG_LAST]
+ * </pre>
+ *
+ * @param sig The signal
+ * @param prefix The NMEA prefix
+ * @param s The NMEA sentence
+ * @return True when valid, false otherwise
+ */
+bool nmeaValidateSignal(NmeaSignal sig, const char *prefix, const char *s);
+
+/**
+ * Validate and upper-case the mode.
+ *
+ * Expects:
+ * <pre>
+ *   c in { A, D, E, F, M, N, P, R, S }
+ *
+ *   A = Autonomous
+ *   D = Differential
+ *   E = Estimated (dead reckoning)
+ *   F = Float RTK (using floating integers)
+ *   M = Manual input
+ *   N = No fix
+ *   P = Precise
+ *   R = Real Time Kinematic (using fixed integers)
+ *   S = Simulation mode
+ * </pre>
+ *
+ * @param c The character, will also be converted to upper-case.
+ * @param prefix The NMEA prefix
+ * @param s The NMEA sentence
+ * @return True when valid, false otherwise
+ */
+bool nmeaValidateMode(char c, const char *prefix, const char *s);
+
+/**
+ * Validate a satellite
+ *
+ * Expects:
+ * <pre>
+ *   elevation: in the range [-180, 180]
+ *   azimuth  : in the range [   0, 359]
+ *   signal   : in the range [   0,  99]
+ * </pre>
+ */
+bool nmeaValidateSatellite(NmeaSatellite *sat, const char *prefix, const char *s);
+
+#ifdef  __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __NMEALIB_VALIDATE_H__ */
index 77e3021..b5caf38 100644 (file)
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <nmea/context.h>
+#include <nmealib/context.h>
 
+#include <nmealib/util.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <stdlib.h>
 
 /**
- * The structure with nmealib context.
+ * The structure with the nmealib context.
  */
-typedef struct _nmeaPROPERTY {
-       nmeaTraceFunc trace_func; /**< the tracing function, defaults to NULL (disabled) */
-       nmeaErrorFunc error_func; /**< the error function, defaults to NULL (disabled) */
-       int parse_buff_size; /**< the size to use for temporary buffers, minimum is NMEA_MIN_PARSEBUFF */
-} nmeaPROPERTY;
-
-/** the nmealib context */
-static nmeaPROPERTY property = { .trace_func = NULL, .error_func = NULL, .parse_buff_size = NMEA_DEF_PARSEBUFF };
-
-/**
- * Set the trace function
- *
- * @param func the trace function
- */
-void nmea_context_set_trace_func(nmeaTraceFunc func) {
-       property.trace_func = func;
+typedef struct _NmeaContext {
+  volatile NmeaContextPrintFunction traceFunction;
+  volatile NmeaContextPrintFunction errorFunction;
+} NmeaContext;
+
+/** The nmealib context */
+static NmeaContext nmealibContext = {
+    .traceFunction = NULL,
+    .errorFunction = NULL };
+
+NmeaContextPrintFunction nmeaContextSetTraceFunction(NmeaContextPrintFunction traceFunction) {
+  NmeaContextPrintFunction r = nmealibContext.traceFunction;
+  nmealibContext.traceFunction = traceFunction;
+  return r;
 }
 
-/**
- * Set the error function
- *
- * @param func the error function
- */
-void nmea_context_set_error_func(nmeaErrorFunc func) {
-       property.error_func = func;
+NmeaContextPrintFunction nmeaContextSetErrorFunction(NmeaContextPrintFunction errorFunction) {
+  NmeaContextPrintFunction r = nmealibContext.errorFunction;
+  nmealibContext.errorFunction = errorFunction;
+  return r;
 }
 
-/**
- * Set the buffer size for temporary buffers.
- * If the size is less than NMEA_MIN_PARSEBUFF, then the size that is
- * configured will be NMEA_MIN_PARSEBUFF.
- *
- * @param buff_size the buffer size for temporary buffers
- */
-void nmea_context_set_buffer_size(int buff_size) {
-       if (buff_size < NMEA_MIN_PARSEBUFF)
-               property.parse_buff_size = NMEA_MIN_PARSEBUFF;
-       else
-               property.parse_buff_size = buff_size;
-}
-
-/**
- * @return the buffer size for temporary buffers
- */
-int nmea_context_get_buffer_size(void) {
-       return property.parse_buff_size;
+void nmeaContextTraceBuffer(const char *s, size_t sz) {
+  NmeaContextPrintFunction f = nmealibContext.traceFunction;
+  if (f && s && sz) {
+    (*f)(s, sz);
+  }
 }
 
-/**
- * Trace a formatted string
- *
- * @param str a formatted string
- */
-void nmea_trace(const char *str, ...) {
-       nmeaTraceFunc func = property.trace_func;
-
-       if (func) {
-               int size;
-               va_list arg_list;
-               char buff[property.parse_buff_size];
-
-               va_start(arg_list, str);
-               size = vsnprintf(&buff[0], property.parse_buff_size - 1, str, arg_list);
-               va_end(arg_list);
-
-               if (size > 0)
-                       (*func)(&buff[0], size);
-       }
+#define nmeaContextBufferEnlarge(buf, sz) { \
+  if (!(buf = realloc(buf, sz))) { \
+    /* can't be covered in a test */ \
+    goto out; \
+  } \
 }
 
-/**
- * Trace a buffer
- *
- * @param buff a pointer to the buffer
- * @param buff_size the size of the buffer
- */
-void nmea_trace_buff(const char *buff, int buff_size) {
-       nmeaTraceFunc func = property.trace_func;
-       if (func && buff_size)
-               (*func)(buff, buff_size);
+void nmeaContextTrace(const char *s, ...) {
+  NmeaContextPrintFunction f = nmealibContext.traceFunction;
+  if (s && f) {
+    va_list args;
+    va_list argsCopy;
+    char *buf = NULL;
+    size_t bufSz = NMEALIB_BUFFER_CHUNK_SIZE;
+    int printedChars;
+
+    va_start(args, s);
+    va_copy(argsCopy, args);
+
+    nmeaContextBufferEnlarge(buf, bufSz);
+    buf[0] = '\0';
+
+    printedChars = vsnprintf(buf, bufSz, s, args);
+    if (printedChars <= 0) {
+      goto out;
+    }
+    if ((size_t) printedChars >= bufSz) {
+      bufSz = (size_t) printedChars + 1;
+      nmeaContextBufferEnlarge(buf, bufSz);
+      printedChars = vsnprintf(buf, bufSz, s, argsCopy);
+    }
+
+    buf[bufSz - 1] = '\0';
+
+    (*f)(buf, (size_t) printedChars);
+
+out:
+    va_end(argsCopy);
+    va_end(args);
+    free(buf);
+  }
 }
 
-/**
- * Log a formatted error string
- *
- * @param str a formatted error string
- */
-void nmea_error(const char *str, ...) {
-       nmeaErrorFunc func = property.error_func;
-
-       if (func) {
-               int size;
-               va_list arg_list;
-               char buff[property.parse_buff_size];
-
-               va_start(arg_list, str);
-               size = vsnprintf(&buff[0], property.parse_buff_size - 1, str, arg_list);
-               va_end(arg_list);
-
-               if (size > 0)
-                       (*func)(&buff[0], size);
-       }
+void nmeaContextError(const char *s, ...) {
+  NmeaContextPrintFunction f = nmealibContext.errorFunction;
+  if (s && f) {
+    va_list args;
+    va_list argsCopy;
+    char *buf = NULL;
+    size_t bufSz = NMEALIB_BUFFER_CHUNK_SIZE;
+    int printedChars;
+
+    va_start(args, s);
+    va_copy(argsCopy, args);
+
+    nmeaContextBufferEnlarge(buf, bufSz);
+    buf[0] = '\0';
+
+    printedChars = vsnprintf(buf, bufSz, s, args);
+    if (printedChars <= 0) {
+      goto out;
+    }
+    if ((size_t) printedChars >= bufSz) {
+      bufSz = (size_t) printedChars + 1;
+      nmeaContextBufferEnlarge(buf, bufSz);
+      printedChars = vsnprintf(buf, bufSz, s, argsCopy);
+    }
+
+    buf[bufSz - 1] = '\0';
+
+    (*f)(buf, (size_t) printedChars);
+
+out:
+    va_end(argsCopy);
+    va_end(args);
+    free(buf);
+  }
 }
diff --git a/lib/pud/nmealib/src/conversions.c b/lib/pud/nmealib/src/conversions.c
deleted file mode 100644 (file)
index dc6b730..0000000
+++ /dev/null
@@ -1,460 +0,0 @@
-/*
- * This file is part of nmealib.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <nmea/conversions.h>
-
-#include <nmea/gmath.h>
-
-#include <assert.h>
-#include <string.h>
-#include <math.h>
-
-/**
- * Determine the number of GSV sentences needed for a number of sats
- *
- * @param sats the number of sats
- * @return the number of GSV sentences needed
- */
-int nmea_gsv_npack(int sats) {
-       int pack_count = sats / NMEA_SATINPACK;
-
-       if ((sats % NMEA_SATINPACK) > 0)
-               pack_count++;
-
-       if (!pack_count)
-               pack_count++;
-
-       return pack_count;
-}
-
-/**
- * Fill nmeaINFO structure from GGA packet structure
- *
- * @param pack a pointer to the packet structure
- * @param info a pointer to the nmeaINFO structure
- */
-void nmea_GPGGA2info(const nmeaGPGGA *pack, nmeaINFO *info) {
-       assert(pack);
-       assert(info);
-
-       info->present |= pack->present;
-       nmea_INFO_set_present(&info->present, SMASK);
-       info->smask |= GPGGA;
-       if (nmea_INFO_is_present(pack->present, UTCTIME)) {
-               info->utc.hour = pack->utc.hour;
-               info->utc.min = pack->utc.min;
-               info->utc.sec = pack->utc.sec;
-               info->utc.hsec = pack->utc.hsec;
-       }
-       if (nmea_INFO_is_present(pack->present, LAT)) {
-               info->lat = ((pack->ns == 'N') ? pack->lat : -pack->lat);
-       }
-       if (nmea_INFO_is_present(pack->present, LON)) {
-               info->lon = ((pack->ew == 'E') ? pack->lon : -pack->lon);
-       }
-       if (nmea_INFO_is_present(pack->present, SIG)) {
-               info->sig = pack->sig;
-       }
-       if (nmea_INFO_is_present(pack->present, SATINUSECOUNT)) {
-               info->satinfo.inuse = pack->satinuse;
-       }
-       if (nmea_INFO_is_present(pack->present, HDOP)) {
-               info->HDOP = pack->HDOP;
-       }
-       if (nmea_INFO_is_present(pack->present, ELV)) {
-               info->elv = pack->elv;
-       }
-       /* ignore diff and diff_units */
-       /* ignore dgps_age and dgps_sid */
-}
-
-/**
- * Convert an nmeaINFO structure into an nmeaGPGGA structure
- *
- * @param info a pointer to the nmeaINFO structure
- * @param pack a pointer to the nmeaGPGGA structure
- */
-void nmea_info2GPGGA(const nmeaINFO *info, nmeaGPGGA *pack) {
-       assert(pack);
-       assert(info);
-
-       nmea_zero_GPGGA(pack);
-
-       pack->present = info->present;
-       nmea_INFO_unset_present(&pack->present, SMASK);
-       if (nmea_INFO_is_present(info->present, UTCTIME)) {
-               pack->utc.hour = info->utc.hour;
-               pack->utc.min = info->utc.min;
-               pack->utc.sec = info->utc.sec;
-               pack->utc.hsec = info->utc.hsec;
-       }
-       if (nmea_INFO_is_present(info->present, LAT)) {
-               pack->lat = fabs(info->lat);
-               pack->ns = ((info->lat > 0) ? 'N' : 'S');
-       }
-       if (nmea_INFO_is_present(info->present, LON)) {
-               pack->lon = fabs(info->lon);
-               pack->ew = ((info->lon > 0) ? 'E' : 'W');
-       }
-       if (nmea_INFO_is_present(info->present, SIG)) {
-               pack->sig = info->sig;
-       }
-       if (nmea_INFO_is_present(info->present, SATINUSECOUNT)) {
-               pack->satinuse = info->satinfo.inuse;
-       }
-       if (nmea_INFO_is_present(info->present, HDOP)) {
-               pack->HDOP = info->HDOP;
-       }
-       if (nmea_INFO_is_present(info->present, ELV)) {
-               pack->elv = info->elv;
-               pack->elv_units = 'M';
-       }
-       /* defaults for (ignored) diff and diff_units */
-       pack->diff = 0;
-       pack->diff_units = 'M';
-       /* defaults for (ignored) dgps_age and dgps_sid */
-       pack->dgps_age = 0;
-       pack->dgps_sid = 0;
-}
-
-/**
- * Fill nmeaINFO structure from GSA packet structure
- *
- * @param pack a pointer to the packet structure
- * @param info a pointer to the nmeaINFO structure
- */
-void nmea_GPGSA2info(const nmeaGPGSA *pack, nmeaINFO *info) {
-       int i = 0;
-
-       assert(pack);
-       assert(info);
-
-       info->present |= pack->present;
-       nmea_INFO_set_present(&info->present, SMASK);
-       info->smask |= GPGSA;
-       if (nmea_INFO_is_present(pack->present, FIX)) {
-               /* fix_mode is ignored */
-               info->fix = pack->fix_type;
-       }
-       if (nmea_INFO_is_present(pack->present, SATINUSE)) {
-               info->satinfo.inuse = 0;
-               for (i = 0; i < NMEA_MAXSAT; i++) {
-                       info->satinfo.in_use[i] = pack->sat_prn[i];
-                       if (pack->sat_prn[i]) {
-                               info->satinfo.inuse++;
-                       }
-               }
-               nmea_INFO_set_present(&info->present, SATINUSECOUNT);
-       }
-       if (nmea_INFO_is_present(pack->present, PDOP)) {
-               info->PDOP = pack->PDOP;
-       }
-       if (nmea_INFO_is_present(pack->present, HDOP)) {
-               info->HDOP = pack->HDOP;
-       }
-       if (nmea_INFO_is_present(pack->present, VDOP)) {
-               info->VDOP = pack->VDOP;
-       }
-}
-
-/**
- * Convert an nmeaINFO structure into an nmeaGPGSA structure
- *
- * @param info a pointer to the nmeaINFO structure
- * @param pack a pointer to the nmeaGPGSA structure
- */
-void nmea_info2GPGSA(const nmeaINFO *info, nmeaGPGSA *pack) {
-       assert(pack);
-       assert(info);
-
-       nmea_zero_GPGSA(pack);
-
-       pack->present = info->present;
-       nmea_INFO_unset_present(&pack->present, SMASK);
-       if (nmea_INFO_is_present(info->present, FIX)) {
-               pack->fix_mode = 'A';
-               pack->fix_type = info->fix;
-       }
-       if (nmea_INFO_is_present(info->present, SATINUSE)) {
-               memcpy(pack->sat_prn, info->satinfo.in_use, sizeof(pack->sat_prn));
-       }
-       if (nmea_INFO_is_present(info->present, PDOP)) {
-               pack->PDOP = info->PDOP;
-       }
-       if (nmea_INFO_is_present(info->present, HDOP)) {
-               pack->HDOP = info->HDOP;
-       }
-       if (nmea_INFO_is_present(info->present, VDOP)) {
-               pack->VDOP = info->VDOP;
-       }
-}
-
-/**
- * Fill nmeaINFO structure from GSV packet structure
- *
- * @param pack a pointer to the packet structure
- * @param info a pointer to the nmeaINFO structure
- */
-void nmea_GPGSV2info(const nmeaGPGSV *pack, nmeaINFO *info) {
-       int pack_index;
-
-       assert(pack);
-       assert(info);
-
-       pack_index = pack->pack_index;
-       if (pack_index < 1)
-               pack_index = 1;
-
-       if (pack_index > pack->pack_count)
-               pack_index = pack->pack_count;
-
-       if ((pack_index * NMEA_SATINPACK) > NMEA_MAXSAT)
-               pack_index = NMEA_NSATPACKS;
-
-       info->present |= pack->present;
-       nmea_INFO_set_present(&info->present, SMASK);
-       info->smask |= GPGSV;
-       if (nmea_INFO_is_present(pack->present, SATINVIEW)) {
-               int sat_index;
-
-               /* index of 1st sat in pack */
-               int sat_offset = (pack_index - 1) * NMEA_SATINPACK;
-               /* the number of sats in this sentence */
-               int sat_count = ((sat_offset + NMEA_SATINPACK) > pack->sat_count) ? (pack->sat_count - sat_offset) : NMEA_SATINPACK;
-
-               for (sat_index = 0; sat_index < sat_count; sat_index++) {
-                       info->satinfo.sat[sat_offset + sat_index].id = pack->sat_data[sat_index].id;
-                       info->satinfo.sat[sat_offset + sat_index].elv = pack->sat_data[sat_index].elv;
-                       info->satinfo.sat[sat_offset + sat_index].azimuth = pack->sat_data[sat_index].azimuth;
-                       info->satinfo.sat[sat_offset + sat_index].sig = pack->sat_data[sat_index].sig;
-               }
-
-               info->satinfo.inview = pack->sat_count;
-       }
-}
-
-/**
- * Convert an nmeaINFO structure into an nmeaGPGSV structure
- *
- * @param info a pointer to the nmeaINFO structure
- * @param pack a pointer to the nmeaGPGSV structure
- * @param pack_idx pack index (zero based)
- */
-void nmea_info2GPGSV(const nmeaINFO *info, nmeaGPGSV *pack, int pack_idx) {
-       assert(pack);
-       assert(info);
-
-       nmea_zero_GPGSV(pack);
-
-       pack->present = info->present;
-       nmea_INFO_unset_present(&pack->present, SMASK);
-       if (nmea_INFO_is_present(info->present, SATINVIEW)) {
-               int sit;
-               int pit;
-               int toskip;
-
-               pack->sat_count = (info->satinfo.inview < NMEA_MAXSAT) ? info->satinfo.inview : NMEA_MAXSAT;
-               pack->pack_count = nmea_gsv_npack(pack->sat_count);
-
-               if (pack_idx >= pack->pack_count)
-                       pack->pack_index = pack->pack_count;
-               else
-                       pack->pack_index = pack_idx + 1;
-
-               /* now skip the first ((pack->pack_index - 1) * NMEA_SATINPACK) in view sats */
-               toskip = ((pack->pack_index - 1) * NMEA_SATINPACK);
-               sit = 0;
-               while ((toskip > 0) && (sit < NMEA_MAXSAT)) {
-                       if (info->satinfo.sat[sit].id) {
-                               toskip--;
-                       }
-                       sit++;
-               }
-
-               for (pit = 0; pit < NMEA_SATINPACK; sit++) {
-                       if (sit < NMEA_MAXSAT) {
-                               if (info->satinfo.sat[sit].id) {
-                                       pack->sat_data[pit] = info->satinfo.sat[sit];
-                                       pit++;
-                               }
-                       } else {
-                               memset(&pack->sat_data[pit], 0, sizeof(pack->sat_data[pit]));
-                               pit++;
-                       }
-               }
-       }
-}
-
-/**
- * Fill nmeaINFO structure from RMC packet structure
- *
- * @param pack a pointer to the packet structure
- * @param info a pointer to the nmeaINFO structure
- */
-void nmea_GPRMC2info(const nmeaGPRMC *pack, nmeaINFO *info) {
-       assert(pack);
-       assert(info);
-
-       info->present |= pack->present;
-       nmea_INFO_set_present(&info->present, SMASK);
-       info->smask |= GPRMC;
-       if (nmea_INFO_is_present(pack->present, UTCDATE)) {
-               info->utc.year = pack->utc.year;
-               info->utc.mon = pack->utc.mon;
-               info->utc.day = pack->utc.day;
-       }
-       if (nmea_INFO_is_present(pack->present, UTCTIME)) {
-               info->utc.hour = pack->utc.hour;
-               info->utc.min = pack->utc.min;
-               info->utc.sec = pack->utc.sec;
-               info->utc.hsec = pack->utc.hsec;
-       }
-       nmea_INFO_set_present(&info->present, SIG);
-       nmea_INFO_set_present(&info->present, FIX);
-       if (pack->status == 'A') {
-               if (info->sig == NMEA_SIG_BAD) {
-                       info->sig = NMEA_SIG_MID;
-               }
-               if (info->fix == NMEA_FIX_BAD) {
-                       info->fix = NMEA_FIX_2D;
-               }
-       } else {
-               info->sig = NMEA_SIG_BAD;
-               info->fix = NMEA_FIX_BAD;
-       }
-       if (nmea_INFO_is_present(pack->present, LAT)) {
-               info->lat = ((pack->ns == 'N') ? pack->lat : -pack->lat);
-       }
-       if (nmea_INFO_is_present(pack->present, LON)) {
-               info->lon = ((pack->ew == 'E') ? pack->lon : -pack->lon);
-       }
-       if (nmea_INFO_is_present(pack->present, SPEED)) {
-               info->speed = pack->speed * NMEA_TUD_KNOTS;
-       }
-       if (nmea_INFO_is_present(pack->present, TRACK)) {
-               info->track = pack->track;
-       }
-       if (nmea_INFO_is_present(pack->present, MAGVAR)) {
-               info->magvar = ((pack->magvar_ew == 'E') ? pack->magvar : -pack->magvar);
-       }
-       /* mode is ignored */
-}
-
-/**
- * Convert an nmeaINFO structure into an nmeaGPRMC structure
- *
- * @param info a pointer to the nmeaINFO structure
- * @param pack a pointer to the nmeaGPRMC structure
- */
-void nmea_info2GPRMC(const nmeaINFO *info, nmeaGPRMC *pack) {
-       assert(pack);
-       assert(info);
-
-       nmea_zero_GPRMC(pack);
-
-       pack->present = info->present;
-       nmea_INFO_unset_present(&pack->present, SMASK);
-       if (nmea_INFO_is_present(info->present, UTCDATE)) {
-               pack->utc.year = info->utc.year;
-               pack->utc.mon = info->utc.mon;
-               pack->utc.day = info->utc.day;
-       }
-       if (nmea_INFO_is_present(info->present, UTCTIME)) {
-               pack->utc.hour = info->utc.hour;
-               pack->utc.min = info->utc.min;
-               pack->utc.sec = info->utc.sec;
-               pack->utc.hsec = info->utc.hsec;
-       }
-       if (nmea_INFO_is_present(info->present, SIG)) {
-               pack->status = ((info->sig != NMEA_SIG_BAD) ? 'A' : 'V');
-       } else {
-               pack->status = 'V';
-       }
-       if (nmea_INFO_is_present(info->present, LAT)) {
-               pack->lat = fabs(info->lat);
-               pack->ns = ((info->lat > 0) ? 'N' : 'S');
-       }
-       if (nmea_INFO_is_present(info->present, LON)) {
-               pack->lon = fabs(info->lon);
-               pack->ew = ((info->lon > 0) ? 'E' : 'W');
-       }
-       if (nmea_INFO_is_present(info->present, SPEED)) {
-               pack->speed = info->speed / NMEA_TUD_KNOTS;
-       }
-       if (nmea_INFO_is_present(info->present, TRACK)) {
-               pack->track = info->track;
-       }
-       if (nmea_INFO_is_present(info->present, MAGVAR)) {
-               pack->magvar = fabs(info->magvar);
-               pack->magvar_ew = ((info->magvar > 0) ? 'E' : 'W');
-       }
-       if (nmea_INFO_is_present(info->present, SIG)) {
-               pack->mode = ((info->sig != NMEA_SIG_BAD) ? 'A' : 'N');
-       } else {
-               pack->mode = 'N';
-       }
-}
-
-/**
- * Fill nmeaINFO structure from VTG packet structure
- *
- * @param pack a pointer to the packet structure
- * @param info a pointer to the nmeaINFO structure
- */
-void nmea_GPVTG2info(const nmeaGPVTG *pack, nmeaINFO *info) {
-       assert(pack);
-       assert(info);
-
-       info->present |= pack->present;
-       nmea_INFO_set_present(&info->present, SMASK);
-       info->smask |= GPVTG;
-       if (nmea_INFO_is_present(pack->present, SPEED)) {
-               info->speed = pack->spk;
-       }
-       if (nmea_INFO_is_present(pack->present, TRACK)) {
-               info->track = pack->track;
-       }
-       if (nmea_INFO_is_present(pack->present, MTRACK)) {
-               info->mtrack = pack->mtrack;
-       }
-}
-
-/**
- * Convert an nmeaINFO structure into an nmeaGPVTG structure
- *
- * @param info a pointer to the nmeaINFO structure
- * @param pack a pointer to the nmeaGPRMC structure
- */
-void nmea_info2GPVTG(const nmeaINFO *info, nmeaGPVTG *pack) {
-       assert(pack);
-       assert(info);
-
-       nmea_zero_GPVTG(pack); /* also sets up units */
-
-       pack->present = info->present;
-       nmea_INFO_unset_present(&pack->present, SMASK);
-       if (nmea_INFO_is_present(info->present, TRACK)) {
-               pack->track = info->track;
-       }
-       if (nmea_INFO_is_present(info->present, MTRACK)) {
-               pack->mtrack = info->mtrack;
-       }
-       if (nmea_INFO_is_present(info->present, SPEED)) {
-               pack->spn = info->speed / NMEA_TUD_KNOTS;
-               pack->spk = info->speed;
-       }
-}
diff --git a/lib/pud/nmealib/src/generate.c b/lib/pud/nmealib/src/generate.c
deleted file mode 100644 (file)
index 27d82c0..0000000
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * This file is part of nmealib.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <nmea/generate.h>
-
-#include <nmea/tok.h>
-#include <nmea/conversions.h>
-
-#include <stdio.h>
-#include <stdbool.h>
-
-/**
- * Generate a GPGGA sentence from an nmeaGPGGA structure
- *
- * @param s a pointer to the buffer to generate the string in
- * @param len the size of the buffer
- * @param pack the structure
- * @return the length of the generated sentence
- */
-int nmea_gen_GPGGA(char *s, const int len, const nmeaGPGGA *pack) {
-       char sTime[16];
-       char sLat[16];
-       char sNs[2];
-       char sLon[16];
-       char sEw[2];
-       char sSig[4];
-       char sSatInUse[4];
-       char sHdop[16];
-       char sElv[16];
-       char sElvUnit[2];
-
-       sTime[0] = 0;
-       sLat[0] = 0;
-       sNs[0] = sNs[1] = 0;
-       sLon[0] = 0;
-       sEw[0] = sEw[1] = 0;
-       sSig[0] = 0;
-       sSatInUse[0] = 0;
-       sHdop[0] = 0;
-       sElv[0] = 0;
-       sElvUnit[0] = sElvUnit[1] = 0;
-
-       if (nmea_INFO_is_present(pack->present, UTCTIME)) {
-               snprintf(&sTime[0], sizeof(sTime), "%02d%02d%02d.%02d", pack->utc.hour, pack->utc.min, pack->utc.sec,
-                               pack->utc.hsec);
-       }
-       if (nmea_INFO_is_present(pack->present, LAT)) {
-               snprintf(&sLat[0], sizeof(sLat), "%09.4f", pack->lat);
-               sNs[0] = pack->ns;
-       }
-       if (nmea_INFO_is_present(pack->present, LON)) {
-               snprintf(&sLon[0], sizeof(sLon), "%010.4f", pack->lon);
-               sEw[0] = pack->ew;
-       }
-       if (nmea_INFO_is_present(pack->present, SIG)) {
-               snprintf(&sSig[0], sizeof(sSig), "%1d", pack->sig);
-       }
-       if (nmea_INFO_is_present(pack->present, SATINUSECOUNT)) {
-               snprintf(&sSatInUse[0], sizeof(sSatInUse), "%02d", pack->satinuse);
-       }
-       if (nmea_INFO_is_present(pack->present, HDOP)) {
-               snprintf(&sHdop[0], sizeof(sHdop), "%03.1f", pack->HDOP);
-       }
-       if (nmea_INFO_is_present(pack->present, ELV)) {
-               snprintf(&sElv[0], sizeof(sElv), "%03.1f", pack->elv);
-               sElvUnit[0] = pack->elv_units;
-       }
-
-       return nmea_printf(s, len, "$GPGGA,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,,,,", &sTime[0], &sLat[0], &sNs[0],
-                       &sLon[0], &sEw[0], &sSig[0], &sSatInUse[0], &sHdop[0], &sElv[0], &sElvUnit[0]);
-}
-
-/**
- * Generate a GPGSA sentence from an nmeaGPGSA structure
- *
- * @param s a pointer to the buffer to generate the string in
- * @param len the size of the buffer
- * @param pack the structure
- * @return the length of the generated sentence
- */
-int nmea_gen_GPGSA(char *s, const int len, const nmeaGPGSA *pack) {
-       int i;
-       char sFixMode[2];
-       char sFixType[2];
-       char sSatPrn[(NMEA_MAXSAT * 4) + 1];
-       char sPdop[16];
-       char sHdop[16];
-       char sVdop[16];
-
-       char * psSatPrn = &sSatPrn[0];
-       int ssSatPrn = sizeof(sSatPrn) - 1;
-
-       bool satinuse = nmea_INFO_is_present(pack->present, SATINUSE);
-
-       sFixMode[0] = sFixMode[1] = 0;
-       sFixType[0] = sFixType[1] = 0;
-       sSatPrn[0] = 0;
-       sPdop[0] = 0;
-       sHdop[0] = 0;
-       sVdop[0] = 0;
-
-       if (nmea_INFO_is_present(pack->present, FIX)) {
-               sFixMode[0] = pack->fix_mode;
-               snprintf(&sFixType[0], sizeof(sFixType), "%1d", pack->fix_type);
-       }
-
-       for (i = 0; i < NMEA_MAXSAT; i++) {
-               if (satinuse && pack->sat_prn[i]) {
-                       int cnt = snprintf(psSatPrn, ssSatPrn, "%d", pack->sat_prn[i]);
-                       if (cnt >= ssSatPrn) {
-                               ssSatPrn = 0;
-                               psSatPrn = &sSatPrn[sizeof(sSatPrn) - 1];
-                               *psSatPrn = '\0';
-                               break;
-                       } else {
-                               ssSatPrn -= cnt;
-                               psSatPrn += cnt;
-                       }
-               }
-               if (i < (NMEA_MAXSAT - 1)) {
-                       *psSatPrn = ',';
-                       psSatPrn++;
-                       ssSatPrn--;
-                       *psSatPrn = '\0';
-               }
-       }
-
-       if (nmea_INFO_is_present(pack->present, PDOP)) {
-               snprintf(&sPdop[0], sizeof(sPdop), "%03.1f", pack->PDOP);
-       }
-       if (nmea_INFO_is_present(pack->present, HDOP)) {
-               snprintf(&sHdop[0], sizeof(sHdop), "%03.1f", pack->HDOP);
-       }
-       if (nmea_INFO_is_present(pack->present, VDOP)) {
-               snprintf(&sVdop[0], sizeof(sVdop), "%03.1f", pack->VDOP);
-       }
-
-       return nmea_printf(s, len, "$GPGSA,%s,%s,%s,%s,%s,%s", &sFixMode[0], &sFixType[0], &sSatPrn[0], &sPdop[0],
-                       &sHdop[0], &sVdop[0]);
-}
-
-/**
- * Generate a GPGSV sentence from an nmeaGPGSV structure
- *
- * @param s a pointer to the buffer to generate the string in
- * @param len the size of the buffer
- * @param pack the structure
- * @return the length of the generated sentence
- */
-int nmea_gen_GPGSV(char *s, const int len, const nmeaGPGSV *pack) {
-       char sCount[2];
-       char sIndex[2];
-       char sSatCount[4];
-       char sSatInfo[(NMEA_SATINPACK * 4) + 1];
-       char * psSatInfo = &sSatInfo[0];
-       int ssSatInfo = sizeof(sSatInfo) - 1;
-       bool satinview = nmea_INFO_is_present(pack->present, SATINVIEW);
-       int i;
-
-       sCount[0] = 0;
-       sIndex[0] = 0;
-       sSatCount[0] = 0;
-       sSatInfo[0] = 0;
-
-       if (satinview) {
-               snprintf(&sCount[0], sizeof(sCount), "%1d", pack->pack_count);
-               snprintf(&sIndex[0], sizeof(sIndex), "%1d", pack->pack_index);
-               snprintf(&sSatCount[0], sizeof(sSatCount), "%02d", pack->sat_count);
-       }
-       for (i = 0; i < NMEA_SATINPACK; i++) {
-               int cnt = 0;
-               if (satinview && pack->sat_data[i].id) {
-                       cnt = snprintf(psSatInfo, ssSatInfo, "%02d,%02d,%03d,%02d", pack->sat_data[i].id, pack->sat_data[i].elv,
-                                       pack->sat_data[i].azimuth, pack->sat_data[i].sig);
-               } else {
-                       cnt = snprintf(psSatInfo, ssSatInfo, ",,,");
-               }
-               if (cnt >= ssSatInfo) {
-                       ssSatInfo = 0;
-                       psSatInfo = &sSatInfo[sizeof(sSatInfo) - 1];
-                       *psSatInfo = '\0';
-                       break;
-               } else {
-                       ssSatInfo -= cnt;
-                       psSatInfo += cnt;
-               }
-               if (i < (NMEA_SATINPACK - 1)) {
-                       *psSatInfo = ',';
-                       psSatInfo++;
-                       ssSatInfo--;
-                       *psSatInfo = '\0';
-               }
-       }
-
-       return nmea_printf(s, len, "$GPGSV,%s,%s,%s,%s", &sCount[0], &sIndex[0], &sSatCount[0], &sSatInfo[0]);
-}
-
-/**
- * Generate a GPRMC sentence from an nmeaGPRMC structure
- *
- * @param s a pointer to the buffer to generate the string in
- * @param len the size of the buffer
- * @param pack the structure
- * @return the length of the generated sentence
- */
-int nmea_gen_GPRMC(char *s, const int len, const nmeaGPRMC *pack) {
-       char sTime[16];
-       char sDate[16];
-       char sLat[16];
-       char sNs[2];
-       char sLon[16];
-       char sEw[2];
-       char sSpeed[16];
-       char sTrack[16];
-       char sMagvar[16];
-       char sMagvar_ew[2];
-
-       sTime[0] = 0;
-       sDate[0] = 0;
-       sLat[0] = 0;
-       sNs[0] = sNs[1] = 0;
-       sLon[0] = 0;
-       sEw[0] = sEw[1] = 0;
-       sSpeed[0] = 0;
-       sTrack[0] = 0;
-       sMagvar[0] = 0;
-       sMagvar_ew[0] = sMagvar_ew[1] = 0;
-
-       if (nmea_INFO_is_present(pack->present, UTCDATE)) {
-               snprintf(&sDate[0], sizeof(sDate), "%02d%02d%02d", pack->utc.day, pack->utc.mon + 1, pack->utc.year - 100);
-       }
-       if (nmea_INFO_is_present(pack->present, UTCTIME)) {
-               snprintf(&sTime[0], sizeof(sTime), "%02d%02d%02d.%02d", pack->utc.hour, pack->utc.min, pack->utc.sec,
-                               pack->utc.hsec);
-       }
-       if (nmea_INFO_is_present(pack->present, LAT)) {
-               snprintf(&sLat[0], sizeof(sLat), "%09.4f", pack->lat);
-               sNs[0] = pack->ns;
-       }
-       if (nmea_INFO_is_present(pack->present, LON)) {
-               snprintf(&sLon[0], sizeof(sLon), "%010.4f", pack->lon);
-               sEw[0] = pack->ew;
-       }
-       if (nmea_INFO_is_present(pack->present, SPEED)) {
-               snprintf(&sSpeed[0], sizeof(sSpeed), "%03.1f", pack->speed);
-       }
-       if (nmea_INFO_is_present(pack->present, TRACK)) {
-               snprintf(&sTrack[0], sizeof(sTrack), "%03.1f", pack->track);
-       }
-       if (nmea_INFO_is_present(pack->present, MAGVAR)) {
-               snprintf(&sMagvar[0], sizeof(sMagvar), "%03.1f", pack->magvar);
-               sMagvar_ew[0] = pack->magvar_ew;
-       }
-
-       return nmea_printf(s, len, "$GPRMC,%s,%c,%s,%s,%s,%s,%s,%s,%s,%s,%s,%c", &sTime[0], pack->status, &sLat[0], &sNs[0],
-                       &sLon[0], &sEw[0], &sSpeed[0], &sTrack[0], &sDate[0], &sMagvar[0], &sMagvar_ew[0], pack->mode);
-}
-
-/**
- * Generate a GPVTG sentence from an nmeaGPVTG structure
- *
- * @param s a pointer to the buffer to generate the string in
- * @param len the size of the buffer
- * @param pack the structure
- * @return the length of the generated sentence
- */
-int nmea_gen_GPVTG(char *s, const int len, const nmeaGPVTG *pack) {
-       char sTrackT[16];
-       char sTrackM[16];
-       char sSpeedN[16];
-       char sSpeedK[16];
-       char sUnitT[2];
-       char sUnitM[2];
-       char sUnitN[2];
-       char sUnitK[2];
-
-       sTrackT[0] = 0;
-       sTrackM[0] = 0;
-       sSpeedN[0] = 0;
-       sSpeedK[0] = 0;
-       sUnitT[0] = sUnitT[1] = 0;
-       sUnitM[0] = sUnitM[1] = 0;
-       sUnitN[0] = sUnitN[1] = 0;
-       sUnitK[0] = sUnitK[1] = 0;
-
-       if (nmea_INFO_is_present(pack->present, TRACK)) {
-               snprintf(&sTrackT[0], sizeof(sTrackT), "%03.1f", pack->track);
-               sUnitT[0] = 'T';
-       }
-       if (nmea_INFO_is_present(pack->present, MTRACK)) {
-               snprintf(&sTrackM[0], sizeof(sTrackM), "%03.1f", pack->mtrack);
-               sUnitM[0] = 'M';
-       }
-       if (nmea_INFO_is_present(pack->present, SPEED)) {
-               snprintf(&sSpeedN[0], sizeof(sSpeedN), "%03.1f", pack->spn);
-               sUnitN[0] = 'N';
-               snprintf(&sSpeedK[0], sizeof(sSpeedK), "%03.1f", pack->spk);
-               sUnitK[0] = 'K';
-       }
-
-       return nmea_printf(s, len, "$GPVTG,%s,%s,%s,%s,%s,%s,%s,%s", &sTrackT[0], &sUnitT[0], &sTrackM[0],
-                       &sUnitM[0], &sSpeedN[0], &sUnitN[0], &sSpeedK[0], &sUnitK[0]);
-}
-
-/**
- * Generate a number of sentences from an nmeaINFO structure.
- *
- * @param s a pointer to the buffer in which to generate the sentences
- * @param len the size of the buffer
- * @param info the structure
- * @param generate_mask the mask of which sentences to generate
- * @return the total length of the generated sentences
- */
-int nmea_generate(char *s, const int len, const nmeaINFO *info, const int generate_mask) {
-       int gen_count = 0;
-       int pack_mask = generate_mask;
-
-       if (!s || !len || !info || !generate_mask)
-               return 0;
-
-       while (pack_mask) {
-               if (pack_mask & GPGGA) {
-                       nmeaGPGGA gga;
-
-                       nmea_info2GPGGA(info, &gga);
-                       gen_count += nmea_gen_GPGGA(s + gen_count, len - gen_count, &gga);
-                       pack_mask &= ~GPGGA;
-               } else if (pack_mask & GPGSA) {
-                       nmeaGPGSA gsa;
-
-                       nmea_info2GPGSA(info, &gsa);
-                       gen_count += nmea_gen_GPGSA(s + gen_count, len - gen_count, &gsa);
-                       pack_mask &= ~GPGSA;
-               } else if (pack_mask & GPGSV) {
-                       nmeaGPGSV gsv;
-                       int gsv_it;
-                       int gsv_count = nmea_gsv_npack(info->satinfo.inview);
-
-                       for (gsv_it = 0; gsv_it < gsv_count && len - gen_count > 0; gsv_it++) {
-                               nmea_info2GPGSV(info, &gsv, gsv_it);
-                               gen_count += nmea_gen_GPGSV(s + gen_count, len - gen_count, &gsv);
-                       }
-                       pack_mask &= ~GPGSV;
-               } else if (pack_mask & GPRMC) {
-                       nmeaGPRMC rmc;
-
-                       nmea_info2GPRMC(info, &rmc);
-                       gen_count += nmea_gen_GPRMC(s + gen_count, len - gen_count, &rmc);
-                       pack_mask &= ~GPRMC;
-               } else if (pack_mask & GPVTG) {
-                       nmeaGPVTG vtg;
-
-                       nmea_info2GPVTG(info, &vtg);
-                       gen_count += nmea_gen_GPVTG(s + gen_count, len - gen_count, &vtg);
-                       pack_mask &= ~GPVTG;
-               } else {
-                       /* no more known sentences to process */
-                       break;
-               }
-
-               if (len - gen_count <= 0)
-                       break;
-       }
-
-       return gen_count;
-}
index 26edd3a..47ae24e 100644 (file)
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <nmea/generator.h>
-
-#include <nmea/context.h>
-#include <nmea/gmath.h>
-#include <nmea/generate.h>
-
-#include "random.h"
+#include <nmealib/generator.h>
 
+#include <nmealib/context.h>
+#include <nmealib/nmath.h>
+#include <nmealib/sentence.h>
+#include <math.h>
 #include <stdlib.h>
 #include <string.h>
-#include <math.h>
 
-/**
- * Initialise the generator
- *
- * @param gen a pointer to the generator
- * @param info a pointer to an nmeaINFO structure to use during generation
- * (present and smask are preserved, other fields are reset before generation starts)
- * @return 1 (true) on success, 0 (false) otherwise
+/*
+ * Forward declarations
  */
-int nmea_gen_init(nmeaGENERATOR *gen, nmeaINFO *info) {
-       int retval = 1;
-       int present = info->present;
-       int smask = info->smask;
-       nmeaGENERATOR *igen = gen;
-
-       nmea_init_random();
-
-       nmea_zero_INFO(info);
-       info->present = present;
-       info->smask = smask;
-       nmea_INFO_set_present(&info->present, SMASK);
-
-       info->lat = NMEA_DEF_LAT;
-       info->lon = NMEA_DEF_LON;
-       nmea_INFO_set_present(&info->present, LAT);
-       nmea_INFO_set_present(&info->present, LON);
-
-       while (retval && igen) {
-               if (igen->init_call)
-                       retval = (*igen->init_call)(igen, info);
-               igen = igen->next;
-       }
-
-       return retval;
-}
 
-/**
- * Loop the generator.
- *
- * @param gen a pointer to the generator
- * @param info a pointer to an nmeaINFO structure to use during generation
- * @return 1 (true) on success, 0 (false) otherwise
- */
-int nmea_gen_loop(nmeaGENERATOR *gen, nmeaINFO *info) {
-       int retVal = 1;
+bool nmeaGeneratorInvokeNoise(NmeaGenerator *gen, NmeaInfo *info);
 
-       if (gen->loop_call)
-               retVal = (*gen->loop_call)(gen, info);
+bool nmeaGeneratorInitStatic(NmeaGenerator *gen, NmeaInfo *info);
+bool nmeaGeneratorInvokeStatic(NmeaGenerator *gen, NmeaInfo *info);
+bool nmeaGeneratorResetStatic(NmeaGenerator *gen, NmeaInfo *info);
 
-       if (retVal && gen->next)
-               retVal = nmea_gen_loop(gen->next, info);
+bool nmeaGeneratorInitRotate(NmeaGenerator *gen, NmeaInfo *info);
+bool nmeaGeneratorInvokeRotate(NmeaGenerator *gen, NmeaInfo *info);
+bool nmeaGeneratorResetRotate(NmeaGenerator *gen, NmeaInfo *info);
 
-       return retVal;
-}
+bool nmeaGeneratorInitRandomMove(NmeaGenerator *gen, NmeaInfo *info);
+bool nmeaGeneratorInvokeRandomMove(NmeaGenerator *gen, NmeaInfo *info);
 
-/**
- * Reset the generator.
- *
- * @param gen a pointer to the generator
- * @param info a pointer to an nmeaINFO structure to use during generation
- * @return 1 (true) on success, 0 (false) otherwise
+/*
+ * NOISE generator
  */
-int nmea_gen_reset(nmeaGENERATOR *gen, nmeaINFO *info) {
-       int RetVal = 1;
-
-       if (gen->reset_call)
-               RetVal = (*gen->reset_call)(gen, info);
-
-       return RetVal;
-}
 
 /**
- * Destroy the generator.
+ * NOISE Generator invoke function
+ *
+ * Does not touch smask nor utc in info.
  *
- * @param gen a pointer to the generator
+ * @param gen The generator
+ * @param info The info structure to use during generation
+ * @return True on success
  */
-void nmea_gen_destroy(nmeaGENERATOR *gen) {
-       if (gen->next) {
-               nmea_gen_destroy(gen->next);
-               gen->next = 0;
-       }
-
-       if (gen->destroy_call)
-               (*gen->destroy_call)(gen);
-
-       free(gen);
+bool nmeaGeneratorInvokeNoise(NmeaGenerator *gen __attribute__ ((unused)), NmeaInfo *info) {
+  size_t i;
+  size_t inUseCount;
+
+  if (!info) {
+    return false;
+  }
+
+  info->sig = (int) lrint(nmeaRandom(NMEALIB_SIG_FIX, NMEALIB_SIG_SENSITIVE));
+  info->fix = (int) lrint(nmeaRandom(NMEALIB_FIX_2D, NMEALIB_FIX_3D));
+  info->pdop = nmeaRandom(0.0, 9.0);
+  info->hdop = nmeaRandom(0.0, 9.0);
+  info->vdop = nmeaRandom(0.0, 9.0);
+  info->latitude = nmeaRandom(0.0, 100.0);
+  info->longitude = nmeaRandom(0.0, 100.0);
+  info->elevation = nmeaRandom(-100.0, 100.0);
+  info->height = nmeaRandom(-100.0, 100.0);
+  info->speed = nmeaRandom(0.0, 100.0);
+  info->track = nmeaRandom(0.0, 360.0);
+  info->mtrack = nmeaRandom(0.0, 360.0);
+  info->magvar = nmeaRandom(0.0, 360.0);
+  info->dgpsAge = nmeaRandom(0.0, 100.0);
+  info->dgpsSid = (unsigned int) lrint(nmeaRandom(0.0, 100.0));
+
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SIG);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_FIX);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_PDOP);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_HDOP);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_VDOP);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_LAT);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_LON);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_ELV);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_HEIGHT);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SPEED);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_TRACK);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_MTRACK);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_MAGVAR);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_DGPSAGE);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_DGPSSID);
+
+  info->satellites.inUseCount = 0;
+  info->satellites.inViewCount = 0;
+
+  for (i = 0; i < NMEALIB_MAX_SATELLITES; i++) {
+    inUseCount = (size_t) labs(lrint(nmeaRandom(0.0, 3.0)));
+
+    info->satellites.inUse[i] = inUseCount ?
+        (unsigned int) i :
+        0;
+    if (inUseCount) {
+      info->satellites.inUseCount++;
+    }
+
+    info->satellites.inView[i].prn = (unsigned int) i;
+    info->satellites.inView[i].elevation = (int) lrint(nmeaRandom(0.0, 90.0));
+    info->satellites.inView[i].azimuth = (unsigned int) lrint(nmeaRandom(0.0, 359.0));
+    info->satellites.inView[i].snr = inUseCount ?
+        (unsigned int) lrint(nmeaRandom(40.0, 99.0)) :
+        (unsigned int) lrint(nmeaRandom(0.0, 40.0));
+    if (info->satellites.inView[i].snr) {
+      info->satellites.inViewCount++;
+    }
+  }
+
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SATINUSECOUNT);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SATINUSE);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SATINVIEWCOUNT);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SATINVIEW);
+
+  return true;
 }
 
-/**
- * Add a generator to the existing ones.
- *
- * @param to the generators to add to
- * @param gen the generator to add
+/*
+ * STATIC generator
  */
-void nmea_gen_add(nmeaGENERATOR *to, nmeaGENERATOR *gen) {
-       nmeaGENERATOR * next = to;
-       while (next->next)
-               next = to->next;
-
-       next->next = gen;
-}
 
 /**
- * Run a new generation loop on the generator
+ * STATIC Generator initialiser function
  *
- * @param s a pointer to the string buffer in which to generate
- * @param len the size of the buffer
- * @param info a pointer to an nmeaINFO structure to use during generation
- * @param gen a pointer to the generator
- * @param generate_mask the smask of sentences to generate
- * @return the total length of the generated sentences
+ * Only touches sig, fix and satinfo in info.
+ *
+ * @param gen The generator
+ * @param info The info structure to use during generation
+ * @return True on success
  */
-int nmea_generate_from(char *s, int len, nmeaINFO *info, nmeaGENERATOR *gen, int generate_mask) {
-       int retval;
+bool nmeaGeneratorInitStatic(NmeaGenerator *gen, NmeaInfo *info) {
+  if (!gen //
+      || !info) {
+    return false;
+  }
 
-       if ((retval = nmea_gen_loop(gen, info)))
-               retval = nmea_generate(s, len, info, generate_mask);
+  info->sig = NMEALIB_SIG_SENSITIVE;
+  info->fix = NMEALIB_FIX_3D;
 
-       return retval;
-}
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SIG);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_FIX);
 
-/*
- * NOISE generator
- */
+  nmeaGeneratorResetStatic(gen, info);
 
-/**
- * NOISE Generator loop function.
- * Does not touch smask and utc in info.
- *
- * @param gen a pointer to the generator
- * @param info a pointer to an nmeaINFO structure to use during generation
- * @return 1 (true) on success, 0 (false) otherwise
- */
-static int nmea_igen_noise_loop(nmeaGENERATOR *gen __attribute__ ((unused)), nmeaINFO *info) {
-       int it;
-       int in_use;
-
-       info->sig = lrint(nmea_random(1, 3));
-       info->fix = lrint(nmea_random(2, 3));
-       info->PDOP = nmea_random(0, 9);
-       info->HDOP = nmea_random(0, 9);
-       info->VDOP = nmea_random(0, 9);
-       info->lat = nmea_random(0, 100);
-       info->lon = nmea_random(0, 100);
-       info->elv = lrint(nmea_random(-100, 100));
-       info->speed = nmea_random(0, 100);
-       info->track = nmea_random(0, 360);
-       info->mtrack = nmea_random(0, 360);
-       info->magvar = nmea_random(0, 360);
-
-       nmea_INFO_set_present(&info->present, SIG);
-       nmea_INFO_set_present(&info->present, FIX);
-       nmea_INFO_set_present(&info->present, PDOP);
-       nmea_INFO_set_present(&info->present, HDOP);
-       nmea_INFO_set_present(&info->present, VDOP);
-       nmea_INFO_set_present(&info->present, LAT);
-       nmea_INFO_set_present(&info->present, LON);
-       nmea_INFO_set_present(&info->present, ELV);
-       nmea_INFO_set_present(&info->present, SPEED);
-       nmea_INFO_set_present(&info->present, TRACK);
-       nmea_INFO_set_present(&info->present, MTRACK);
-       nmea_INFO_set_present(&info->present, MAGVAR);
-
-       info->satinfo.inuse = 0;
-       info->satinfo.inview = 0;
-
-       for (it = 0; it < NMEA_MAXSAT; it++) {
-               in_use = lrint(nmea_random(0, 3));
-               info->satinfo.in_use[it] = in_use ? it : 0;
-               info->satinfo.sat[it].id = it;
-               info->satinfo.sat[it].elv = lrint(nmea_random(0, 90));
-               info->satinfo.sat[it].azimuth = lrint(nmea_random(0, 359));
-               info->satinfo.sat[it].sig = (int) (in_use ? nmea_random(40, 99) : nmea_random(0, 40));
-
-               if (in_use)
-                       info->satinfo.inuse++;
-               if (info->satinfo.sat[it].sig > 0)
-                       info->satinfo.inview++;
-       }
-
-       nmea_INFO_set_present(&info->present, SATINUSECOUNT);
-       nmea_INFO_set_present(&info->present, SATINUSE);
-       nmea_INFO_set_present(&info->present, SATINVIEW);
-
-       return 1;
+  return true;
 }
 
-/*
- * STATIC generator
- */
-
 /**
- * STATIC Generator loop function.
+ * STATIC Generator invoke function
+ *
  * Only touches utc in info.
  *
- * @param gen a pointer to the generator
- * @param info a pointer to an nmeaINFO structure to use during generation
- * @return 1 (true) on success, 0 (false) otherwise
+ * @param gen The generator
+ * @param info The info structure to use during generation
+ * @return True on success
  */
-static int nmea_igen_static_loop(nmeaGENERATOR *gen __attribute__ ((unused)), nmeaINFO *info) {
-       nmea_time_now(&info->utc, &info->present);
-       return 1;
-}
+bool nmeaGeneratorInvokeStatic(NmeaGenerator *gen __attribute__ ((unused)), NmeaInfo *info) {
+  if (!info) {
+    return false;
+  }
 
-/**
- * STATIC Generator reset function.
- * Resets only the satinfo to 4 sats in use and in view.
- *
- * @param gen a pointer to the generator
- * @param info a pointer to an nmeaINFO structure to use during generation
- * @return 1 (true) on success, 0 (false) otherwise
- */
-static int nmea_igen_static_reset(nmeaGENERATOR *gen __attribute__ ((unused)), nmeaINFO *info) {
-       info->satinfo.inuse = 4;
-       info->satinfo.inview = 4;
-
-       info->satinfo.in_use[0] = 1;
-       info->satinfo.sat[0].id = 1;
-       info->satinfo.sat[0].elv = 50;
-       info->satinfo.sat[0].azimuth = 0;
-       info->satinfo.sat[0].sig = 99;
-
-       info->satinfo.in_use[1] = 2;
-       info->satinfo.sat[1].id = 2;
-       info->satinfo.sat[1].elv = 50;
-       info->satinfo.sat[1].azimuth = 90;
-       info->satinfo.sat[1].sig = 99;
-
-       info->satinfo.in_use[2] = 3;
-       info->satinfo.sat[2].id = 3;
-       info->satinfo.sat[2].elv = 50;
-       info->satinfo.sat[2].azimuth = 180;
-       info->satinfo.sat[2].sig = 99;
-
-       info->satinfo.in_use[3] = 4;
-       info->satinfo.sat[3].id = 4;
-       info->satinfo.sat[3].elv = 50;
-       info->satinfo.sat[3].azimuth = 270;
-       info->satinfo.sat[3].sig = 99;
-
-       nmea_INFO_set_present(&info->present, SATINUSECOUNT);
-       nmea_INFO_set_present(&info->present, SATINUSE);
-       nmea_INFO_set_present(&info->present, SATINVIEW);
-
-       return 1;
+  nmeaTimeSet(&info->utc, &info->present, NULL);
+
+  return true;
 }
 
 /**
- * STATIC Generator initialiser function.
- * Only touches sig, fix and satinfo in info.
+ * STATIC Generator reset function
+ *
+ * Only resets the satinfo to 4 sats in inUse and in inView.
  *
- * @param gen a pointer to the generator
- * @param info a pointer to an nmeaINFO structure to use during generation
- * @return 1 (true) on success, 0 (false) otherwise
+ * @param gen The generator
+ * @param info The info structure to use during generation
+ * @return True on success
  */
-static int nmea_igen_static_init(nmeaGENERATOR *gen, nmeaINFO *info) {
-       info->sig = 3;
-       info->fix = 3;
-
-       nmea_INFO_set_present(&info->present, SIG);
-       nmea_INFO_set_present(&info->present, FIX);
-
-       nmea_igen_static_reset(gen, info);
-
-       return 1;
+bool nmeaGeneratorResetStatic(NmeaGenerator *gen __attribute__ ((unused)), NmeaInfo *info) {
+  if (!info) {
+    return false;
+  }
+
+  info->satellites.inUseCount = 4;
+  info->satellites.inViewCount = 4;
+
+  info->satellites.inUse[0] = 1;
+  info->satellites.inView[0].prn = 1;
+  info->satellites.inView[0].elevation = 50;
+  info->satellites.inView[0].azimuth = 0;
+  info->satellites.inView[0].snr = 99;
+
+  info->satellites.inUse[1] = 2;
+  info->satellites.inView[1].prn = 2;
+  info->satellites.inView[1].elevation = 50;
+  info->satellites.inView[1].azimuth = 90;
+  info->satellites.inView[1].snr = 99;
+
+  info->satellites.inUse[2] = 3;
+  info->satellites.inView[2].prn = 3;
+  info->satellites.inView[2].elevation = 50;
+  info->satellites.inView[2].azimuth = 180;
+  info->satellites.inView[2].snr = 99;
+
+  info->satellites.inUse[3] = 4;
+  info->satellites.inView[3].prn = 4;
+  info->satellites.inView[3].elevation = 50;
+  info->satellites.inView[3].azimuth = 270;
+  info->satellites.inView[3].snr = 99;
+
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SATINUSECOUNT);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SATINUSE);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SATINVIEWCOUNT);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SATINVIEW);
+
+  return true;
 }
 
 /*
@@ -298,79 +229,106 @@ static int nmea_igen_static_init(nmeaGENERATOR *gen, nmeaINFO *info) {
  */
 
 /**
- * SAT_ROTATE Generator loop function.
+ * SAT_ROTATE Generator initialiser function
  *
- * @param gen a pointer to the generator
- * @param info a pointer to an nmeaINFO structure to use during generation
- * @return 1 (true) on success, 0 (false) otherwise
+ * Only touches sig, fix and satinfo in info.
+ *
+ * @param gen The generator
+ * @param info The info structure to use during generation
+ * @return True on success
  */
-static int nmea_igen_rotate_loop(nmeaGENERATOR *gen __attribute__ ((unused)), nmeaINFO *info) {
-       int it;
-       int count = info->satinfo.inview;
-       double deg = 360.0 / (count ? count : 1);
-       double srt = (count ? (info->satinfo.sat[0].azimuth) : 0) + 5;
+bool nmeaGeneratorInitRotate(NmeaGenerator *gen, NmeaInfo *info) {
+  if (!gen //
+      || !info) {
+    return false;
+  }
 
-       nmea_time_now(&info->utc, &info->present);
+  info->sig = NMEALIB_SIG_SENSITIVE;
+  info->fix = NMEALIB_FIX_3D;
 
-       for (it = 0; it < count; it++) {
-               info->satinfo.sat[it].azimuth = (int) ((srt >= 360) ? srt - 360 : srt);
-               srt += deg;
-       }
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SIG);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_FIX);
 
-       nmea_INFO_set_present(&info->present, SATINVIEW);
+  nmeaGeneratorResetRotate(gen, info);
 
-       return 1;
+  return true;
 }
 
 /**
- * SAT_ROTATE Generator reset function.
+ * SAT_ROTATE Generator invoke function.
  *
- * @param gen a pointer to the generator
- * @param info a pointer to an nmeaINFO structure to use during generation
- * @return 1 (true) on success, 0 (false) otherwise
+ * @param gen The generator
+ * @param info The info structure to use during generation
+ * @return True on success
  */
-static int nmea_igen_rotate_reset(nmeaGENERATOR *gen __attribute__ ((unused)), nmeaINFO *info) {
-       int it;
-       double deg = 360 / 8;
-       double srt = 0;
-
-       info->satinfo.inuse = 8;
-       info->satinfo.inview = 8;
-
-       for (it = 0; it < info->satinfo.inview; it++) {
-               info->satinfo.in_use[it] = it + 1;
-               info->satinfo.sat[it].id = it + 1;
-               info->satinfo.sat[it].elv = 5;
-               info->satinfo.sat[it].azimuth = (int) srt;
-               info->satinfo.sat[it].sig = 80;
-               srt += deg;
-       }
-
-       nmea_INFO_set_present(&info->present, SATINUSECOUNT);
-       nmea_INFO_set_present(&info->present, SATINUSE);
-       nmea_INFO_set_present(&info->present, SATINVIEW);
-
-       return 1;
+bool nmeaGeneratorInvokeRotate(NmeaGenerator *gen __attribute__ ((unused)), NmeaInfo *info) {
+  size_t i;
+  size_t inViewCount;
+  double degreesPerSatellite;
+  double azimuth;
+
+  if (!info) {
+    return false;
+  }
+
+  inViewCount = info->satellites.inViewCount;
+  degreesPerSatellite = 360.0 / (inViewCount ?
+      (double) inViewCount :
+      1.0);
+  azimuth = (inViewCount ?
+      (info->satellites.inView[0].azimuth) :
+      0) + 5;
+
+  nmeaTimeSet(&info->utc, &info->present, NULL);
+
+  for (i = 0; i < inViewCount; i++) {
+    while (azimuth >= 360.0) {
+      azimuth -= 360.0;
+    }
+    info->satellites.inView[i].azimuth = (unsigned int) azimuth;
+    azimuth += degreesPerSatellite;
+  }
+
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SATINVIEWCOUNT);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SATINVIEW);
+
+  return true;
 }
 
 /**
- * SAT_ROTATE Generator initialiser function.
- * Only touches sig, fix and satinfo in info.
+ * SAT_ROTATE Generator reset function.
  *
- * @param gen a pointer to the generator
- * @param info a pointer to an nmeaINFO structure to use during generation
- * @return 1 (true) on success, 0 (false) otherwise
+ * @param gen The generator
+ * @param info The info structure to use during generation
+ * @return True on success
  */
-static int nmea_igen_rotate_init(nmeaGENERATOR *gen, nmeaINFO *info) {
-       info->sig = 3;
-       info->fix = 3;
-
-       nmea_INFO_set_present(&info->present, SIG);
-       nmea_INFO_set_present(&info->present, FIX);
-
-       nmea_igen_rotate_reset(gen, info);
-
-       return 1;
+bool nmeaGeneratorResetRotate(NmeaGenerator *gen __attribute__ ((unused)), NmeaInfo *info) {
+  size_t i;
+  double degrees = 360 / 8;
+  double azimuth = 0;
+
+  if (!info) {
+    return false;
+  }
+
+  info->satellites.inUseCount = 8;
+  info->satellites.inViewCount = 8;
+
+  for (i = 0; i < info->satellites.inViewCount; i++) {
+    info->satellites.inUse[i] = (unsigned int) (i + 1);
+    info->satellites.inView[i].prn = (unsigned int) (i + 1);
+    info->satellites.inView[i].elevation = 5;
+    info->satellites.inView[i].azimuth = (unsigned int) azimuth;
+    info->satellites.inView[i].snr = 80;
+    azimuth += degrees;
+  }
+
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SATINUSECOUNT);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SATINUSE);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SATINVIEWCOUNT);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SATINVIEW);
+
+  return true;
 }
 
 /*
@@ -378,150 +336,270 @@ static int nmea_igen_rotate_init(nmeaGENERATOR *gen, nmeaINFO *info) {
  */
 
 /**
- * POS_RANDMOVE Generator initialiser function.
+ * POS_RANDMOVE Generator initialiser function
+ *
  * Only touches sig, fix, track, mtrack, magvar and speed in info.
  *
- * @param gen a pointer to the generator
- * @param info a pointer to an nmeaINFO structure to use during generation
- * @return 1 (true) on success, 0 (false) otherwise
+ * @param gen The generator
+ * @param info The info structure to use during generation
+ * @return True on success
  */
-static int nmea_igen_pos_rmove_init(nmeaGENERATOR *gen __attribute__ ((unused)), nmeaINFO *info) {
-       info->sig = 3;
-       info->fix = 3;
-       info->speed = 20;
-       info->track = 0;
-       info->mtrack = 0;
-       info->magvar = 0;
-
-       nmea_INFO_set_present(&info->present, SIG);
-       nmea_INFO_set_present(&info->present, FIX);
-       nmea_INFO_set_present(&info->present, SPEED);
-       nmea_INFO_set_present(&info->present, TRACK);
-       nmea_INFO_set_present(&info->present, MTRACK);
-       nmea_INFO_set_present(&info->present, MAGVAR);
-
-       return 1;
+bool nmeaGeneratorInitRandomMove(NmeaGenerator *gen __attribute__ ((unused)), NmeaInfo *info) {
+  if (!info) {
+    return false;
+  }
+
+  info->sig = NMEALIB_SIG_SENSITIVE;
+  info->fix = NMEALIB_FIX_3D;
+  info->speed = 20.0;
+  info->track = 0.0;
+  info->mtrack = 0.0;
+  info->magvar = 0.0;
+
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SIG);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_FIX);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SPEED);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_TRACK);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_MTRACK);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_MAGVAR);
+
+  return true;
 }
 
 /**
- * POS_RANDMOVE Generator loop function.
+ * POS_RANDMOVE Generator invoke function
  *
- * @param gen a pointer to the generator
- * @param info a pointer to an nmeaINFO structure to use during generation
- * @return 1 (true) on success, 0 (false) otherwise
+ * @param gen The generator
+ * @param info The info structure to use during generation
+ * @return True on success
  */
-static int nmea_igen_pos_rmove_loop(nmeaGENERATOR *gen __attribute__ ((unused)), nmeaINFO *info) {
-       nmeaPOS crd;
-
-       info->track += nmea_random(-10, 10);
-       info->mtrack += nmea_random(-10, 10);
-       info->speed += nmea_random(-2, 3);
-
-       if (info->track < 0) {
-               info->track = 359 + info->track;
-       }
-       if (info->track > 359) {
-               info->track -= 359;
-       }
-       if (info->mtrack < 0) {
-               info->mtrack = 359 + info->mtrack;
-       }
-       if (info->mtrack > 359) {
-               info->mtrack -= 359;
-       }
-
-       if (info->speed > 40)
-               info->speed = 40;
-       if (info->speed < 1)
-               info->speed = 1;
-
-       nmea_info2pos(info, &crd);
-       nmea_move_horz(&crd, &crd, info->track, info->speed / 3600);
-       nmea_pos2info(&crd, info);
-
-       info->magvar = info->track;
-
-       nmea_INFO_set_present(&info->present, LAT);
-       nmea_INFO_set_present(&info->present, LON);
-       nmea_INFO_set_present(&info->present, SPEED);
-       nmea_INFO_set_present(&info->present, TRACK);
-       nmea_INFO_set_present(&info->present, MTRACK);
-       nmea_INFO_set_present(&info->present, MAGVAR);
-
-       return 1;
+bool nmeaGeneratorInvokeRandomMove(NmeaGenerator *gen __attribute__ ((unused)), NmeaInfo *info) {
+  NmeaPosition pos;
+
+  if (!info) {
+    return false;
+  }
+
+  info->track += nmeaRandom(-10.0, 10.0);
+  info->mtrack += nmeaRandom(-10.0, 10.0);
+  info->speed += nmeaRandom(-2.0, 3.0);
+
+  if (info->track < 0.0) {
+    info->track = 360.0 + info->track;
+  }
+  if (info->track >= 360.0) {
+    info->track -= 360.0;
+  }
+
+  if (info->mtrack < 0.0) {
+    info->mtrack = 360.0 + info->mtrack;
+  }
+  if (info->mtrack >= 360.0) {
+    info->mtrack -= 360.0;
+  }
+
+  if (info->speed < 1.0) {
+    info->speed = 1.0;
+  }
+  if (info->speed > 40.0) {
+    info->speed = 40.0;
+  }
+
+
+  nmeaMathInfoToPosition(info, &pos);
+  nmeaMathMoveFlat(&pos, &pos, info->track, info->speed / 3600.0);
+  nmeaMathPositionToInfo(&pos, info);
+
+  info->magvar = info->track;
+
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_LAT);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_LON);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SPEED);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_TRACK);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_MTRACK);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_MAGVAR);
+
+  return true;
 }
 
-/**
- * Create the generator.
- *
- * @param type the type of the generator to create (see nmeaGENTYPE)
- * @param info a pointer to an nmeaINFO structure to use during generation
- * @return the generator
+/*
+ * Generator
  */
-static nmeaGENERATOR * __nmea_create_generator(const int type, nmeaINFO *info) {
-       nmeaGENERATOR *gen = 0;
-
-       switch (type) {
-       case NMEA_GEN_NOISE:
-               if (!(gen = malloc(sizeof(nmeaGENERATOR))))
-                       nmea_error("__nmea_create_generator: insufficient memory!");
-               else {
-                       memset(gen, 0, sizeof(nmeaGENERATOR));
-                       gen->loop_call = &nmea_igen_noise_loop;
-               }
-               break;
-       case NMEA_GEN_STATIC:
-       case NMEA_GEN_SAT_STATIC:
-               if (!(gen = malloc(sizeof(nmeaGENERATOR))))
-                       nmea_error("__nmea_create_generator: insufficient memory!");
-               else {
-                       memset(gen, 0, sizeof(nmeaGENERATOR));
-                       gen->init_call = &nmea_igen_static_init;
-                       gen->loop_call = &nmea_igen_static_loop;
-                       gen->reset_call = &nmea_igen_static_reset;
-               }
-               break;
-       case NMEA_GEN_SAT_ROTATE:
-               if (!(gen = malloc(sizeof(nmeaGENERATOR))))
-                       nmea_error("__nmea_create_generator: insufficient memory!");
-               else {
-                       memset(gen, 0, sizeof(nmeaGENERATOR));
-                       gen->init_call = &nmea_igen_rotate_init;
-                       gen->loop_call = &nmea_igen_rotate_loop;
-                       gen->reset_call = &nmea_igen_rotate_reset;
-               }
-               break;
-       case NMEA_GEN_POS_RANDMOVE:
-               if (!(gen = malloc(sizeof(nmeaGENERATOR))))
-                       nmea_error("__nmea_create_generator: insufficient memory!");
-               else {
-                       memset(gen, 0, sizeof(nmeaGENERATOR));
-                       gen->init_call = &nmea_igen_pos_rmove_init;
-                       gen->loop_call = &nmea_igen_pos_rmove_loop;
-               }
-               break;
-       default:
-               /* case NMEA_GEN_ROTATE: */
-               gen = __nmea_create_generator(NMEA_GEN_SAT_ROTATE, info);
-               nmea_gen_add(gen, __nmea_create_generator(NMEA_GEN_POS_RANDMOVE, info));
-               break;
-       };
-
-       return gen;
+
+bool nmeaGeneratorInit(NmeaGenerator *gen, NmeaInfo *info) {
+  bool r;
+  uint32_t present;
+  uint32_t smask;
+  NmeaGenerator *g;
+
+  if (!gen //
+      || !info) {
+    return false;
+  }
+
+  r = true;
+  present = info->present;
+  smask = info->smask;
+  g = gen;
+
+  nmeaInfoClear(info);
+  nmeaTimeSet(&info->utc, &info->present, NULL);
+
+  info->present = present;
+  info->smask = smask;
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SMASK);
+
+  info->latitude = NMEALIB_LATITUDE_DEFAULT_NDEG;
+  info->longitude = NMEALIB_LONGITUDE_DEFAULT_NDEG;
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_LAT);
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_LON);
+
+  while (r && g) {
+    if (g->init) {
+      r = (*g->init)(g, info);
+    }
+    g = g->next;
+  }
+
+  return r;
 }
 
-/**
- * Create the generator and initialise it.
- *
- * @param type the type of the generator to create (see nmeaGENTYPE)
- * @param info a pointer to an nmeaINFO structure to use during generation
- * @return the generator
- */
-nmeaGENERATOR * nmea_create_generator(const int type, nmeaINFO *info) {
-       nmeaGENERATOR *gen = __nmea_create_generator(type, info);
+NmeaGenerator *nmeaGeneratorCreate(NmeaGeneratorType type, NmeaInfo *info) {
+  NmeaGenerator *gen = 0;
+
+  if (!info) {
+    return NULL;
+  }
+
+  gen = calloc(1, sizeof(NmeaGenerator));
+  if (!gen) {
+    /* can't be covered in a test */
+    return NULL;
+  }
+
+  switch (type) {
+    case NMEALIB_GENERATOR_NOISE:
+      gen->invoke = nmeaGeneratorInvokeNoise;
+      break;
+
+    case NMEALIB_GENERATOR_STATIC:
+    case NMEALIB_GENERATOR_SAT_STATIC:
+      gen->init = nmeaGeneratorInitStatic;
+      gen->invoke = nmeaGeneratorInvokeStatic;
+      gen->reset = nmeaGeneratorResetStatic;
+      break;
+
+    case NMEALIB_GENERATOR_ROTATE:
+    case NMEALIB_GENERATOR_SAT_ROTATE:
+      gen->init = nmeaGeneratorInitRotate;
+      gen->invoke = nmeaGeneratorInvokeRotate;
+      gen->reset = nmeaGeneratorResetRotate;
+
+      if (type == NMEALIB_GENERATOR_ROTATE) {
+        nmeaGeneratorAppend(gen, nmeaGeneratorCreate(NMEALIB_GENERATOR_POS_RANDMOVE, info));
+      }
+      break;
+
+    case NMEALIB_GENERATOR_POS_RANDMOVE:
+      gen->init = nmeaGeneratorInitRandomMove;
+      gen->invoke = nmeaGeneratorInvokeRandomMove;
+      break;
+
+    default:
+      free(gen);
+      return NULL;
+  };
+
+  nmeaGeneratorInit(gen, info);
+
+  return gen;
+}
+
+bool nmeaGeneratorReset(NmeaGenerator *gen, NmeaInfo *info) {
+  bool r = true;
+
+  if (!gen //
+      || !info) {
+    return false;
+  }
+
+  if (gen->reset) {
+    r = (*gen->reset)(gen, info);
+  }
+
+  return r;
+}
+
+void nmeaGeneratorDestroy(NmeaGenerator *gen) {
+  if (!gen) {
+    return;
+  }
+
+  if (gen->next) {
+    nmeaGeneratorDestroy(gen->next);
+    gen->next = NULL;
+  }
+
+  free(gen);
+}
+
+bool nmeaGeneratorInvoke(NmeaGenerator *gen, NmeaInfo *info) {
+  bool r = true;
+
+  if (!gen //
+      || !info) {
+    return false;
+  }
+
+  if (gen->invoke) {
+    r = (*gen->invoke)(gen, info);
+  }
+
+  if (r //
+      && gen->next) {
+    r = nmeaGeneratorInvoke(gen->next, info);
+  }
+
+  return r;
+}
+
+void nmeaGeneratorAppend(NmeaGenerator *to, NmeaGenerator *gen) {
+  NmeaGenerator *next;
+
+  if (!to //
+      || !gen //
+      || (to == gen)) {
+    return;
+  }
+
+  next = to;
+  while (next->next) {
+    next = next->next;
+    if ((next == to) //
+        || (next == gen)) {
+      return;
+    }
+  }
+
+  next->next = gen;
+}
+
+size_t nmeaGeneratorGenerateFrom(NmeaMallocedBuffer *buf, NmeaInfo *info, NmeaGenerator *gen, NmeaSentence mask) {
+  size_t r;
+
+  if (!buf //
+      || (!buf->buffer && buf->bufferSize) //
+      || (buf->buffer && !buf->bufferSize) //
+      || !info //
+      || !gen //
+      || !mask) {
+    return 0;
+  }
 
-       if (gen)
-               nmea_gen_init(gen, info);
+  r = nmeaGeneratorInvoke(gen, info);
+  if (!r) {
+    return 0;
+  }
 
-       return gen;
+  return nmeaSentenceFromInfo(buf, info, mask);
 }
diff --git a/lib/pud/nmealib/src/gmath.c b/lib/pud/nmealib/src/gmath.c
deleted file mode 100644 (file)
index 074b042..0000000
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * This file is part of nmealib.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <nmea/gmath.h>
-
-#include <math.h>
-#include <assert.h>
-
-/**
- * Convert degrees to radians
- *
- * @param val degrees
- * @return radians
- */
-double nmea_degree2radian(const double val) {
-       return (val * NMEA_PI180);
-}
-
-/**
- * Convert radians to degrees
- *
- * @param val radians
- * @return degrees
- */
-double nmea_radian2degree(const double val) {
-       return (val / NMEA_PI180);
-}
-
-/**
- * Convert NDEG (NMEA degrees) to decimal (fractional) degrees
- *
- * @param val NDEG (NMEA degrees)
- * @return decimal (fractional) degrees
- */
-double nmea_ndeg2degree(const double val) {
-       double deg;
-       double fra_part = modf(val / 100.0, &deg);
-       return (deg + ((fra_part * 100.0) / 60.0));
-}
-
-/**
- * Convert decimal (fractional) degrees to NDEG (NMEA degrees)
- *
- * @param val decimal (fractional) degrees
- * @return NDEG (NMEA degrees)
- */
-double nmea_degree2ndeg(const double val) {
-       double deg;
-       double fra_part = modf(val, &deg);
-       return ((deg * 100.0) + (fra_part * 60.0));
-}
-
-/**
- * Convert NDEG (NMEA degrees) to radians
- *
- * @param val NDEG (NMEA degrees)
- * @return radians
- */
-double nmea_ndeg2radian(const double val) {
-       return nmea_degree2radian(nmea_ndeg2degree(val));
-}
-
-/**
- * Convert radians to NDEG (NMEA degrees)
- *
- * @param val radians
- * @return NDEG (NMEA degrees)
- */
-double nmea_radian2ndeg(const double val) {
-       return nmea_degree2ndeg(nmea_radian2degree(val));
-}
-
-/**
- * Calculate PDOP (Position Dilution Of Precision) factor from HDOP and VDOP
- *
- * @param hdop HDOP
- * @param vdop VDOP
- * @return PDOP
- */
-double nmea_calc_pdop(const double hdop, const double vdop) {
-       return sqrt(pow(hdop, 2) + pow(vdop, 2));
-}
-
-/**
- * Convert DOP to meters, using the NMEA_DOP_FACTOR factor
- *
- * @param dop the DOP
- * @return the DOP in meters
- */
-double nmea_dop2meters(const double dop) {
-       return (dop * NMEA_DOP_FACTOR);
-}
-
-/**
- * Convert DOP in meters to plain DOP, using the NMEA_DOP_FACTOR factor
- *
- * @param meters the DOP in meters
- * @return the plain DOP
- */
-double nmea_meters2dop(const double meters) {
-       return (meters / NMEA_DOP_FACTOR);
-}
-
-/**
- * Calculate distance between two points
- *
- * @param from_pos a pointer to the from position (in radians)
- * @param to_pos a pointer to the to position (in radians)
- * @return distance in meters
- */
-double nmea_distance(const nmeaPOS *from_pos, const nmeaPOS *to_pos) {
-       return ((double) NMEA_EARTHRADIUS_M)
-                       * acos(
-                                       sin(to_pos->lat) * sin(from_pos->lat)
-                                                       + cos(to_pos->lat) * cos(from_pos->lat) * cos(to_pos->lon - from_pos->lon));
-}
-
-/**
- * Calculate the distance between two points.
- * This function uses an algorithm for an oblate spheroid earth model.
- * The algorithm is described here: 
- * http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
- *
- * @param from_pos a pointer to the from position (in radians)
- * @param to_pos a pointer to the to position (in radians)
- * @param from_azimuth a pointer to the azimuth at "from" position (in radians) (output)
- * @param to_azimuth a pointer to the azimuth at "to" position (in radians) (output)
- * @return distance in meters
- */
-double nmea_distance_ellipsoid(const nmeaPOS *from_pos, const nmeaPOS *to_pos, double *from_azimuth, double *to_azimuth) {
-       /* All variables */
-       double f, a, b, sqr_a, sqr_b;
-       double L, phi1, phi2, U1, U2, sin_U1, sin_U2, cos_U1, cos_U2;
-       double sigma, sin_sigma, cos_sigma, cos_2_sigmam, sqr_cos_2_sigmam, sqr_cos_alpha, lambda, sin_lambda, cos_lambda,
-                       delta_lambda;
-       int remaining_steps;
-       double sqr_u, A, B, delta_sigma, lambda_prev;
-
-       /* Check input */
-       assert(from_pos != 0);
-       assert(to_pos != 0);
-
-       if ((from_pos->lat == to_pos->lat) && (from_pos->lon == to_pos->lon)) { /* Identical points */
-               if (from_azimuth != 0)
-                       *from_azimuth = 0;
-               if (to_azimuth != 0)
-                       *to_azimuth = 0;
-               return 0;
-       } /* Identical points */
-
-       /* Earth geometry */
-       f = NMEA_EARTH_FLATTENING;
-       a = NMEA_EARTH_SEMIMAJORAXIS_M;
-       b = (1 - f) * a;
-       sqr_a = a * a;
-       sqr_b = b * b;
-
-       /* Calculation */
-       L = to_pos->lon - from_pos->lon;
-       phi1 = from_pos->lat;
-       phi2 = to_pos->lat;
-       U1 = atan((1 - f) * tan(phi1));
-       U2 = atan((1 - f) * tan(phi2));
-       sin_U1 = sin(U1);
-       sin_U2 = sin(U2);
-       cos_U1 = cos(U1);
-       cos_U2 = cos(U2);
-
-       /* Initialize iteration */
-       sigma = 0;
-       sin_sigma = sin(sigma);
-       cos_sigma = cos(sigma);
-       cos_2_sigmam = 0;
-       sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam;
-       sqr_cos_alpha = 0;
-       lambda = L;
-       sin_lambda = sin(lambda);
-       cos_lambda = cos(lambda);
-       lambda_prev = (double) 2.0 * (double) NMEA_PI;
-       delta_lambda = lambda_prev - lambda;
-       if (delta_lambda < 0)
-               delta_lambda = -delta_lambda;
-       remaining_steps = 20;
-
-       while ((delta_lambda > 1e-12) && (remaining_steps > 0)) { /* Iterate */
-               /* Variables */
-               double tmp1, tmp2, sin_alpha, cos_alpha, C;
-
-               /* Calculation */
-               tmp1 = cos_U2 * sin_lambda;
-               tmp2 = cos_U1 * sin_U2 - sin_U1 * cos_U2 * cos_lambda;
-               sin_sigma = sqrt(tmp1 * tmp1 + tmp2 * tmp2);
-               cos_sigma = sin_U1 * sin_U2 + cos_U1 * cos_U2 * cos_lambda;
-               sin_alpha = cos_U1 * cos_U2 * sin_lambda / sin_sigma;
-               cos_alpha = cos(asin(sin_alpha));
-               sqr_cos_alpha = cos_alpha * cos_alpha;
-               cos_2_sigmam = cos_sigma - 2 * sin_U1 * sin_U2 / sqr_cos_alpha;
-               sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam;
-               C = f / 16 * sqr_cos_alpha * (4 + f * (4 - 3 * sqr_cos_alpha));
-               lambda_prev = lambda;
-               sigma = asin(sin_sigma);
-               lambda = L
-                               + (1 - C) * f * sin_alpha
-                                               * (sigma + C * sin_sigma * (cos_2_sigmam + C * cos_sigma * (-1 + 2 * sqr_cos_2_sigmam)));
-               delta_lambda = lambda_prev - lambda;
-               if (delta_lambda < 0)
-                       delta_lambda = -delta_lambda;
-               sin_lambda = sin(lambda);
-               cos_lambda = cos(lambda);
-               remaining_steps--;
-       } /* Iterate */
-
-       /* More calculation  */
-       sqr_u = sqr_cos_alpha * (sqr_a - sqr_b) / sqr_b;
-       A = 1 + sqr_u / 16384 * (4096 + sqr_u * (-768 + sqr_u * (320 - 175 * sqr_u)));
-       B = sqr_u / 1024 * (256 + sqr_u * (-128 + sqr_u * (74 - 47 * sqr_u)));
-       delta_sigma = B * sin_sigma
-                       * (cos_2_sigmam
-                                       + B / 4
-                                                       * (cos_sigma * (-1 + 2 * sqr_cos_2_sigmam)
-                                                                       - B / 6 * cos_2_sigmam * (-3 + 4 * sin_sigma * sin_sigma)
-                                                                                       * (-3 + 4 * sqr_cos_2_sigmam)));
-
-       /* Calculate result */
-       if (from_azimuth != 0) {
-               double tan_alpha_1 = cos_U2 * sin_lambda / (cos_U1 * sin_U2 - sin_U1 * cos_U2 * cos_lambda);
-               *from_azimuth = atan(tan_alpha_1);
-       }
-       if (to_azimuth != 0) {
-               double tan_alpha_2 = cos_U1 * sin_lambda / (-sin_U1 * cos_U2 + cos_U1 * sin_U2 * cos_lambda);
-               *to_azimuth = atan(tan_alpha_2);
-       }
-
-       return b * A * (sigma - delta_sigma);
-}
-
-/**
- * Perform a horizontal move.
- *
- * @param start_pos a pointer to the start position (in radians)
- * @param end_pos a pointer to the end position (in radians) (output)
- * @param azimuth azimuth (in degrees, [0, 359])
- * @param distance the distance (in km)
- * @return 1 (true) on success, 0 (false) on failure
- */
-int nmea_move_horz(const nmeaPOS *start_pos, nmeaPOS *end_pos, double azimuth, double distance) {
-       nmeaPOS p1 = *start_pos;
-       int RetVal = 1;
-
-       distance /= NMEA_EARTHRADIUS_KM; /* Angular distance covered on earth's surface */
-       azimuth = nmea_degree2radian(azimuth);
-
-       end_pos->lat = asin(sin(p1.lat) * cos(distance) + cos(p1.lat) * sin(distance) * cos(azimuth));
-       end_pos->lon = p1.lon
-                       + atan2(sin(azimuth) * sin(distance) * cos(p1.lat), cos(distance) - sin(p1.lat) * sin(end_pos->lat));
-
-       if (isnan(end_pos->lat) || isnan(end_pos->lon)) {
-               end_pos->lat = 0;
-               end_pos->lon = 0;
-               RetVal = 0;
-       }
-
-       return RetVal;
-}
-
-/**
- * Perform a horizontal move.
- * This function uses an algorithm for an oblate spheroid earth model.
- * The algorithm is described here: 
- * http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
- *
- * @param start_pos a pointer to the start position (in radians)
- * @param end_pos a pointer to the end position (in radians) (output)
- * @param azimuth azimuth (in radians)
- * @param distance the distance (in km)
- * @param end_azimuth azimuth at end position (in radians) (output)
- * @return 1 (true) on success, 0 (false) on failure
- */
-int nmea_move_horz_ellipsoid(const nmeaPOS *start_pos, nmeaPOS *end_pos, double azimuth, double distance,
-               double *end_azimuth) {
-       /* Variables */
-       double f, a, b, sqr_a, sqr_b;
-       double phi1, tan_U1, sin_U1, cos_U1, s, alpha1, sin_alpha1, cos_alpha1;
-       double sigma1, sin_alpha, sqr_cos_alpha, sqr_u, A, B;
-       double sigma_initial, sigma, sigma_prev, sin_sigma, cos_sigma, cos_2_sigmam, sqr_cos_2_sigmam, delta_sigma;
-       int remaining_steps;
-       double tmp1, phi2, lambda, C, L;
-
-       /* Check input */
-       assert(start_pos != 0);
-       assert(end_pos != 0);
-
-       if (fabs(distance) < 1e-12) { /* No move */
-               *end_pos = *start_pos;
-               if (end_azimuth != 0)
-                       *end_azimuth = azimuth;
-               return !(isnan(end_pos->lat) || isnan(end_pos->lon));
-       } /* No move */
-
-       /* Earth geometry */
-       f = NMEA_EARTH_FLATTENING;
-       a = NMEA_EARTH_SEMIMAJORAXIS_M;
-       b = (1 - f) * a;
-       sqr_a = a * a;
-       sqr_b = b * b;
-
-       /* Calculation */
-       phi1 = start_pos->lat;
-       tan_U1 = (1 - f) * tan(phi1);
-       cos_U1 = 1 / sqrt(1 + tan_U1 * tan_U1);
-       sin_U1 = tan_U1 * cos_U1;
-       s = distance;
-       alpha1 = azimuth;
-       sin_alpha1 = sin(alpha1);
-       cos_alpha1 = cos(alpha1);
-       sigma1 = atan2(tan_U1, cos_alpha1);
-       sin_alpha = cos_U1 * sin_alpha1;
-       sqr_cos_alpha = 1 - sin_alpha * sin_alpha;
-       sqr_u = sqr_cos_alpha * (sqr_a - sqr_b) / sqr_b;
-       A = 1 + sqr_u / 16384 * (4096 + sqr_u * (-768 + sqr_u * (320 - 175 * sqr_u)));
-       B = sqr_u / 1024 * (256 + sqr_u * (-128 + sqr_u * (74 - 47 * sqr_u)));
-
-       /* Initialize iteration */
-       sigma_initial = s / (b * A);
-       sigma = sigma_initial;
-       sin_sigma = sin(sigma);
-       cos_sigma = cos(sigma);
-       cos_2_sigmam = cos(2 * sigma1 + sigma);
-       sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam;
-       delta_sigma = 0;
-       sigma_prev = 2 * NMEA_PI;
-       remaining_steps = 20;
-
-       while ((fabs(sigma - sigma_prev) > 1e-12) && (remaining_steps > 0)) { /* Iterate */
-               cos_2_sigmam = cos(2 * sigma1 + sigma);
-               sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam;
-               sin_sigma = sin(sigma);
-               cos_sigma = cos(sigma);
-               delta_sigma = B * sin_sigma
-                               * (cos_2_sigmam
-                                               + B / 4
-                                                               * (cos_sigma * (-1 + 2 * sqr_cos_2_sigmam)
-                                                                               - B / 6 * cos_2_sigmam * (-3 + 4 * sin_sigma * sin_sigma)
-                                                                                               * (-3 + 4 * sqr_cos_2_sigmam)));
-               sigma_prev = sigma;
-               sigma = sigma_initial + delta_sigma;
-               remaining_steps--;
-       } /* Iterate */
-
-       /* Calculate result */
-       tmp1 = (sin_U1 * sin_sigma - cos_U1 * cos_sigma * cos_alpha1);
-       phi2 = atan2(sin_U1 * cos_sigma + cos_U1 * sin_sigma * cos_alpha1,
-                       (1 - f) * sqrt(sin_alpha * sin_alpha + tmp1 * tmp1));
-       lambda = atan2(sin_sigma * sin_alpha1, cos_U1 * cos_sigma - sin_U1 * sin_sigma * cos_alpha1);
-       C = f / 16 * sqr_cos_alpha * (4 + f * (4 - 3 * sqr_cos_alpha));
-       L = lambda
-                       - (1 - C) * f * sin_alpha
-                                       * (sigma + C * sin_sigma * (cos_2_sigmam + C * cos_sigma * (-1 + 2 * sqr_cos_2_sigmam)));
-
-       /* Result */
-       end_pos->lon = start_pos->lon + L;
-       end_pos->lat = phi2;
-       if (end_azimuth != 0) {
-               *end_azimuth = atan2(sin_alpha, -sin_U1 * sin_sigma + cos_U1 * cos_sigma * cos_alpha1);
-       }
-       return !(isnan(end_pos->lat) || isnan(end_pos->lon));
-}
-
-/**
- * Convert a position from INFO to radians position
- *
- * @param info a pointer to the INFO position
- * @param pos a pointer to the radians position (output)
- */
-void nmea_info2pos(const nmeaINFO *info, nmeaPOS *pos) {
-       if (nmea_INFO_is_present(info->present, LAT))
-               pos->lat = nmea_ndeg2radian(info->lat);
-       else
-               pos->lat = NMEA_DEF_LAT;
-
-       if (nmea_INFO_is_present(info->present, LON))
-               pos->lon = nmea_ndeg2radian(info->lon);
-       else
-               pos->lon = NMEA_DEF_LON;
-}
-
-/**
- * Convert a radians position to a position from INFO
- *
- * @param pos a pointer to the radians position
- * @param info a pointer to the INFO position (output)
- */
-void nmea_pos2info(const nmeaPOS *pos, nmeaINFO *info) {
-       info->lat = nmea_radian2ndeg(pos->lat);
-       info->lon = nmea_radian2ndeg(pos->lon);
-       nmea_INFO_set_present(&info->present, LAT);
-       nmea_INFO_set_present(&info->present, LON);
-}
diff --git a/lib/pud/nmealib/src/gpgga.c b/lib/pud/nmealib/src/gpgga.c
new file mode 100644 (file)
index 0000000..a93bcd5
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+ * This file is part of nmealib.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <nmealib/gpgga.h>
+
+#include <nmealib/context.h>
+#include <nmealib/sentence.h>
+#include <nmealib/util.h>
+#include <nmealib/validate.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+bool nmeaGPGGAParse(const char *s, const size_t sz, NmeaGPGGA *pack) {
+  size_t tokenCount;
+  char timeBuf[16];
+
+  if (!s //
+      || !sz //
+      || !pack) {
+    return false;
+  }
+
+  nmeaContextTraceBuffer(s, sz);
+
+  /* Clear before parsing, to be able to detect absent fields */
+  *timeBuf = '\0';
+  memset(pack, 0, sizeof(*pack));
+  pack->latitude = NaN;
+  pack->longitude = NaN;
+  pack->sig = INT_MAX;
+  pack->inViewCount = UINT_MAX;
+  pack->hdop = NaN;
+  pack->elevation = NaN;
+  pack->height = NaN;
+  pack->dgpsAge = NaN;
+  pack->dgpsSid = UINT_MAX;
+
+  /* parse */
+  tokenCount = nmeaScanf(s, sz, //
+      "$" NMEALIB_GPGGA_PREFIX ",%16s,%F,%C,%F,%C,%d,%u,%F,%f,%C,%f,%C,%F,%u*", //
+      timeBuf, //
+      &pack->latitude, //
+      &pack->latitudeNS, //
+      &pack->longitude, //
+      &pack->longitudeEW, //
+      &pack->sig, //
+      &pack->inViewCount, //
+      &pack->hdop, //
+      &pack->elevation, //
+      &pack->elevationM, //
+      &pack->height, //
+      &pack->heightM, //
+      &pack->dgpsAge, //
+      &pack->dgpsSid);
+
+  /* see that there are enough tokens */
+  if (tokenCount != 14) {
+    nmeaContextError(NMEALIB_GPGGA_PREFIX " parse error: need 14 tokens, got %lu in '%s'", (long unsigned) tokenCount,
+        s);
+    goto err;
+  }
+
+  /* determine which fields are present and validate them */
+
+  if (*timeBuf) {
+    if (!nmeaTimeParseTime(timeBuf, &pack->utc) //
+        || !nmeaValidateTime(&pack->utc, NMEALIB_GPGGA_PREFIX, s)) {
+      goto err;
+    }
+
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_UTCTIME);
+  } else {
+    memset(&pack->utc, 0, sizeof(pack->utc));
+  }
+
+  if (!isNaN(pack->latitude)) {
+    if (!nmeaValidateNSEW(pack->latitudeNS, true, NMEALIB_GPGGA_PREFIX, s)) {
+      goto err;
+    }
+
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_LAT);
+  } else {
+    pack->latitude = 0.0;
+    pack->latitudeNS = '\0';
+  }
+
+  if (!isNaN(pack->longitude)) {
+    if (!nmeaValidateNSEW(pack->longitudeEW, false, NMEALIB_GPGGA_PREFIX, s)) {
+      goto err;
+    }
+
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_LON);
+  } else {
+    pack->longitude = 0.0;
+    pack->longitudeEW = '\0';
+  }
+
+  if (pack->sig != INT_MAX) {
+    if (!nmeaValidateSignal(pack->sig, NMEALIB_GPGGA_PREFIX, s)) {
+      goto err;
+    }
+
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_SIG);
+  } else {
+    pack->sig = NMEALIB_SIG_INVALID;
+  }
+
+  if (pack->inViewCount != UINT_MAX) {
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_SATINVIEWCOUNT);
+  } else {
+    pack->inViewCount = 0;
+  }
+
+  if (!isNaN(pack->hdop)) {
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_HDOP);
+  } else {
+    pack->hdop = 0.0;
+  }
+
+  if (!isNaN(pack->elevation)) {
+    if (pack->elevationM != 'M') {
+      nmeaContextError(NMEALIB_GPGGA_PREFIX " parse error: invalid elevation unit '%c' in '%s'", pack->elevationM, s);
+      goto err;
+    }
+
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_ELV);
+  } else {
+    pack->elevation = 0.0;
+    pack->elevationM = '\0';
+  }
+
+  if (!isNaN(pack->height)) {
+    if (pack->heightM != 'M') {
+      nmeaContextError(NMEALIB_GPGGA_PREFIX " parse error: invalid height unit '%c' in '%s'", pack->heightM, s);
+      goto err;
+    }
+
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_HEIGHT);
+  } else {
+    pack->height = 0.0;
+    pack->heightM = '\0';
+  }
+
+  if (!isNaN(pack->dgpsAge)) {
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_DGPSAGE);
+  } else {
+    pack->dgpsAge = 0.0;
+  }
+
+  if (pack->dgpsSid != UINT_MAX) {
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_DGPSSID);
+  } else {
+    pack->dgpsSid = 0;
+  }
+
+  return true;
+
+err:
+  memset(pack, 0, sizeof(*pack));
+  pack->sig = NMEALIB_SIG_INVALID;
+  return false;
+}
+
+void nmeaGPGGAToInfo(const NmeaGPGGA *pack, NmeaInfo *info) {
+  if (!pack //
+      || !info) {
+    return;
+  }
+
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SMASK);
+
+  info->smask |= NMEALIB_SENTENCE_GPGGA;
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_UTCTIME)) {
+    info->utc.hour = pack->utc.hour;
+    info->utc.min = pack->utc.min;
+    info->utc.sec = pack->utc.sec;
+    info->utc.hsec = pack->utc.hsec;
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_UTCTIME);
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_LAT)) {
+    info->latitude = ((pack->latitudeNS == 'S') ?
+        -pack->latitude :
+        pack->latitude);
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_LAT);
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_LON)) {
+    info->longitude = ((pack->longitudeEW == 'W') ?
+        -pack->longitude :
+        pack->longitude);
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_LON);
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_SIG)) {
+    info->sig = pack->sig;
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SIG);
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_SATINVIEWCOUNT)) {
+    info->satellites.inViewCount = pack->inViewCount;
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SATINVIEWCOUNT);
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_HDOP)) {
+    info->hdop = pack->hdop;
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_HDOP);
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_ELV)) {
+    info->elevation = pack->elevation;
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_ELV);
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_HEIGHT)) {
+    info->height = pack->height;
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_HEIGHT);
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_DGPSAGE)) {
+    info->dgpsAge = pack->dgpsAge;
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_DGPSAGE);
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_DGPSSID)) {
+    info->dgpsSid = pack->dgpsSid;
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_DGPSSID);
+  }
+}
+
+void nmeaGPGGAFromInfo(const NmeaInfo *info, NmeaGPGGA *pack) {
+  if (!pack //
+      || !info) {
+    return;
+  }
+
+  memset(pack, 0, sizeof(*pack));
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_UTCTIME)) {
+    pack->utc.hour = info->utc.hour;
+    pack->utc.min = info->utc.min;
+    pack->utc.sec = info->utc.sec;
+    pack->utc.hsec = info->utc.hsec;
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_UTCTIME);
+  }
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_LAT)) {
+    pack->latitude = fabs(info->latitude);
+    pack->latitudeNS = ((info->latitude >= 0.0) ?
+        'N' :
+        'S');
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_LAT);
+  }
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_LON)) {
+    pack->longitude = fabs(info->longitude);
+    pack->longitudeEW = ((info->longitude >= 0.0) ?
+        'E' :
+        'W');
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_LON);
+  }
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_SIG)) {
+    pack->sig = info->sig;
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_SIG);
+  } else {
+    pack->sig = NMEALIB_SIG_INVALID;
+  }
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_SATINVIEWCOUNT)) {
+    pack->inViewCount = info->satellites.inViewCount;
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_SATINVIEWCOUNT);
+  }
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_HDOP)) {
+    pack->hdop = info->hdop;
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_HDOP);
+  }
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_ELV)) {
+    pack->elevation = info->elevation;
+    pack->elevationM = 'M';
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_ELV);
+  }
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_HEIGHT)) {
+    pack->height = info->height;
+    pack->heightM = 'M';
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_HEIGHT);
+  }
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_DGPSAGE)) {
+    pack->dgpsAge = info->dgpsAge;
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_DGPSAGE);
+  }
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_DGPSSID)) {
+    pack->dgpsSid = info->dgpsSid;
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_DGPSSID);
+  }
+}
+
+size_t nmeaGPGGAGenerate(char *s, const size_t sz, const NmeaGPGGA *pack) {
+
+#define dst       (&s[chars])
+#define available ((sz <= (size_t) chars) ? 0 : (sz - (size_t) chars))
+
+  int chars = 0;
+
+  if (!s //
+      || !pack) {
+    return 0;
+  }
+
+  chars += snprintf(dst, available, "$" NMEALIB_GPGGA_PREFIX);
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_UTCTIME)) {
+    chars += snprintf(dst, available, //
+        ",%02u%02u%02u.%02u", //
+        pack->utc.hour, //
+        pack->utc.min, //
+        pack->utc.sec, //
+        pack->utc.hsec);
+  } else {
+    chars += snprintf(dst, available, ",");
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_LAT)) {
+    chars += snprintf(dst, available, ",%09.4f", pack->latitude);
+    if (pack->latitudeNS) {
+      chars += snprintf(dst, available, ",%c", pack->latitudeNS);
+    } else {
+      chars += snprintf(dst, available, ",");
+    }
+  } else {
+    chars += snprintf(dst, available, ",,");
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_LON)) {
+    chars += snprintf(dst, available, ",%010.4f", pack->longitude);
+    if (pack->longitudeEW) {
+      chars += snprintf(dst, available, ",%c", pack->longitudeEW);
+    } else {
+      chars += snprintf(dst, available, ",");
+    }
+  } else {
+    chars += snprintf(dst, available, ",,");
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_SIG)) {
+    chars += snprintf(dst, available, ",%d", pack->sig);
+  } else {
+    chars += snprintf(dst, available, ",");
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_SATINVIEWCOUNT)) {
+    chars += snprintf(dst, available, ",%02u", pack->inViewCount);
+  } else {
+    chars += snprintf(dst, available, ",");
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_HDOP)) {
+    chars += snprintf(dst, available, ",%03.1f", pack->hdop);
+  } else {
+    chars += snprintf(dst, available, ",");
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_ELV)) {
+    chars += snprintf(dst, available, ",%03.1f", pack->elevation);
+    if (pack->elevationM) {
+      chars += snprintf(dst, available, ",%c", pack->elevationM);
+    } else {
+      chars += snprintf(dst, available, ",");
+    }
+  } else {
+    chars += snprintf(dst, available, ",,");
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_HEIGHT)) {
+    chars += snprintf(dst, available, ",%03.1f", pack->height);
+    if (pack->heightM) {
+      chars += snprintf(dst, available, ",%c", pack->heightM);
+    } else {
+      chars += snprintf(dst, available, ",");
+    }
+  } else {
+    chars += snprintf(dst, available, ",,");
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_DGPSAGE)) {
+    chars += snprintf(dst, available, ",%03.1f", pack->dgpsAge);
+  } else {
+    chars += snprintf(dst, available, ",");
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_DGPSSID)) {
+    chars += snprintf(dst, available, ",%u", pack->dgpsSid);
+  } else {
+    chars += snprintf(dst, available, ",");
+  }
+
+  /* checksum */
+  chars += nmeaAppendChecksum(s, sz, (size_t) chars);
+
+  return (size_t) chars;
+
+#undef available
+#undef dst
+
+}
diff --git a/lib/pud/nmealib/src/gpgsa.c b/lib/pud/nmealib/src/gpgsa.c
new file mode 100644 (file)
index 0000000..f840452
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * This file is part of nmealib.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <nmealib/gpgsa.h>
+
+#include <nmealib/context.h>
+#include <nmealib/sentence.h>
+#include <nmealib/util.h>
+#include <nmealib/validate.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+bool nmeaGPGSAParse(const char *s, const size_t sz, NmeaGPGSA *pack) {
+  size_t tokenCount;
+  size_t i;
+  bool noPrns;
+
+  if (!s //
+      || !sz //
+      || !pack) {
+    return false;
+  }
+
+  nmeaContextTraceBuffer(s, sz);
+
+  /* Clear before parsing, to be able to detect absent fields */
+  memset(pack, 0, sizeof(*pack));
+  pack->fix = INT_MAX;
+  pack->pdop = NaN;
+  pack->hdop = NaN;
+  pack->vdop = NaN;
+
+  /* parse */
+  tokenCount = nmeaScanf(s, sz, //
+      "$" NMEALIB_GPGSA_PREFIX ",%C,%d," //
+      "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,"//
+      "%F,%F,%F*",//
+      &pack->sig, //
+      &pack->fix, //
+      &pack->prn[0], //
+      &pack->prn[1], //
+      &pack->prn[2], //
+      &pack->prn[3], //
+      &pack->prn[4], //
+      &pack->prn[5], //
+      &pack->prn[6], //
+      &pack->prn[7], //
+      &pack->prn[8], //
+      &pack->prn[9], //
+      &pack->prn[10], //
+      &pack->prn[11], //
+      &pack->pdop, //
+      &pack->hdop, //
+      &pack->vdop);
+
+  /* see that there are enough tokens */
+  if (tokenCount != 17) {
+    nmeaContextError(NMEALIB_GPGSA_PREFIX " parse error: need 17 tokens, got %lu in '%s'", (long unsigned) tokenCount,
+        s);
+    goto err;
+  }
+
+  /* determine which fields are present and validate them */
+
+  if (pack->sig) {
+    if ((pack->sig != 'A') //
+        && (pack->sig != 'M')) {
+      nmeaContextError(NMEALIB_GPGSA_PREFIX " parse error: invalid selection mode '%c' in '%s'", pack->sig, s);
+      goto err;
+    }
+
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_SIG);
+  } else {
+    pack->sig = '\0';
+  }
+
+  if (pack->fix != INT_MAX) {
+    if (!nmeaValidateFix(pack->fix, NMEALIB_GPGSA_PREFIX, s)) {
+      goto err;
+    }
+
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_FIX);
+  } else {
+    pack->fix = NMEALIB_FIX_BAD;
+  }
+
+  noPrns = true;
+  for (i = 0; i < NMEALIB_GPGSA_SATS_IN_SENTENCE; i++) {
+    noPrns = (pack->prn[i] == 0);
+    if (!noPrns) {
+      break;
+    }
+  }
+  if (!noPrns) {
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_SATINUSE);
+  }
+
+  if (!isNaN(pack->pdop)) {
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_PDOP);
+  } else {
+    pack->pdop = 0.0;
+  }
+
+  if (!isNaN(pack->hdop)) {
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_HDOP);
+  } else {
+    pack->hdop = 0.0;
+  }
+
+  if (!isNaN(pack->vdop)) {
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_VDOP);
+  } else {
+    pack->vdop = 0.0;
+  }
+
+  return true;
+
+err:
+  memset(pack, 0, sizeof(*pack));
+  pack->fix = NMEALIB_FIX_BAD;
+  return false;
+}
+
+void nmeaGPGSAToInfo(const NmeaGPGSA *pack, NmeaInfo *info) {
+  if (!pack //
+      || !info) {
+    return;
+  }
+
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SMASK);
+
+  info->smask |= NMEALIB_SENTENCE_GPGSA;
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_SIG) //
+      && (info->sig == NMEALIB_SIG_INVALID)) {
+    if (pack->sig == 'M') {
+      info->sig = NMEALIB_SIG_MANUAL;
+    } else {
+      info->sig = NMEALIB_SIG_FIX;
+    }
+
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SIG);
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_FIX)) {
+    info->fix = pack->fix;
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_FIX);
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_SATINUSE)) {
+    size_t p = 0;
+    size_t i = 0;
+
+    info->satellites.inUseCount = 0;
+    memset(&info->satellites.inUse, 0, sizeof(info->satellites.inUse[0]));
+
+    for (p = 0; (p < NMEALIB_GPGSA_SATS_IN_SENTENCE) && (i < NMEALIB_MAX_SATELLITES); p++) {
+      unsigned int prn = pack->prn[p];
+      if (prn) {
+        info->satellites.inUse[i++] = prn;
+        info->satellites.inUseCount++;
+      }
+    }
+
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SATINUSECOUNT | NMEALIB_PRESENT_SATINUSE);
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_PDOP)) {
+    info->pdop = pack->pdop;
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_PDOP);
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_HDOP)) {
+    info->hdop = pack->hdop;
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_HDOP);
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_VDOP)) {
+    info->vdop = pack->vdop;
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_VDOP);
+  }
+}
+
+void nmeaGPGSAFromInfo(const NmeaInfo *info, NmeaGPGSA *pack) {
+  if (!pack //
+      || !info) {
+    return;
+  }
+
+  memset(pack, 0, sizeof(*pack));
+  pack->fix = NMEALIB_FIX_BAD;
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_SIG)) {
+    if (info->sig == NMEALIB_SIG_MANUAL) {
+      pack->sig = 'M';
+    } else {
+      pack->sig = 'A';
+    }
+
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_SIG);
+  }
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_FIX)) {
+    pack->fix = info->fix;
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_FIX);
+  }
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_SATINUSE)) {
+    size_t i = 0;
+    size_t p = 0;
+
+    for (i = 0; (i < NMEALIB_MAX_SATELLITES) && (p < NMEALIB_GPGSA_SATS_IN_SENTENCE); i++) {
+      unsigned int prn = info->satellites.inUse[i];
+      if (prn) {
+        pack->prn[p++] = prn;
+      }
+    }
+
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_SATINUSE);
+  }
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_PDOP)) {
+    pack->pdop = info->pdop;
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_PDOP);
+  }
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_HDOP)) {
+    pack->hdop = info->hdop;
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_HDOP);
+  }
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_VDOP)) {
+    pack->vdop = info->vdop;
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_VDOP);
+  }
+}
+
+size_t nmeaGPGSAGenerate(char *s, const size_t sz, const NmeaGPGSA *pack) {
+
+#define dst       (&s[chars])
+#define available ((sz <= (size_t) chars) ? 0 : (sz - (size_t) chars))
+
+  int chars = 0;
+  bool satInUse;
+  size_t i;
+
+  if (!s //
+      || !pack) {
+    return 0;
+  }
+
+  chars += snprintf(dst, available, "$" NMEALIB_GPGSA_PREFIX);
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_SIG) //
+      && pack->sig) {
+    chars += snprintf(dst, available, ",%c", pack->sig);
+  } else {
+    chars += snprintf(dst, available, ",");
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_FIX)) {
+    chars += snprintf(dst, available, ",%d", pack->fix);
+  } else {
+    chars += snprintf(dst, available, ",");
+  }
+
+  satInUse = nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_SATINUSE);
+  for (i = 0; i < NMEALIB_GPGSA_SATS_IN_SENTENCE; i++) {
+    unsigned int prn = pack->prn[i];
+    if (satInUse && prn) {
+      chars += snprintf(dst, available, ",%d", prn);
+    } else {
+      chars += snprintf(dst, available, ",");
+    }
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_PDOP)) {
+    chars += snprintf(dst, available, ",%03.1f", pack->pdop);
+  } else {
+    chars += snprintf(dst, available, ",");
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_HDOP)) {
+    chars += snprintf(dst, available, ",%03.1f", pack->hdop);
+  } else {
+    chars += snprintf(dst, available, ",");
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_VDOP)) {
+    chars += snprintf(dst, available, ",%03.1f", pack->vdop);
+  } else {
+    chars += snprintf(dst, available, ",");
+  }
+
+  /* checksum */
+  chars += nmeaAppendChecksum(s, sz, (size_t) chars);
+
+  return (size_t) chars;
+
+#undef available
+#undef dst
+
+}
diff --git a/lib/pud/nmealib/src/gpgsv.c b/lib/pud/nmealib/src/gpgsv.c
new file mode 100644 (file)
index 0000000..1493f47
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * This file is part of nmealib.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <nmealib/gpgsv.h>
+
+#include <nmealib/context.h>
+#include <nmealib/sentence.h>
+#include <nmealib/validate.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+size_t nmeaGPGSVsatellitesToSentencesCount(const size_t satellites) {
+  size_t sentenceCount;
+
+  if (!satellites) {
+    return 1;
+  }
+
+  sentenceCount = satellites >> NMEALIB_GPGSV_MAX_SATS_PER_SENTENCE_SHIFT;
+
+  if (satellites & NMEALIB_GPGSV_MAX_SATS_PER_SENTENCE_MOD_MASK) {
+    sentenceCount++;
+  }
+
+  return sentenceCount;
+}
+
+bool nmeaGPGSVParse(const char *s, const size_t sz, NmeaGPGSV *pack) {
+
+#define sat0 pack->inView[0]
+#define sat1 pack->inView[1]
+#define sat2 pack->inView[2]
+#define sat3 pack->inView[3]
+
+  size_t tokenCount;
+  size_t tokenCountExpected;
+  size_t satellitesInSentence;
+  size_t i;
+
+  if (!pack) {
+    return false;
+  }
+
+  memset(pack, 0, sizeof(*pack));
+
+  if (!s //
+      || !sz) {
+    return false;
+  }
+
+  nmeaContextTraceBuffer(s, sz);
+
+  /* Clear before parsing, to be able to detect absent fields */
+  pack->sentenceCount = UINT_MAX;
+  pack->sentence = UINT_MAX;
+  pack->inViewCount = UINT_MAX;
+
+  /* parse */
+  tokenCount = nmeaScanf(s, sz, //
+      "$" NMEALIB_GPGSV_PREFIX ",%u,%u,%u" //
+      ",%u,%d,%u,%u"//
+      ",%u,%d,%u,%u"//
+      ",%u,%d,%u,%u"//
+      ",%u,%d,%u,%u*",//
+      &pack->sentenceCount, &pack->sentence, &pack->inViewCount, //
+      &sat0.prn, &sat0.elevation, &sat0.azimuth, &sat0.snr, //
+      &sat1.prn, &sat1.elevation, &sat1.azimuth, &sat1.snr, //
+      &sat2.prn, &sat2.elevation, &sat2.azimuth, &sat2.snr, //
+      &sat3.prn, &sat3.elevation, &sat3.azimuth, &sat3.snr);
+
+  if ((pack->sentenceCount == UINT_MAX) //
+      || (pack->sentence == UINT_MAX) //
+      || (pack->inViewCount == UINT_MAX)) {
+    goto err;
+  }
+
+  /* check data */
+
+  if (pack->inViewCount > NMEALIB_MAX_SATELLITES) {
+    nmeaContextError(NMEALIB_GPGSV_PREFIX " parse error: can't handle %u satellites (maximum is %u)", pack->inViewCount,
+    NMEALIB_MAX_SATELLITES);
+    goto err;
+  }
+
+  if (!pack->sentenceCount) {
+    nmeaContextError(NMEALIB_GPGSV_PREFIX " parse error: sentences count %u is invalid in '%s'", pack->sentenceCount,
+        s);
+    goto err;
+  }
+
+  if (pack->sentenceCount > NMEALIB_GPGSV_MAX_SENTENCES) {
+    nmeaContextError(NMEALIB_GPGSV_PREFIX " parse error: can't handle %u sentences (maximum is %u)",
+        pack->sentenceCount,
+        NMEALIB_GPGSV_MAX_SENTENCES);
+    goto err;
+  }
+
+  if (pack->sentenceCount != nmeaGPGSVsatellitesToSentencesCount(pack->inViewCount)) {
+    nmeaContextError(
+        NMEALIB_GPGSV_PREFIX " parse error: sentence count %u does not correspond to satellite count %u in '%s'",
+        pack->sentenceCount, pack->inViewCount, s);
+    goto err;
+  }
+
+  if (!pack->sentence) {
+    nmeaContextError(NMEALIB_GPGSV_PREFIX " parse error: sentence index %u is invalid in '%s'", pack->sentence, s);
+    goto err;
+  }
+
+  if (pack->sentence > pack->sentenceCount) {
+    nmeaContextError(
+        NMEALIB_GPGSV_PREFIX " parse error: sentence index %u is beyond the sentence count (%u) in '%s'",
+        pack->sentence, pack->sentenceCount, s);
+    goto err;
+  }
+
+  /* see that there are enough tokens */
+  if (pack->sentence != pack->sentenceCount) {
+    satellitesInSentence = NMEALIB_GPGSV_MAX_SATS_PER_SENTENCE;
+  } else {
+    satellitesInSentence = pack->inViewCount - ((pack->sentenceCount - 1) << NMEALIB_GPGSV_MAX_SATS_PER_SENTENCE_SHIFT);
+  }
+
+  tokenCountExpected = 3 + (4 * satellitesInSentence); /* 4 fields per satellite */
+
+  if ((tokenCount != tokenCountExpected) //
+      && (tokenCount != 19)) {
+    nmeaContextError(NMEALIB_GPGSV_PREFIX " parse error: need %lu (or 19) tokens, got %lu in '%s'",
+        (long unsigned) tokenCountExpected, (long unsigned) tokenCount, s);
+    goto err;
+  }
+
+  /* validate all satellites */
+  for (i = 0; i < NMEALIB_GPGSV_MAX_SATS_PER_SENTENCE; i++) {
+    NmeaSatellite *sat = &pack->inView[i];
+    if (!nmeaValidateSatellite(sat, NMEALIB_GPGSV_PREFIX, s)) {
+      goto err;
+    }
+  }
+
+  nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_SATINVIEWCOUNT | NMEALIB_PRESENT_SATINVIEW);
+
+  return true;
+
+err:
+  memset(pack, 0, sizeof(*pack));
+  return false;
+
+#undef sat3
+#undef sat2
+#undef sat1
+#undef sat0
+
+}
+
+void nmeaGPGSVToInfo(const NmeaGPGSV *pack, NmeaInfo *info) {
+  if (!pack //
+      || !info) {
+    return;
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_SATINVIEWCOUNT)) {
+    if (pack->inViewCount > NMEALIB_MAX_SATELLITES) {
+      nmeaContextError("%s error: can't handle %u satellites (maximum is %u)", __FUNCTION__, pack->inViewCount,
+      NMEALIB_MAX_SATELLITES);
+      return;
+    }
+
+    info->satellites.inViewCount = pack->inViewCount;
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SATINVIEWCOUNT);
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_SATINVIEW)) {
+    size_t i;
+    size_t p;
+
+    if (!pack->sentenceCount) {
+      nmeaContextError("%s error: sentences count %u is invalid", __FUNCTION__, pack->sentenceCount);
+      return;
+    }
+
+    if (pack->sentenceCount > NMEALIB_GPGSV_MAX_SENTENCES) {
+      nmeaContextError("%s error: can't handle %u sentences (maximum is %u)", __FUNCTION__, pack->sentenceCount,
+      NMEALIB_GPGSV_MAX_SENTENCES);
+      return;
+    }
+
+    if (pack->sentenceCount != nmeaGPGSVsatellitesToSentencesCount(pack->inViewCount)) {
+      nmeaContextError("%s error: sentences count %u does not correspond to satellite count %u", __FUNCTION__,
+          pack->sentenceCount, pack->inViewCount);
+      return;
+    }
+
+    if (!pack->sentence) {
+      nmeaContextError("%s error: sentence index %u is invalid", __FUNCTION__, pack->sentence);
+      return;
+    }
+
+    if (pack->sentence > pack->sentenceCount) {
+      nmeaContextError("%s error: sentence %u is beyond the sentence count (%u)", __FUNCTION__, pack->sentence,
+          pack->sentenceCount);
+      return;
+    }
+
+    if (pack->sentence <= pack->sentenceCount) {
+      /* clear non-present satellites */
+      size_t start = pack->sentence << NMEALIB_GPGSV_MAX_SATS_PER_SENTENCE_SHIFT;
+      size_t clearCount = NMEALIB_MAX_SATELLITES - start;
+      if (clearCount) {
+        memset(&info->satellites.inView[start], 0, clearCount * sizeof(info->satellites.inView[0]));
+      }
+    }
+
+    i = (pack->sentence - 1) << NMEALIB_GPGSV_MAX_SATS_PER_SENTENCE_SHIFT;
+
+    for (p = 0; (p < NMEALIB_GPGSV_MAX_SATS_PER_SENTENCE) && (i < NMEALIB_MAX_SATELLITES); p++, i++) {
+      const NmeaSatellite *src = &pack->inView[p];
+      if (!src->prn) {
+        memset(&info->satellites.inView[i], 0, sizeof(info->satellites.inView[i]));
+      } else {
+        info->satellites.inView[i] = *src;
+      }
+    }
+
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SATINVIEW);
+
+    info->progress.gpgsvInProgress = (pack->sentence != pack->sentenceCount);
+  }
+
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SMASK);
+
+  info->smask |= NMEALIB_SENTENCE_GPGSV;
+}
+
+void nmeaGPGSVFromInfo(const NmeaInfo *info, NmeaGPGSV *pack, size_t sentence) {
+  size_t inViewCount;
+  size_t sentences;
+
+  if (!pack) {
+    return;
+  }
+
+  memset(pack, 0, sizeof(*pack));
+
+  if (!info //
+      || !nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_SATINVIEWCOUNT) //
+      || !info->satellites.inViewCount) {
+    return;
+  }
+
+  inViewCount = info->satellites.inViewCount;
+  sentences = nmeaGPGSVsatellitesToSentencesCount(inViewCount);
+
+  if (sentence >= sentences) {
+    return;
+  }
+
+  pack->inViewCount = (unsigned int) inViewCount;
+  pack->sentenceCount = (unsigned int) sentences;
+  nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_SATINVIEWCOUNT);
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_SATINVIEW)) {
+    size_t i;
+    size_t p;
+
+    pack->sentence = (unsigned int) sentence + 1;
+
+    i = sentence << NMEALIB_GPGSV_MAX_SATS_PER_SENTENCE_SHIFT;
+
+    for (p = 0; (p < NMEALIB_GPGSV_MAX_SATS_PER_SENTENCE) && (i < NMEALIB_MAX_SATELLITES); p++, i++) {
+      pack->inView[p] = info->satellites.inView[i];
+    }
+
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_SATINVIEW);
+  }
+}
+
+size_t nmeaGPGSVGenerate(char *s, const size_t sz, const NmeaGPGSV *pack) {
+
+#define dst       (&s[chars])
+#define available ((sz <= (size_t) chars) ? 0 : (sz - (size_t) chars))
+
+  int chars = 0;
+  size_t inViewCount = 0;
+  size_t sentenceCount = 1;
+  size_t sentence = 1;
+  size_t satellitesInSentence = 0;
+  size_t i = 0;
+
+  if (!s //
+      || !pack) {
+    return 0;
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_SATINVIEWCOUNT)) {
+    inViewCount = pack->inViewCount;
+    sentenceCount = pack->sentenceCount;
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_SATINVIEW)) {
+    sentence = pack->sentence;
+  }
+
+  chars += snprintf(dst, available, //
+      "$" NMEALIB_GPGSV_PREFIX ",%lu,%lu,%lu", //
+      (long unsigned) sentenceCount, //
+      (long unsigned) sentence, //
+      (long unsigned) inViewCount);
+
+  if (pack->sentence != pack->sentenceCount) {
+    satellitesInSentence = NMEALIB_GPGSV_MAX_SATS_PER_SENTENCE;
+  } else {
+    satellitesInSentence = inViewCount - ((pack->sentenceCount - 1) << NMEALIB_GPGSV_MAX_SATS_PER_SENTENCE_SHIFT);
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_SATINVIEW)) {
+    for (i = 0; i < satellitesInSentence; i++) {
+      const NmeaSatellite *sat = &pack->inView[i];
+      if (sat->prn) {
+        chars += snprintf(dst, available, ",%u,%d,%u,%u", sat->prn, sat->elevation, sat->azimuth, sat->snr);
+      } else {
+        chars += snprintf(dst, available, ",,,,");
+      }
+    }
+  }
+
+  /* checksum */
+  chars += nmeaAppendChecksum(s, sz, (size_t) chars);
+
+  return (size_t) chars;
+
+#undef available
+#undef dst
+
+}
diff --git a/lib/pud/nmealib/src/gprmc.c b/lib/pud/nmealib/src/gprmc.c
new file mode 100644 (file)
index 0000000..f1efbc0
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ * This file is part of nmealib.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <nmealib/gprmc.h>
+
+#include <nmealib/context.h>
+#include <nmealib/nmath.h>
+#include <nmealib/sentence.h>
+#include <nmealib/util.h>
+#include <nmealib/validate.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+bool nmeaGPRMCParse(const char *s, const size_t sz, NmeaGPRMC *pack) {
+  size_t tokenCount;
+  char timeBuf[16];
+  char dateBuf[16];
+  bool v23Saved;
+
+  if (!s //
+      || !sz //
+      || !pack) {
+    return false;
+  }
+
+  nmeaContextTraceBuffer(s, sz);
+
+  /* Clear before parsing, to be able to detect absent fields */
+  memset(timeBuf, 0, sizeof(timeBuf));
+  memset(dateBuf, 0, sizeof(dateBuf));
+  memset(pack, 0, sizeof(*pack));
+  pack->latitude = NaN;
+  pack->longitude = NaN;
+  pack->speed = NaN;
+  pack->track = NaN;
+  pack->magvar = NaN;
+
+  /* parse */
+  tokenCount = nmeaScanf(s, sz, //
+      "$GPRMC,%16s,%C,%F,%C,%F,%C,%f,%f,%16s,%F,%C,%C*", //
+      timeBuf, //
+      &pack->sigSelection, //
+      &pack->latitude, //
+      &pack->latitudeNS, //
+      &pack->longitude, //
+      &pack->longitudeEW, //
+      &pack->speed, //
+      &pack->track, //
+      dateBuf, //
+      &pack->magvar, //
+      &pack->magvarEW, //
+      &pack->sig);
+
+  /* see that there are enough tokens */
+  if ((tokenCount != 11) //
+      && (tokenCount != 12)) {
+    nmeaContextError(NMEALIB_GPRMC_PREFIX " parse error: need 11 or 12 tokens, got %lu in '%s'",
+        (long unsigned) tokenCount, s);
+    goto err;
+  }
+
+  pack->v23 = (tokenCount == 12);
+
+  /* determine which fields are present and validate them */
+
+  if (*timeBuf) {
+    if (!nmeaTimeParseTime(timeBuf, &pack->utc) //
+        || !nmeaValidateTime(&pack->utc, NMEALIB_GPRMC_PREFIX, s)) {
+      goto err;
+    }
+
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_UTCTIME);
+  } else {
+    pack->utc.hour = 0;
+    pack->utc.min = 0;
+    pack->utc.sec = 0;
+    pack->utc.hsec = 0;
+  }
+
+  if (pack->sigSelection //
+      && (pack->sigSelection != 'A') //
+      && (pack->sigSelection != 'V')) {
+    nmeaContextError(NMEALIB_GPRMC_PREFIX " parse error: invalid status '%c' in '%s'", pack->sigSelection, s);
+    goto err;
+  }
+
+  if (!pack->v23) {
+    /* no mode */
+    if (pack->sigSelection) {
+      pack->sig = '\0';
+      nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_SIG);
+    } else {
+      pack->sigSelection = '\0';
+      pack->sig = '\0';
+    }
+  } else {
+    /* with mode */
+    if (pack->sigSelection //
+        && pack->sig) {
+      if (!nmeaValidateMode(pack->sig, NMEALIB_GPRMC_PREFIX, s)) {
+        goto err;
+      }
+
+      nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_SIG);
+    } else {
+      pack->sigSelection = '\0';
+      pack->sig = '\0';
+    }
+  }
+
+  if (!isNaN(pack->latitude)) {
+    if (!nmeaValidateNSEW(pack->latitudeNS, true, NMEALIB_GPRMC_PREFIX, s)) {
+      goto err;
+    }
+
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_LAT);
+  } else {
+    pack->latitude = 0.0;
+    pack->latitudeNS = '\0';
+  }
+
+  if (!isNaN(pack->longitude)) {
+    if (!nmeaValidateNSEW(pack->longitudeEW, false, NMEALIB_GPRMC_PREFIX, s)) {
+      goto err;
+    }
+
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_LON);
+  } else {
+    pack->longitude = 0.0;
+    pack->longitudeEW = '\0';
+  }
+
+  if (!isNaN(pack->speed)) {
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_SPEED);
+  } else {
+    pack->speed = 0.0;
+  }
+
+  if (!isNaN(pack->track)) {
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_TRACK);
+  } else {
+    pack->track = 0.0;
+  }
+
+  if (*dateBuf) {
+    if (!nmeaTimeParseDate(dateBuf, &pack->utc) //
+        || !nmeaValidateDate(&pack->utc, NMEALIB_GPRMC_PREFIX, s)) {
+      goto err;
+    }
+
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_UTCDATE);
+  } else {
+    pack->utc.year = 0;
+    pack->utc.mon = 0;
+    pack->utc.day = 0;
+  }
+
+  if (!isNaN(pack->magvar)) {
+    if (!nmeaValidateNSEW(pack->magvarEW, false, NMEALIB_GPRMC_PREFIX, s)) {
+      goto err;
+    }
+
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_MAGVAR);
+  } else {
+    pack->magvar = 0.0;
+    pack->magvarEW = '\0';
+  }
+
+  return true;
+
+err:
+  v23Saved = pack->v23;
+  memset(pack, 0, sizeof(*pack));
+  pack->v23 = v23Saved;
+  return false;
+}
+
+void nmeaGPRMCToInfo(const NmeaGPRMC *pack, NmeaInfo *info) {
+  if (!pack //
+      || !info) {
+    return;
+  }
+
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SMASK);
+
+  info->smask |= NMEALIB_SENTENCE_GPRMC;
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_UTCTIME)) {
+    info->utc.hour = pack->utc.hour;
+    info->utc.min = pack->utc.min;
+    info->utc.sec = pack->utc.sec;
+    info->utc.hsec = pack->utc.hsec;
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_UTCTIME);
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_SIG)) {
+    if (!pack->v23) {
+      /* no mode */
+      if ((pack->sigSelection == 'A') //
+          && (info->sig == NMEALIB_SIG_INVALID)) {
+        info->sig = NMEALIB_SIG_FIX;
+        nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SIG);
+      }
+    } else {
+      /* with mode */
+
+      if (pack->sigSelection != 'A') {
+        info->sig = NMEALIB_SIG_INVALID;
+      } else {
+        info->sig = nmeaInfoModeToSignal(pack->sig);
+      }
+      nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SIG);
+    }
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_LAT)) {
+    info->latitude = ((pack->latitudeNS == 'N') ?
+        pack->latitude :
+        -pack->latitude);
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_LAT);
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_LON)) {
+    info->longitude = ((pack->longitudeEW == 'E') ?
+        pack->longitude :
+        -pack->longitude);
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_LON);
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_SPEED)) {
+    info->speed = pack->speed * NMEALIB_KNOT_TO_KPH;
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SPEED);
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_TRACK)) {
+    info->track = pack->track;
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_TRACK);
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_UTCDATE)) {
+    info->utc.year = pack->utc.year;
+    info->utc.mon = pack->utc.mon;
+    info->utc.day = pack->utc.day;
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_UTCDATE);
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_MAGVAR)) {
+    info->magvar = ((pack->magvarEW == 'E') ?
+        pack->magvar :
+        -pack->magvar);
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_MAGVAR);
+  }
+}
+
+void nmeaGPRMCFromInfo(const NmeaInfo *info, NmeaGPRMC *pack) {
+  if (!pack //
+      || !info) {
+    return;
+  }
+
+  memset(pack, 0, sizeof(*pack));
+
+  pack->v23 = true;
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_UTCTIME)) {
+    pack->utc.hour = info->utc.hour;
+    pack->utc.min = info->utc.min;
+    pack->utc.sec = info->utc.sec;
+    pack->utc.hsec = info->utc.hsec;
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_UTCTIME);
+  }
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_SIG)) {
+    pack->sigSelection = ((info->sig != NMEALIB_SIG_INVALID) ?
+        'A' :
+        'V');
+    pack->sig = nmeaInfoSignalToMode(info->sig);
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_SIG);
+  }
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_LAT)) {
+    pack->latitude = fabs(info->latitude);
+    pack->latitudeNS = ((info->latitude >= 0.0) ?
+        'N' :
+        'S');
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_LAT);
+  }
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_LON)) {
+    pack->longitude = fabs(info->longitude);
+    pack->longitudeEW = ((info->longitude >= 0.0) ?
+        'E' :
+        'W');
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_LON);
+  }
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_SPEED)) {
+    pack->speed = info->speed * NMEALIB_KPH_TO_KNOT;
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_SPEED);
+  }
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_TRACK)) {
+    pack->track = info->track;
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_TRACK);
+  }
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_UTCDATE)) {
+    pack->utc.year = info->utc.year;
+    pack->utc.mon = info->utc.mon;
+    pack->utc.day = info->utc.day;
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_UTCDATE);
+  }
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_MAGVAR)) {
+    pack->magvar = fabs(info->magvar);
+    pack->magvarEW = ((info->magvar >= 0.0) ?
+        'E' :
+        'W');
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_MAGVAR);
+  }
+}
+
+size_t nmeaGPRMCGenerate(char *s, const size_t sz, const NmeaGPRMC *pack) {
+
+#define dst       (&s[chars])
+#define available ((sz <= (size_t) chars) ? 0 : (sz - (size_t) chars))
+
+  int chars = 0;
+
+  if (!s //
+      || !pack) {
+    return 0;
+  }
+
+  chars += snprintf(dst, available, "$" NMEALIB_GPRMC_PREFIX);
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_UTCTIME)) {
+    chars += snprintf(dst, available, //
+        ",%02u%02u%02u.%02u", //
+        pack->utc.hour, //
+        pack->utc.min, //
+        pack->utc.sec, //
+        pack->utc.hsec);
+  } else {
+    chars += snprintf(dst, available, ",");
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_SIG) //
+      && pack->sigSelection) {
+    chars += snprintf(dst, available, ",%c", pack->sigSelection);
+  } else {
+    chars += snprintf(dst, available, ",");
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_LAT)) {
+    chars += snprintf(dst, available, ",%09.4f", pack->latitude);
+    if (pack->latitudeNS) {
+      chars += snprintf(dst, available, ",%c", pack->latitudeNS);
+    } else {
+      chars += snprintf(dst, available, ",");
+    }
+  } else {
+    chars += snprintf(dst, available, ",,");
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_LON)) {
+    chars += snprintf(dst, available, ",%010.4f", pack->longitude);
+    if (pack->longitudeEW) {
+      chars += snprintf(dst, available, ",%c", pack->longitudeEW);
+    } else {
+      chars += snprintf(dst, available, ",");
+    }
+  } else {
+    chars += snprintf(dst, available, ",,");
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_SPEED)) {
+    chars += snprintf(dst, available, ",%03.1f", pack->speed);
+  } else {
+    chars += snprintf(dst, available, ",");
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_TRACK)) {
+    chars += snprintf(dst, available, ",%03.1f", pack->track);
+  } else {
+    chars += snprintf(dst, available, ",");
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_UTCDATE)) {
+    chars += snprintf(dst, available, //
+        ",%02u%02u%02u", //
+        pack->utc.day, //
+        pack->utc.mon, //
+        pack->utc.year % 100);
+  } else {
+    chars += snprintf(dst, available, ",");
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_MAGVAR)) {
+    chars += snprintf(dst, available, ",%03.1f", pack->magvar);
+    if (pack->magvarEW) {
+      chars += snprintf(dst, available, ",%c", pack->magvarEW);
+    } else {
+      chars += snprintf(dst, available, ",");
+    }
+  } else {
+    chars += snprintf(dst, available, ",,");
+  }
+
+  if (pack->v23) {
+    if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_SIG) //
+        && pack->sig) {
+      chars += snprintf(dst, available, ",%c", pack->sig);
+    } else {
+      chars += snprintf(dst, available, ",");
+    }
+  }
+
+  /* checksum */
+  chars += nmeaAppendChecksum(s, sz, (size_t) chars);
+
+  return (size_t) chars;
+
+#undef available
+#undef dst
+
+}
diff --git a/lib/pud/nmealib/src/gpvtg.c b/lib/pud/nmealib/src/gpvtg.c
new file mode 100644 (file)
index 0000000..b778158
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * This file is part of nmealib.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <nmealib/gpvtg.h>
+
+#include <nmealib/context.h>
+#include <nmealib/nmath.h>
+#include <nmealib/sentence.h>
+#include <nmealib/util.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+bool nmeaGPVTGParse(const char *s, const size_t sz, NmeaGPVTG *pack) {
+  size_t tokenCount;
+  bool speedK = false;
+  bool speedN = false;
+
+  if (!s //
+      || !sz //
+      || !pack) {
+    return false;
+  }
+
+  nmeaContextTraceBuffer(s, sz);
+
+  /* Clear before parsing, to be able to detect absent fields */
+  memset(pack, 0, sizeof(*pack));
+  pack->track = NaN;
+  pack->mtrack = NaN;
+  pack->spn = NaN;
+  pack->spk = NaN;
+
+  /* parse */
+  tokenCount = nmeaScanf(s, sz, //
+      "$" NMEALIB_GPVTG_PREFIX ",%f,%C,%f,%C,%f,%C,%f,%C*", //
+      &pack->track, //
+      &pack->trackT, //
+      &pack->mtrack, //
+      &pack->mtrackM, //
+      &pack->spn, //
+      &pack->spnN, //
+      &pack->spk, //
+      &pack->spkK);
+
+  /* see that there are enough tokens */
+  if (tokenCount != 8) {
+    nmeaContextError(NMEALIB_GPVTG_PREFIX " parse error: need 8 tokens, got %lu in '%s'", (long unsigned) tokenCount,
+        s);
+    goto err;
+  }
+
+  /* determine which fields are present and validate them */
+
+  if (!isNaN(pack->track)) {
+    if (pack->trackT != 'T') {
+      nmeaContextError(NMEALIB_GPVTG_PREFIX " parse error: invalid track unit, got '%c', expected 'T'", pack->trackT);
+      goto err;
+    }
+
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_TRACK);
+  } else {
+    pack->track = 0.0;
+    pack->trackT = '\0';
+  }
+
+  if (!isNaN(pack->mtrack)) {
+    if (pack->mtrackM != 'M') {
+      nmeaContextError(NMEALIB_GPVTG_PREFIX " parse error: invalid mtrack unit, got '%c', expected 'M'",
+          pack->mtrackM);
+      goto err;
+    }
+
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_MTRACK);
+  } else {
+    pack->mtrack = 0.0;
+    pack->mtrackM = '\0';
+  }
+
+  if (!isNaN(pack->spn)) {
+    if (pack->spnN != 'N') {
+      nmeaContextError(NMEALIB_GPVTG_PREFIX " parse error: invalid knots speed unit, got '%c', expected 'N'",
+          pack->spnN);
+      goto err;
+    }
+
+    speedN = true;
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_SPEED);
+  } else {
+    pack->spn = 0.0;
+    pack->spnN = '\0';
+  }
+
+  if (!isNaN(pack->spk)) {
+    if (pack->spkK != 'K') {
+      nmeaContextError(NMEALIB_GPVTG_PREFIX " parse error: invalid kph speed unit, got '%c', expected 'K'",
+          pack->spkK);
+      goto err;
+    }
+
+    speedK = true;
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_SPEED);
+  } else {
+    pack->spk = 0.0;
+    pack->spkK = '\0';
+  }
+
+  if (!speedK && speedN) {
+    pack->spk = pack->spn * NMEALIB_KNOT_TO_KPH;
+    pack->spkK = 'K';
+  } else if (speedK && !speedN) {
+    pack->spn = pack->spk * NMEALIB_KPH_TO_KNOT;
+    pack->spnN = 'N';
+  }
+
+  return true;
+
+err:
+  memset(pack, 0, sizeof(*pack));
+  return false;
+}
+
+void nmeaGPVTGToInfo(const NmeaGPVTG *pack, NmeaInfo *info) {
+  if (!pack //
+      || !info) {
+    return;
+  }
+
+  nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SMASK);
+
+  info->smask |= NMEALIB_SENTENCE_GPVTG;
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_TRACK)) {
+    info->track = pack->track;
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_TRACK);
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_MTRACK)) {
+    info->mtrack = pack->mtrack;
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_MTRACK);
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_SPEED)) {
+    if (pack->spkK) {
+      info->speed = pack->spk;
+    } else {
+      info->speed = pack->spn * NMEALIB_KNOT_TO_KPH;
+    }
+    nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SPEED);
+  }
+}
+
+void nmeaGPVTGFromInfo(const NmeaInfo *info, NmeaGPVTG *pack) {
+  if (!pack //
+      || !info) {
+    return;
+  }
+
+  memset(pack, 0, sizeof(*pack));
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_TRACK)) {
+    pack->track = info->track;
+    pack->trackT = 'T';
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_TRACK);
+  }
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_MTRACK)) {
+    pack->mtrack = info->mtrack;
+    pack->mtrackM = 'M';
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_MTRACK);
+  }
+
+  if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_SPEED)) {
+    pack->spn = info->speed * NMEALIB_KPH_TO_KNOT;
+    pack->spnN = 'N';
+    pack->spk = info->speed;
+    pack->spkK = 'K';
+    nmeaInfoSetPresent(&pack->present, NMEALIB_PRESENT_SPEED);
+  }
+}
+
+size_t nmeaGPVTGGenerate(char *s, const size_t sz, const NmeaGPVTG *pack) {
+
+#define dst       (&s[chars])
+#define available ((sz <= (size_t) chars) ? 0 : (sz - (size_t) chars))
+
+  int chars = 0;
+
+  if (!s //
+      || !pack) {
+    return 0;
+  }
+
+  chars += snprintf(dst, available, "$" NMEALIB_GPVTG_PREFIX);
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_TRACK)) {
+    chars += snprintf(dst, available, ",%03.1f", pack->track);
+    if (pack->trackT) {
+      chars += snprintf(dst, available, ",%c", pack->trackT);
+    } else {
+      chars += snprintf(dst, available, ",");
+    }
+  } else {
+    chars += snprintf(dst, available, ",,");
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_MTRACK)) {
+    chars += snprintf(dst, available, ",%03.1f", pack->mtrack);
+    if (pack->mtrackM) {
+      chars += snprintf(dst, available, ",%c", pack->mtrackM);
+    } else {
+      chars += snprintf(dst, available, ",");
+    }
+  } else {
+    chars += snprintf(dst, available, ",,");
+  }
+
+  if (nmeaInfoIsPresentAll(pack->present, NMEALIB_PRESENT_SPEED)) {
+    chars += snprintf(dst, available, ",%03.1f", pack->spn);
+    if (pack->spnN) {
+      chars += snprintf(dst, available, ",%c", pack->spnN);
+    } else {
+      chars += snprintf(dst, available, ",");
+    }
+
+    chars += snprintf(dst, available, ",%03.1f", pack->spk);
+    if (pack->spkK) {
+      chars += snprintf(dst, available, ",%c", pack->spkK);
+    } else {
+      chars += snprintf(dst, available, ",");
+    }
+  } else {
+    chars += snprintf(dst, available, ",,,,");
+  }
+
+  /* checksum */
+  chars += nmeaAppendChecksum(s, sz, (size_t) chars);
+
+  return (size_t) chars;
+
+#undef available
+#undef dst
+
+}
index 56383fc..d4cfeff 100644 (file)
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <nmea/info.h>
+#include <nmealib/info.h>
 
-#include <nmea/sentence.h>
-#include <nmea/gmath.h>
-
-#include <stdbool.h>
-#include <string.h>
+#include <nmealib/nmath.h>
+#include <nmealib/sentence.h>
 #include <math.h>
+#include <stdlib.h>
+#include <string.h>
 #include <time.h>
-#include <sys/time.h>
-#include <assert.h>
 
-/**
- * Reset the time to now
- *
- * @param utc a pointer to the time structure
- * @param present a pointer to a present field. when non-NULL then the UTCDATE
- * and UTCTIME flags are set in it.
- */
-void nmea_time_now(nmeaTIME *utc, uint32_t * present) {
-       struct timeval tp;
-       struct tm tt;
-
-       assert(utc);
-
-       gettimeofday(&tp, NULL );
-       gmtime_r(&tp.tv_sec, &tt);
-
-       utc->year = tt.tm_year;
-       utc->mon = tt.tm_mon;
-       utc->day = tt.tm_mday;
-       utc->hour = tt.tm_hour;
-       utc->min = tt.tm_min;
-       utc->sec = tt.tm_sec;
-       utc->hsec = (tp.tv_usec / 10000);
-       if (present) {
-         nmea_INFO_set_present(present, UTCDATE | UTCTIME);
-       }
-}
+NmeaSignal nmeaInfoModeToSignal(char mode) {
+  switch (mode) {
+    case 'N':
+      return NMEALIB_SIG_INVALID;
 
-/**
- * Clear an info structure.
- * Resets the time to now, sets up the signal as BAD, the FIX as BAD, and
- * signals presence of these fields.
- * Resets all other fields to 0.
- *
- * @param info a pointer to the structure
- */
-void nmea_zero_INFO(nmeaINFO *info) {
-       if (!info) {
-               return;
-       }
+    case 'A':
+      return NMEALIB_SIG_FIX;
+
+    case 'D':
+      return NMEALIB_SIG_DIFFERENTIAL;
+
+    case 'P':
+      return NMEALIB_SIG_SENSITIVE;
+
+    case 'R':
+      return NMEALIB_SIG_RTKIN;
+
+    case 'F':
+      return NMEALIB_SIG_FLOAT_RTK;
 
-       memset(info, 0, sizeof(nmeaINFO));
-       nmea_time_now(&info->utc, &info->present);
+    case 'E':
+      return NMEALIB_SIG_ESTIMATED;
 
-       info->sig = NMEA_SIG_BAD;
-       nmea_INFO_set_present(&info->present, SIG);
+    case 'M':
+      return NMEALIB_SIG_MANUAL;
 
-       info->fix = NMEA_FIX_BAD;
-       nmea_INFO_set_present(&info->present, FIX);
+    case 'S':
+      return NMEALIB_SIG_SIMULATION;
+
+    default:
+      return NMEALIB_SIG_INVALID;
+  }
 }
 
-/**
- * Determine if a nmeaINFO structure has a certain field (from the smask).
- * Note: this is not the complete truth as fields may be absent in certain
- * sentences and are presented as 'present' by this function.
- *
- * @deprecated use nmea_INFO_is_present instead
- * @param smask the smask field
- * @param fieldName use a name from nmeaINFO_FIELD
- * @return a boolean, true when the structure has the requested field
- */
-bool nmea_INFO_is_present_smask(int smask, nmeaINFO_FIELD fieldName) {
-       switch (fieldName) {
-       case SMASK:
-               return true;
+char nmeaInfoSignalToMode(NmeaSignal sig) {
+  switch (sig) {
+    case NMEALIB_SIG_INVALID:
+      return 'N';
 
-       case ELV:
-               return ((smask & GPGGA) != 0);
+    case NMEALIB_SIG_FIX:
+      return 'A';
 
-       case PDOP:
-       case VDOP:
-       case SATINUSE:
-               return ((smask & GPGSA) != 0);
+    case NMEALIB_SIG_DIFFERENTIAL:
+      return 'D';
 
-       case SATINVIEW:
-               return ((smask & GPGSV) != 0);
+    case NMEALIB_SIG_SENSITIVE:
+      return 'P';
 
-       case UTCDATE:
-       case MAGVAR:
-               return ((smask & GPRMC) != 0);
+    case NMEALIB_SIG_RTKIN:
+      return 'R';
 
-       case MTRACK:
-               return ((smask & GPVTG) != 0);
+    case NMEALIB_SIG_FLOAT_RTK:
+      return 'F';
 
-       case SATINUSECOUNT:
-       case HDOP:
-               return ((smask & (GPGGA | GPGSA)) != 0);
+    case NMEALIB_SIG_ESTIMATED:
+      return 'E';
 
-       case UTCTIME:
-       case SIG:
-       case LAT:
-       case LON:
-               return ((smask & (GPGGA | GPRMC)) != 0);
+    case NMEALIB_SIG_MANUAL:
+      return 'M';
 
-       case FIX:
-               return ((smask & (GPGSA | GPRMC)) != 0);
+    case NMEALIB_SIG_SIMULATION:
+      return 'S';
 
-       case SPEED:
-       case TRACK:
-               return ((smask & (GPRMC | GPVTG)) != 0);
+    default:
+      return 'N';
+  }
+}
 
-       default:
-               return false;
-       }
+bool nmeaTimeParseTime(const char *s, NmeaTime *time) {
+  const char *t;
+  size_t sz;
+
+  if (!s //
+      || !time) {
+    return false;
+  }
+
+  t = s;
+  sz = nmeaStringTrim(&t);
+
+  if (nmeaStringContainsWhitespace(t, sz)) {
+    return false;
+  }
+
+  if (sz == 6) { // HHMMSS
+    time->hsec = 0;
+    return (3 == nmeaScanf(t, sz, "%2u%2u%2u", &time->hour, &time->min, &time->sec));
+  }
+
+  if (sz == 8) { // HHMMSS.t
+    if (4 == nmeaScanf(t, sz, "%2u%2u%2u.%u", &time->hour, &time->min, &time->sec, &time->hsec)) {
+      time->hsec *= 10;
+      return true;
+    }
+    return false;
+  }
+
+  if (sz == 9) { // HHMMSS.hh
+    return (4 == nmeaScanf(t, sz, "%2u%2u%2u.%u", &time->hour, &time->min, &time->sec, &time->hsec));
+  }
+
+  if (sz == 10) { // HHMMSS.mmm
+    if ((4 == nmeaScanf(t, sz, "%2u%2u%2u.%u", &time->hour, &time->min, &time->sec, &time->hsec))) {
+      time->hsec = (time->hsec + 5) / 10;
+      return true;
+    }
+    return false;
+  }
+
+  return false;
 }
 
-/**
- * Flag a nmeaINFO structure to contain a certain field
- *
- * @param present a pointer to the presence field
- * @param fieldName use a name from nmeaINFO_FIELD
- */
-void nmea_INFO_set_present(uint32_t * present, nmeaINFO_FIELD fieldName) {
-       assert(present);
-       *present |= fieldName;
+bool nmeaTimeParseDate(const char *s, NmeaTime *date) {
+  size_t sz;
+  const char *d;
+
+  if (!s //
+      || !date) {
+    return false;
+  }
+
+  d = s;
+  sz = nmeaStringTrim(&d);
+
+  if (nmeaStringContainsWhitespace(d, sz)) {
+    return false;
+  }
+
+  if (sz != 6) {
+    return false;
+  }
+
+  if (3 != nmeaScanf(d, sz, "%2u%2u%2u", &date->day, &date->mon, &date->year)) {
+    return false;
+  }
+
+  if (date->year > 90) {
+    date->year += 1900;
+  } else {
+    date->year += 2000;
+  }
+
+  return true;
 }
 
-/**
- * Flag a nmeaINFO structure to NOT contain a certain field
- *
- * @param present a pointer to the presence field
- * @param fieldName use a name from nmeaINFO_FIELD
- */
-void nmea_INFO_unset_present(uint32_t * present, nmeaINFO_FIELD fieldName) {
-       assert(present);
-       *present &= ~fieldName;
+void nmeaTimeSet(NmeaTime *utc, uint32_t *present, struct timeval *timeval) {
+  struct timeval tv;
+  struct tm tm;
+  long usec;
+
+  if (!utc) {
+    return;
+  }
+
+  if (timeval) {
+    gmtime_r(&timeval->tv_sec, &tm);
+    usec = timeval->tv_usec;
+  } else {
+    gettimeofday(&tv, NULL);
+    gmtime_r(&tv.tv_sec, &tm);
+    usec = tv.tv_usec;
+  }
+
+  utc->year = (unsigned int) tm.tm_year + 1900;
+  utc->mon = (unsigned int) tm.tm_mon + 1;
+  utc->day = (unsigned int) tm.tm_mday;
+  utc->hour = (unsigned int) tm.tm_hour;
+  utc->min = (unsigned int) tm.tm_min;
+  utc->sec = (unsigned int) tm.tm_sec;
+  utc->hsec = (unsigned int) (usec / 10000);
+  if (present) {
+    nmeaInfoSetPresent(present, NMEALIB_PRESENT_UTCDATE | NMEALIB_PRESENT_UTCTIME);
+  }
 }
 
-/**
- * Sanitise the NMEA info, make sure that:
- * - sig is in the range [0, 8],
- * - fix is in the range [1, 3],
- * - DOPs are positive,
- * - latitude is in the range [-9000, 9000],
- * - longitude is in the range [-18000, 18000],
- * - speed is positive,
- * - track is in the range [0, 360>.
- * - mtrack is in the range [0, 360>.
- * - magvar is in the range [0, 360>.
- * - satinfo:
- *   - inuse and in_use are consistent (w.r.t. count)
- *   - inview and sat are consistent (w.r.t. count/id)
- *   - in_use and sat are consistent (w.r.t. count/id)
- *   - elv is in the range [0, 90]
- *   - azimuth is in the range [0, 359]
- *   - sig is in the range [0, 99]
- *
- * Time is set to the current time when not present.
- * Fields are reset to their defaults (0) when not signaled as being present.
- *
- * @param nmeaInfo
- * the NMEA info structure to sanitise
- */
-void nmea_INFO_sanitise(nmeaINFO *nmeaInfo) {
-       double lat = 0;
-       double lon = 0;
-       double speed = 0;
-       double track = 0;
-       double mtrack = 0;
-       double magvar = 0;
-       bool latAdjusted = false;
-       bool lonAdjusted = false;
-       bool speedAdjusted = false;
-       bool trackAdjusted = false;
-       bool mtrackAdjusted = false;
-       bool magvarAdjusted = false;
-       nmeaTIME utc;
-       int inuseIndex;
-       int inviewIndex;
-
-       if (!nmeaInfo) {
-               return;
-       }
-
-       nmeaInfo->present = nmeaInfo->present & NMEA_INFO_PRESENT_MASK;
-
-       if (!nmea_INFO_is_present(nmeaInfo->present, SMASK)) {
-               nmeaInfo->smask = 0;
-       }
-
-       if (!nmea_INFO_is_present(nmeaInfo->present, UTCDATE) || !nmea_INFO_is_present(nmeaInfo->present, UTCTIME)) {
-               nmea_time_now(&utc, NULL);
-       }
-
-       if (!nmea_INFO_is_present(nmeaInfo->present, UTCDATE)) {
-               nmeaInfo->utc.year = utc.year;
-               nmeaInfo->utc.mon = utc.mon;
-               nmeaInfo->utc.day = utc.day;
-       }
-
-       if (!nmea_INFO_is_present(nmeaInfo->present, UTCTIME)) {
-               nmeaInfo->utc.hour = utc.hour;
-               nmeaInfo->utc.min = utc.min;
-               nmeaInfo->utc.sec = utc.sec;
-               nmeaInfo->utc.hsec = utc.hsec;
-       }
-
-       if (!nmea_INFO_is_present(nmeaInfo->present, SIG)) {
-               nmeaInfo->sig = NMEA_SIG_BAD;
-       } else {
-               if ((nmeaInfo->sig < NMEA_SIG_BAD) || (nmeaInfo->sig > NMEA_SIG_SIM)) {
-                       nmeaInfo->sig = NMEA_SIG_BAD;
-               }
-       }
-
-       if (!nmea_INFO_is_present(nmeaInfo->present, FIX)) {
-               nmeaInfo->fix = NMEA_FIX_BAD;
-       } else {
-               if ((nmeaInfo->fix < NMEA_FIX_BAD) || (nmeaInfo->fix > NMEA_FIX_3D)) {
-                       nmeaInfo->fix = NMEA_FIX_BAD;
-               }
-       }
-
-       if (!nmea_INFO_is_present(nmeaInfo->present, PDOP)) {
-               nmeaInfo->PDOP = 0;
-       } else {
-               nmeaInfo->PDOP = fabs(nmeaInfo->PDOP);
-       }
-
-       if (!nmea_INFO_is_present(nmeaInfo->present, HDOP)) {
-               nmeaInfo->HDOP = 0;
-       } else {
-               nmeaInfo->HDOP = fabs(nmeaInfo->HDOP);
-       }
-
-       if (!nmea_INFO_is_present(nmeaInfo->present, VDOP)) {
-               nmeaInfo->VDOP = 0;
-       } else {
-               nmeaInfo->VDOP = fabs(nmeaInfo->VDOP);
-       }
-
-       if (!nmea_INFO_is_present(nmeaInfo->present, LAT)) {
-               nmeaInfo->lat = 0;
-       }
-
-       if (!nmea_INFO_is_present(nmeaInfo->present, LON)) {
-               nmeaInfo->lon = 0;
-       }
-
-       if (!nmea_INFO_is_present(nmeaInfo->present, ELV)) {
-               nmeaInfo->elv = 0;
-       }
-
-       if (!nmea_INFO_is_present(nmeaInfo->present, SPEED)) {
-               nmeaInfo->speed = 0;
-       }
-
-       if (!nmea_INFO_is_present(nmeaInfo->present, TRACK)) {
-               nmeaInfo->track = 0;
-       }
-
-       if (!nmea_INFO_is_present(nmeaInfo->present, MTRACK)) {
-               nmeaInfo->mtrack = 0;
-       }
-
-       if (!nmea_INFO_is_present(nmeaInfo->present, MAGVAR)) {
-               nmeaInfo->magvar = 0;
-       }
-
-       if (!nmea_INFO_is_present(nmeaInfo->present, SATINUSECOUNT)) {
-               nmeaInfo->satinfo.inuse = 0;
-       }
-       if (!nmea_INFO_is_present(nmeaInfo->present, SATINUSE)) {
-               memset(&nmeaInfo->satinfo.in_use, 0, sizeof(nmeaInfo->satinfo.in_use));
-       }
-       if (!nmea_INFO_is_present(nmeaInfo->present, SATINVIEW)) {
-               nmeaInfo->satinfo.inview = 0;
-               memset(&nmeaInfo->satinfo.sat, 0, sizeof(nmeaInfo->satinfo.sat));
-       }
-
-       /*
-        * lat
-        */
-
-       lat = nmeaInfo->lat;
-       lon = nmeaInfo->lon;
-
-       /* force lat in [-18000, 18000] */
-       while (lat < -18000.0) {
-               lat += 36000.0;
-               latAdjusted = true;
-       }
-       while (lat > 18000.0) {
-               lat -= 36000.0;
-               latAdjusted = true;
-       }
-
-       /* lat is now in [-18000, 18000] */
-
-       /* force lat from <9000, 18000] in [9000, 0] */
-       if (lat > 9000.0) {
-               lat = 18000.0 - lat;
-               lon += 18000.0;
-               latAdjusted = true;
-               lonAdjusted = true;
-       }
-
-       /* force lat from [-18000, -9000> in [0, -9000] */
-       if (lat < -9000.0) {
-               lat = -18000.0 - lat;
-               lon += 18000.0;
-               latAdjusted = true;
-               lonAdjusted = true;
-       }
-
-       /* lat is now in [-9000, 9000] */
-
-       if (latAdjusted) {
-               nmeaInfo->lat = lat;
-       }
-
-       /*
-        * lon
-        */
-
-       /* force lon in [-18000, 18000] */
-       while (lon < -18000.0) {
-               lon += 36000.0;
-               lonAdjusted = true;
-       }
-       while (lon > 18000.0) {
-               lon -= 36000.0;
-               lonAdjusted = true;
-       }
-
-       /* lon is now in [-18000, 18000] */
-
-       if (lonAdjusted) {
-               nmeaInfo->lon = lon;
-       }
-
-       /*
-        * speed
-        */
-
-       speed = nmeaInfo->speed;
-       track = nmeaInfo->track;
-       mtrack = nmeaInfo->mtrack;
-
-       if (speed < 0.0) {
-               speed = -speed;
-               track += 180.0;
-               mtrack += 180.0;
-               speedAdjusted = true;
-               trackAdjusted = true;
-               mtrackAdjusted = true;
-       }
-
-       /* speed is now in [0, max> */
-
-       if (speedAdjusted) {
-               nmeaInfo->speed = speed;
-       }
-
-       /*
-        * track
-        */
-
-       /* force track in [0, 360> */
-       while (track < 0.0) {
-               track += 360.0;
-               trackAdjusted = true;
-       }
-       while (track >= 360.0) {
-               track -= 360.0;
-               trackAdjusted = true;
-       }
-
-       /* track is now in [0, 360> */
-
-       if (trackAdjusted) {
-               nmeaInfo->track = track;
-       }
-
-       /*
-        * mtrack
-        */
-
-       /* force mtrack in [0, 360> */
-       while (mtrack < 0.0) {
-               mtrack += 360.0;
-               mtrackAdjusted = true;
-       }
-       while (mtrack >= 360.0) {
-               mtrack -= 360.0;
-               mtrackAdjusted = true;
-       }
-
-       /* mtrack is now in [0, 360> */
-
-       if (mtrackAdjusted) {
-               nmeaInfo->mtrack = mtrack;
-       }
-
-       /*
-        * magvar
-        */
-
-       magvar = nmeaInfo->magvar;
-
-       /* force magvar in [0, 360> */
-       while (magvar < 0.0) {
-               magvar += 360.0;
-               magvarAdjusted = true;
-       }
-       while (magvar >= 360.0) {
-               magvar -= 360.0;
-               magvarAdjusted = true;
-       }
-
-       /* magvar is now in [0, 360> */
-
-       if (magvarAdjusted) {
-               nmeaInfo->magvar = magvar;
-       }
-
-       /*
-        * satinfo
-        */
-
-       nmeaInfo->satinfo.inuse = 0;
-       for (inuseIndex = 0; inuseIndex < NMEA_MAXSAT; inuseIndex++) {
-               if (nmeaInfo->satinfo.in_use[inuseIndex])
-                       nmeaInfo->satinfo.inuse++;
-       }
-
-       nmeaInfo->satinfo.inview = 0;
-       for (inviewIndex = 0; inviewIndex < NMEA_MAXSAT; inviewIndex++) {
-               if (nmeaInfo->satinfo.sat[inviewIndex].id) {
-                       nmeaInfo->satinfo.inview++;
-
-                       /* force elv in [-180, 180] */
-                       while (nmeaInfo->satinfo.sat[inviewIndex].elv < -180) {
-                               nmeaInfo->satinfo.sat[inviewIndex].elv += 360;
-                       }
-                       while (nmeaInfo->satinfo.sat[inviewIndex].elv > 180) {
-                               nmeaInfo->satinfo.sat[inviewIndex].elv -= 360;
-                       }
-
-                       /* elv is now in [-180, 180] */
-
-                       /* force elv from <90, 180] in [90, 0] */
-                       if (nmeaInfo->satinfo.sat[inviewIndex].elv > 90) {
-                               nmeaInfo->satinfo.sat[inviewIndex].elv = 180 - nmeaInfo->satinfo.sat[inviewIndex].elv;
-                       }
-
-                       /* force elv from [-180, -90> in [0, -90] */
-                       if (nmeaInfo->satinfo.sat[inviewIndex].elv < -90) {
-                               nmeaInfo->satinfo.sat[inviewIndex].elv = -180 - nmeaInfo->satinfo.sat[inviewIndex].elv;
-                       }
-
-                       /* elv is now in [-90, 90] */
-
-                       if (nmeaInfo->satinfo.sat[inviewIndex].elv < 0) {
-                               nmeaInfo->satinfo.sat[inviewIndex].elv = -nmeaInfo->satinfo.sat[inviewIndex].elv;
-                       }
-
-                       /* elv is now in [0, 90] */
-
-                       /* force azimuth in [0, 360> */
-                       while (nmeaInfo->satinfo.sat[inviewIndex].azimuth < 0) {
-                               nmeaInfo->satinfo.sat[inviewIndex].azimuth += 360;
-                       }
-                       while (nmeaInfo->satinfo.sat[inviewIndex].azimuth >= 360) {
-                               nmeaInfo->satinfo.sat[inviewIndex].azimuth -= 360;
-                       }
-                       /* azimuth is now in [0, 360> */
-
-                       /* force sig in [0, 99] */
-                       if (nmeaInfo->satinfo.sat[inviewIndex].sig < 0)
-                               nmeaInfo->satinfo.sat[inviewIndex].sig = 0;
-       &