summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric S. Raymond <esr@thyrsus.com>2013-09-14 06:54:44 -0400
committerEric S. Raymond <esr@thyrsus.com>2013-09-14 06:57:44 -0400
commit531f5384638b9fe3e21e542ce6eed9a39b98fdfb (patch)
tree8bb2f3db54e8243f874d61c7ea58f7a5a0e70041
parentea0b84da541fb6e69d03a9dc85c399c7e4fff4cd (diff)
downloadgpsd-531f5384638b9fe3e21e542ce6eed9a39b98fdfb.tar.gz
Split Type 24 reporting, including the -s option to gpsdecode.
All regression tests pass.
-rw-r--r--NEWS1
-rw-r--r--driver_ais.c94
-rw-r--r--drivers.c8
-rw-r--r--gps.h11
-rw-r--r--gpsd.c1
-rw-r--r--gpsd.h-tail3
-rw-r--r--gpsd_json.c70
-rw-r--r--gpsd_json.xml9
-rw-r--r--gpsdecode.c8
-rw-r--r--gpsdecode.xml5
-rw-r--r--libgps_core.c3
-rw-r--r--libgps_sock.c4
-rw-r--r--shared_json.c1
-rw-r--r--test/clientlib/multipacket.log.chk2
14 files changed, 145 insertions, 75 deletions
diff --git a/NEWS b/NEWS
index a97a4f3f..2976d882 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,7 @@
Tweaks of Evermore support remove code and suppress spurious error messages.
Minor fix to AIVDM unpacking of Type 123 radio field.
Longer maximum path names (required an object library version bump.
+ New split24 option supports passing through AIS type 24 message halves.
* Wed 1 May 2013 Eric S. Raymond <esr@snark.thyrsus.com> - 3.9
Note to packagers: this is an urgent release that fixes a possible
diff --git a/driver_ais.c b/driver_ais.c
index b0be6c48..e8dbf668 100644
--- a/driver_ais.c
+++ b/driver_ais.c
@@ -853,56 +853,74 @@ bool ais_binary_decode(struct ais_t *ais,
bitlen);
return false;
}
- /* save incoming 24A shipname/MMSI pairs in a circular queue */
+ if (type24_queue != NULL)
{
- struct ais_type24a_t *saveptr = &type24_queue->ships[type24_queue->index];
+ /* save incoming 24A shipname/MMSI pairs in a circular queue */
+ {
+ struct ais_type24a_t *saveptr = &type24_queue->ships[type24_queue->index];
- gpsd_report(LOG_PROG,
- "AIVDM: 24A from %09u stashed.\n",
- ais->mmsi);
- saveptr->mmsi = ais->mmsi;
- UCHARS(40, saveptr->shipname);
- ++type24_queue->index;
- type24_queue->index %= MAX_TYPE24_INTERLEAVE;
+ gpsd_report(LOG_PROG,
+ "AIVDM: 24A from %09u stashed.\n",
+ ais->mmsi);
+ saveptr->mmsi = ais->mmsi;
+ UCHARS(40, saveptr->shipname);
+ ++type24_queue->index;
+ type24_queue->index %= MAX_TYPE24_INTERLEAVE;
+ }
+ //ais->type24.a.spare = UBITS(160, 8);
+ return false; /* data only partially decoded */
+ }
+ else
+ {
+ UCHARS(40, ais->type24.shipname);
+ ais->type24.part = part_a;
+ return true;
}
- //ais->type24.a.spare = UBITS(160, 8);
- return false; /* data only partially decoded */
case 1:
if (bitlen != 168) {
gpsd_report(LOG_WARN, "AIVDM message type 24B size not 168 bits (%zd).\n",
bitlen);
return false;
}
- /* search the 24A queue for a matching MMSI */
- for (i = 0; i < MAX_TYPE24_INTERLEAVE; i++) {
- if (type24_queue->ships[i].mmsi == ais->mmsi) {
- (void)strlcpy(ais->type24.shipname,
- type24_queue->ships[i].shipname,
- sizeof(type24_queue->ships[i].shipname));
- ais->type24.shiptype = UBITS(40, 8);
- UCHARS(48, ais->type24.vendorid);
- UCHARS(90, ais->type24.callsign);
- if (AIS_AUXILIARY_MMSI(ais->mmsi)) {
- ais->type24.mothership_mmsi = UBITS(132, 30);
- } else {
- ais->type24.dim.to_bow = UBITS(132, 9);
- ais->type24.dim.to_stern = UBITS(141, 9);
- ais->type24.dim.to_port = UBITS(150, 6);
- ais->type24.dim.to_starboard = UBITS(156, 6);
+ ais->type24.shiptype = UBITS(40, 8);
+ UCHARS(48, ais->type24.vendorid);
+ UCHARS(90, ais->type24.callsign);
+ if (AIS_AUXILIARY_MMSI(ais->mmsi)) {
+ ais->type24.mothership_mmsi = UBITS(132, 30);
+ } else {
+ ais->type24.dim.to_bow = UBITS(132, 9);
+ ais->type24.dim.to_stern = UBITS(141, 9);
+ ais->type24.dim.to_port = UBITS(150, 6);
+ ais->type24.dim.to_starboard = UBITS(156, 6);
+ }
+ //ais->type24.b.spare = UBITS(162, 8);
+ if (type24_queue != NULL)
+ {
+ /* search the 24A queue for a matching MMSI */
+ for (i = 0; i < MAX_TYPE24_INTERLEAVE; i++) {
+ if (type24_queue->ships[i].mmsi == ais->mmsi) {
+ (void)strlcpy(ais->type24.shipname,
+ type24_queue->ships[i].shipname,
+ sizeof(type24_queue->ships[i].shipname));
+ gpsd_report(LOG_PROG,
+ "AIVDM 24B from %09u matches a 24A.\n",
+ ais->mmsi);
+ /* prevent false match if a 24B is repeated */
+ type24_queue->ships[i].mmsi = 0;
+ return true;
}
- //ais->type24.b.spare = UBITS(162, 8);
- gpsd_report(LOG_PROG,
- "AIVDM 24B from %09u matches a 24A.\n",
- ais->mmsi);
- /* prevent false match if a 24B is repeated */
- type24_queue->ships[i].mmsi = 0;
- return true;
}
+ gpsd_report(LOG_WARN,
+ "AIVDM 24B from %09u can't be matched to a 24A.\n",
+ ais->mmsi);
+ ais->type24.part = both;
+ return false;
+ }
+ else
+ {
+ ais->type24.part = part_b;
+ return true;
}
- gpsd_report(LOG_WARN,
- "AIVDM 24B from %09u can't be matched to a 24A.\n",
- ais->mmsi);
- return false;
default:
gpsd_report(LOG_WARN, "AIVDM message type 24 of subtype unknown.\n");
return false;
diff --git a/drivers.c b/drivers.c
index 0e208730..4cb267ce 100644
--- a/drivers.c
+++ b/drivers.c
@@ -1207,7 +1207,7 @@ const struct gps_type_t mtk3301 = {
static bool aivdm_decode(const char *buf, size_t buflen,
struct gps_device_t *session,
struct ais_t *ais,
- int debug)
+ bool split24, int debug)
{
#ifdef __UNUSED_DEBUG__
char *sixbits[64] = {
@@ -1363,7 +1363,7 @@ static bool aivdm_decode(const char *buf, size_t buflen,
return ais_binary_decode(ais,
ais_context->bits,
ais_context->bitlen,
- &ais_context->type24_queue);
+ split24 ? NULL : &ais_context->type24_queue);
}
/* we're still waiting on another sentence */
@@ -1383,7 +1383,9 @@ static gps_mask_t aivdm_analyze(struct gps_device_t *session)
if (session->packet.type == AIVDM_PACKET) {
if (aivdm_decode
((char *)session->packet.outbuffer, session->packet.outbuflen,
- session, &session->gpsdata.ais, session->context->debug)) {
+ session, &session->gpsdata.ais,
+ session->gpsdata.policy.split24,
+ session->context->debug)) {
return ONLINE_SET | AIS_SET;
} else
return ONLINE_SET;
diff --git a/gps.h b/gps.h
index 0e16084a..80e93539 100644
--- a/gps.h
+++ b/gps.h
@@ -36,10 +36,10 @@ extern "C" {
* 5.0 - MAXCHANNELS bumped from 20 to 32 for GLONASS (Mar 2011, release 2.96)
* gps_open() becomes reentrant, what gps_open_r() used to be.
* gps_poll() removed in favor of gps_read(). The raw hook is gone.
- * 5.1 - GPS_PATH_MAX uses system PATH_MAX.
+ * 5.1 - GPS_PATH_MAX uses system PATH_MAX; split24 flag added.
*/
#define GPSD_API_MAJOR_VERSION 5 /* bump on incompatible changes */
-#define GPSD_API_MINOR_VERSION 0 /* bump on compatible changes */
+#define GPSD_API_MINOR_VERSION 1 /* bump on compatible changes */
#define MAXTAGLEN 8 /* maximum length of sentence tag name */
#define MAXCHANNELS 72 /* must be > 12 GPS + 12 GLONASS + 2 WAAS */
@@ -1645,6 +1645,11 @@ struct ais_t
/* Type 24 - Class B CS Static Data Report */
struct {
char shipname[AIS_SHIPNAME_MAXLEN+1]; /* vessel name */
+ enum {
+ both,
+ part_a,
+ part_b,
+ } part;
unsigned int shiptype; /* ship type code */
char vendorid[8]; /* vendor ID */
char callsign[8]; /* callsign */
@@ -1776,6 +1781,7 @@ struct policy_t {
int raw; /* requesting raw data? */
bool scaled; /* requesting report scaling? */
bool timing; /* requesting timing info */
+ bool split24; /* requesting split AIS Type 24s */
int loglevel; /* requested log level of messages */
char devpath[GPS_PATH_MAX]; /* specific device to watch */
char remote[GPS_PATH_MAX]; /* ...if this was passthrough */
@@ -1801,6 +1807,7 @@ typedef int socket_t;
#define WATCH_SCALED 0x000100u /* scale output to floats */
#define WATCH_TIMING 0x000200u /* timing information */
#define WATCH_DEVICE 0x000800u /* watch specific device */
+#define WATCH_SPLIT24 0x001000u /* split AIS Type 24s */
#define WATCH_NEWSTYLE 0x010000u /* force JSON streaming */
#define WATCH_OLDSTYLE 0x020000u /* force old-style streaming */
diff --git a/gpsd.c b/gpsd.c
index f65641e6..4ef66aec 100644
--- a/gpsd.c
+++ b/gpsd.c
@@ -620,6 +620,7 @@ static void detach_client(struct subscriber_t *sub)
sub->policy.raw = 0;
sub->policy.scaled = false;
sub->policy.timing = false;
+ sub->policy.split24 = false;
sub->policy.devpath[0] = '\0';
sub->fd = UNALLOCATED_FD;
/*@+mustfreeonly@*/
diff --git a/gpsd.h-tail b/gpsd.h-tail
index eb901339..ba932793 100644
--- a/gpsd.h-tail
+++ b/gpsd.h-tail
@@ -38,9 +38,10 @@ typedef unsigned int speed_t;
* 3.7 PPS message added to repertoire. SDDBT water depth reported as
* negative altitude with Mode 3 set.
* 3.8 AIS course nember becomes float in scaled mode (bug fix).
+ * 3.9 split24 flag added.
*/
#define GPSD_PROTO_MAJOR_VERSION 3 /* bump on incompatible changes */
-#define GPSD_PROTO_MINOR_VERSION 8 /* bump on compatible changes */
+#define GPSD_PROTO_MINOR_VERSION 9 /* bump on compatible changes */
#define JSON_DATE_MAX 24 /* ISO8601 timestamp with 2 decimal places */
diff --git a/gpsd_json.c b/gpsd_json.c
index 9f57c032..babbc1ac 100644
--- a/gpsd_json.c
+++ b/gpsd_json.c
@@ -423,13 +423,14 @@ void json_watch_dump(const struct policy_t *ccp,
{
/*@-compdef@*/
(void)snprintf(reply, replylen,
- "{\"class\":\"WATCH\",\"enable\":%s,\"json\":%s,\"nmea\":%s,\"raw\":%d,\"scaled\":%s,\"timing\":%s,",
+ "{\"class\":\"WATCH\",\"enable\":%s,\"json\":%s,\"nmea\":%s,\"raw\":%d,\"scaled\":%s,\"timing\":%s,\"split24\":%s",
ccp->watcher ? "true" : "false",
ccp->json ? "true" : "false",
ccp->nmea ? "true" : "false",
ccp->raw,
ccp->scaled ? "true" : "false",
- ccp->timing ? "true" : "false");
+ ccp->timing ? "true" : "false",
+ ccp->split24 ? "true" : "false");
if (ccp->devpath[0] != '\0')
(void)snprintf(reply + strlen(reply), replylen - strlen(reply),
"\"device\":\"%s\",", ccp->devpath);
@@ -2963,37 +2964,50 @@ void json_aivdm_dump(const struct ais_t *ais,
}
break;
case 24: /* Class B CS Static Data Report */
- (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
- "\"shipname\":\"%s\",",
- json_stringify(buf1, sizeof(buf1),
- ais->type24.shipname));
- if (scaled) {
+ if (ais->type24.part != both) {
+ static char *partnames[] = {"AB", "A", "B"};
(void)snprintf(buf + strlen(buf), buflen - strlen(buf),
- "\"shiptype\":\"%s\",",
- SHIPTYPE_DISPLAY(ais->type24.shiptype));
- } else {
- (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
- "\"shiptype\":%u,", ais->type24.shiptype);
+ "\"part\":\"%s\",",
+ json_stringify(buf1, sizeof(buf1),
+ partnames[ais->type24.part]));
}
- (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
- "\"vendorid\":\"%s\",\"callsign\":\"%s\",",
- json_stringify(buf1, sizeof(buf1),
- ais->type24.vendorid),
- json_stringify(buf2, sizeof(buf2),
- ais->type24.callsign));
- if (AIS_AUXILIARY_MMSI(ais->mmsi)) {
+ if (ais->type24.part != part_b)
(void)snprintf(buf + strlen(buf), buflen - strlen(buf),
- "\"mothership_mmsi\":%u}\r\n",
- ais->type24.mothership_mmsi);
- } else {
+ "\"shipname\":\"%s\",",
+ json_stringify(buf1, sizeof(buf1),
+ ais->type24.shipname));
+ if (ais->type24.part != part_a) {
+ if (scaled) {
+ (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
+ "\"shiptype\":\"%s\",",
+ SHIPTYPE_DISPLAY(ais->type24.shiptype));
+ } else {
+ (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
+ "\"shiptype\":%u,", ais->type24.shiptype);
+ }
(void)snprintf(buf + strlen(buf), buflen - strlen(buf),
- "\"to_bow\":%u,\"to_stern\":%u,"
- "\"to_port\":%u,\"to_starboard\":%u}\r\n",
- ais->type24.dim.to_bow,
- ais->type24.dim.to_stern,
- ais->type24.dim.to_port,
- ais->type24.dim.to_starboard);
+ "\"vendorid\":\"%s\",\"callsign\":\"%s\",",
+ json_stringify(buf1, sizeof(buf1),
+ ais->type24.vendorid),
+ json_stringify(buf2, sizeof(buf2),
+ ais->type24.callsign));
+ if (AIS_AUXILIARY_MMSI(ais->mmsi)) {
+ (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
+ "\"mothership_mmsi\":%u}\r\n",
+ ais->type24.mothership_mmsi);
+ } else {
+ (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
+ "\"to_bow\":%u,\"to_stern\":%u,"
+ "\"to_port\":%u,\"to_starboard\":%u",
+ ais->type24.dim.to_bow,
+ ais->type24.dim.to_stern,
+ ais->type24.dim.to_port,
+ ais->type24.dim.to_starboard);
+ }
}
+ if (buf[strlen(buf)-1] == ',')
+ buf[strlen(buf)-1] = '\0';
+ strncat(buf, "}\r\n", buflen);
break;
case 25: /* Binary Message, Single Slot */
(void)snprintf(buf + strlen(buf), buflen - strlen(buf),
diff --git a/gpsd_json.xml b/gpsd_json.xml
index 7b9b1dd7..6d31e989 100644
--- a/gpsd_json.xml
+++ b/gpsd_json.xml
@@ -1003,6 +1003,15 @@ object.</para>
reports.</entry>
</row>
<row>
+ <entry>split24</entry>
+ <entry>No</entry>
+ <entry>boolean</entry>
+ <entry>If true, aggregate AIS type24 sentence parts. If false,
+ report each part as a separatee JSON object, leaving the
+ client to match MMSIs and aggregate. Default is
+ false. Applies only to AIS reports.</entry>
+</row>
+<row>
<entry>device</entry>
<entry>No</entry>
<entry>string</entry>
diff --git a/gpsdecode.c b/gpsdecode.c
index c3673114..0ed7ef50 100644
--- a/gpsdecode.c
+++ b/gpsdecode.c
@@ -17,6 +17,7 @@
static int verbose = 0;
static bool scaled = true;
static bool json = true;
+static bool split24 = false;
static unsigned int ntypes = 0;
static unsigned int typelist[32];
@@ -532,6 +533,7 @@ static void decode(FILE *fpin, FILE*fpout)
gpsd_clear(&session);
session.gpsdata.gps_fd = fileno(fpin);
session.gpsdata.dev.baudrate = 38400; /* hack to enable subframes */
+ session.gpsdata.policy.split24 = split24;
(void)strlcpy(session.gpsdata.dev.path,
"stdin",
sizeof(session.gpsdata.dev.path));
@@ -621,7 +623,7 @@ int main(int argc, char **argv)
enum
{ doencode, dodecode } mode = dodecode;
- while ((c = getopt(argc, argv, "cdejpt:uvVD:")) != EOF) {
+ while ((c = getopt(argc, argv, "cdejpst:uvVD:")) != EOF) {
switch (c) {
case 'c':
json = false;
@@ -639,6 +641,10 @@ int main(int argc, char **argv)
json = true;
break;
+ case 's':
+ split24 = true;
+ break;
+
case 't':
/*@-nullpass@*/
typelist[ntypes++] = (unsigned int)atoi(strtok(optarg, ","));
diff --git a/gpsdecode.xml b/gpsdecode.xml
index f5aae92d..984b968d 100644
--- a/gpsdecode.xml
+++ b/gpsdecode.xml
@@ -26,6 +26,7 @@ BSD terms apply: see the file COPYING in the distribution root for details.
<arg choice='opt'>-d</arg>
<arg choice='opt'>-e</arg>
<arg choice='opt'>-j</arg>
+ <arg choice='opt'>-s</arg>
<arg choice='opt'>-t <replaceable>typelist</replaceable></arg>
<arg choice='opt'>-u</arg>
<arg choice='opt'>-v</arg>
@@ -73,6 +74,10 @@ encode JSON on standard input to JSON on standard output. This option
is only useful for regression-testing of the JSON dumping and parsing
code.</para>
+<para>The <option>-t</option> option option tells the program to report
+AIS Type 24 sentence halves separately rather than attempting to
+aggregate them.</para>
+
<para>The <option>-t</option> accepts a comma-separated list of
numeric types. Packets with a numeric AIS, RTCM2, or RTCM3 type are
passed through and output only if they match a type in the
diff --git a/libgps_core.c b/libgps_core.c
index 3d0c57e6..5da71c4e 100644
--- a/libgps_core.c
+++ b/libgps_core.c
@@ -319,12 +319,13 @@ void libgps_dump_state(struct gps_data_t *collect)
collect->version.proto_minor);
if (collect->set & POLICY_SET)
(void)fprintf(debugfp,
- "POLICY: watcher=%s nmea=%s raw=%d scaled=%s timing=%s, devpath=%s\n",
+ "POLICY: watcher=%s nmea=%s raw=%d scaled=%s timing=%s, split24=%s devpath=%s\n",
collect->policy.watcher ? "true" : "false",
collect->policy.nmea ? "true" : "false",
collect->policy.raw,
collect->policy.scaled ? "true" : "false",
collect->policy.timing ? "true" : "false",
+ collect->policy.split24 ? "true" : "false",
collect->policy.devpath);
if (collect->set & SATELLITE_SET) {
int i;
diff --git a/libgps_sock.c b/libgps_sock.c
index b8d01034..bdbecdea 100644
--- a/libgps_sock.c
+++ b/libgps_sock.c
@@ -517,6 +517,8 @@ int gps_sock_stream(struct gps_data_t *gpsdata, unsigned int flags,
(void)strlcat(buf, "\"scaled\":false,", sizeof(buf));
if (flags & WATCH_TIMING)
(void)strlcat(buf, "\"timing\":false,", sizeof(buf));
+ if (flags & WATCH_SPLIT24)
+ (void)strlcat(buf, "\"split24\":false,", sizeof(buf));
if (buf[strlen(buf) - 1] == ',')
buf[strlen(buf) - 1] = '\0';
(void)strlcat(buf, "};", sizeof(buf));
@@ -543,6 +545,8 @@ int gps_sock_stream(struct gps_data_t *gpsdata, unsigned int flags,
(void)strlcat(buf, "\"scaled\":true,", sizeof(buf));
if (flags & WATCH_TIMING)
(void)strlcat(buf, "\"timing\":true,", sizeof(buf));
+ if (flags & WATCH_SPLIT24)
+ (void)strlcat(buf, "\"split24\":true,", sizeof(buf));
/*@-nullpass@*//* shouldn't be needed, splint has a bug */
if (flags & WATCH_DEVICE)
(void)snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
diff --git a/shared_json.c b/shared_json.c
index e3f116c3..7c87c3e6 100644
--- a/shared_json.c
+++ b/shared_json.c
@@ -96,6 +96,7 @@ int json_watch_read(const char *buf,
.nodefault = true},
{"scaled", t_boolean, .addr.boolean = &ccp->scaled},
{"timing", t_boolean, .addr.boolean = &ccp->timing},
+ {"split24", t_boolean, .addr.boolean = &ccp->split24},
{"device", t_string, .addr.string = ccp->devpath,
.len = sizeof(ccp->devpath)},
{"remote", t_string, .addr.string = ccp->remote,
diff --git a/test/clientlib/multipacket.log.chk b/test/clientlib/multipacket.log.chk
index cc1b4904..8b78f647 100644
--- a/test/clientlib/multipacket.log.chk
+++ b/test/clientlib/multipacket.log.chk
@@ -1,2 +1,2 @@
flags: (0x20000000) {POLICY}
-POLICY: watcher=true nmea=false raw=0 scaled=false timing=false, devpath=
+POLICY: watcher=true nmea=false raw=0 scaled=false timing=false, split24=false devpath=