[prev in list] [next in list] [prev in thread] [next in thread]
List: gpsd-dev
Subject: [Gpsd-dev] [PATCH] aivdm again
From: Nirgal <contact_gpsd () nirgal ! com>
Date: 2010-05-18 20:45:05
Message-ID: 201005182245.06730.contact_gpsd () nirgal ! com
[Download RAW message or body]
> Please send a minimal patch againsat HEAD for the rest.
Here's a new almost-minimal patch:
* Allways clean the resulting ais buffer, so that no garbage is left. Removed CLEAR \
macro.
* Allways returns false when decoding is incomplete, including for unsupported \
message types.
* Warn about unknown messages of type 24C and 24D, return false.
* Added support for AIS channels 1, 2 and empty. Maps respectively to 'A', 'B', 'A' \
and generate an error message. Added FIXME in code.
* fragmented message fix. Ok that one is not minimal. It's only reader-sanity minimal \
;)
- Renamed context var "await" to "decoded_frags", because of its initial value of 0. \
It now contains the number of successfully decoded fragments in the complete \
sentence.
- Added local var "nfrag" for expected fragment count. It used to be store in context \
directly, under name "await". Contexts are for keeping data across several calls! \
Things stored there unconditionally at the beginning of processing shouldn't be \
there, they should be on stack as temporary values.
- Renamed local var "part" as "ifrag", it still contains the fragment id amongst \
nfrags fragments.
Code is correctly commented I hope, so just enjoy :)
I did not re-implement type 24 shipname checks. One should do something about it.
-> Either split the message so that you actually receive 2 lines: 24A and 24B. This \
means rewriting type24 ais structure with a union of struct 24A and \
struct 24B.
-> Or check the mmsi of 24A and 24B matches, so that you won't get a 24A of an mmsi \
mixed up with the 24B of another ship. In that case, either we want to add "mmsi24" \
in aivdm context and abort in case of mismatch, either we implement a full hashtable \
or database of last 24A / mmsi messages, but that's way beyond the scope of that \
decoder. My first dirty implementation was to erase shipname in context after \
decoding 24B, and to check the shipname was not empty before. That's not enough, as I \
discovered running real life packets.
["aivdm.diff" (text/x-diff)]
diff --git a/driver_aivdm.c b/driver_aivdm.c
index 83a129e..056fcb4 100644
--- a/driver_aivdm.c
+++ b/driver_aivdm.c
@@ -82,7 +82,7 @@ bool aivdm_decode(const char *buf, size_t buflen,
"111100", "111101", "111110", "111111",
};
#endif /* __UNUSED_DEBUG__ */
- int part, nfields = 0;
+ int nfrags, ifrag, nfields = 0;
unsigned char *field[NMEA_MAX*2];
unsigned char fieldcopy[NMEA_MAX*2+1];
unsigned char *data, *cp = fieldcopy;
@@ -96,6 +96,9 @@ bool aivdm_decode(const char *buf, size_t buflen,
/* we may need to dump the raw packet */
gpsd_report(LOG_PROG, "AIVDM packet length %zd: %s\n", buflen, buf);
+ /* first clear the result, making sure we don't return garbage */
+ memset(ais, 0, sizeof(*ais));
+
/* discard overlong sentences */
if (strlen(buf) > sizeof(fieldcopy)-1) {
gpsd_report(LOG_ERROR, "overlong AIVDM packet.\n");
@@ -119,22 +122,46 @@ bool aivdm_decode(const char *buf, size_t buflen,
}
switch (field[4][0]) {
- case 'A': ais_context = &ais_contexts[0]; break;
- case 'B': ais_context = &ais_contexts[1]; break;
+ /* FIXME: if fields[4] == "12", it doesn't detect the error */
+ case '\0':
+ case '1':
+ gpsd_report(LOG_ERROR, "invalid AIS channel '%c'. Assuming 'A'\n",
+ field[4][0]);
+ /* no break */
+ case 'A':
+ ais_context = &ais_contexts[0];
+ break;
+ case '2':
+ gpsd_report(LOG_ERROR, "invalid AIS channel '2'. Assuming 'B'.\n");
+ /* no break */
+ case 'B':
+ ais_context = &ais_contexts[1];
+ break;
default:
gpsd_report(LOG_ERROR, "invalid AIS channel.\n");
return false;
}
- ais_context->await = atoi((char *)field[1]);
- part = atoi((char *)field[2]);
+ nfrags = atoi((char *)field[1]); /* number of fragments to expect */
+ ifrag = atoi((char *)field[2]); /* fragment id */
data = field[5];
- pad = field[6][0];
- gpsd_report(LOG_PROG, "await=%d, part=%d, data=%s\n",
- ais_context->await, part, data);
+ pad = field[6][0]; /* number of padding bits */
+ gpsd_report(LOG_PROG, "nfrags=%d, ifrag=%d, decoded_frags=%d, data=%s\n",
+ nfrags, ifrag, ais_context->decoded_frags, data);
/* assemble the binary data */
- if (part == 1) {
+
+ /* check fragment ordering */
+ if (ifrag != ais_context->decoded_frags + 1) {
+ gpsd_report(LOG_ERROR, "invalid fragment #%d received, expected #%d.\n",
+ ifrag, ais_context->decoded_frags + 1);
+ if (ifrag != 1)
+ return false;
+ /* else, ifrag==1: Just discard all that was previously decoded and
+ * simply handle that packet */
+ ais_context->decoded_frags = 0;
+ }
+ if (ifrag == 1) {
(void)memset(ais_context->bits, '\0', sizeof(ais_context->bits));
ais_context->bitlen = 0;
}
@@ -164,18 +191,19 @@ bool aivdm_decode(const char *buf, size_t buflen,
/*@ -charint @*/
/* time to pass buffered-up data to where it's actually processed? */
- if (part == ais_context->await) {
+ if (ifrag == nfrags) {
size_t clen = (ais_context->bitlen + 7) / 8;
gpsd_report(LOG_INF, "AIVDM payload is %zd bits, %zd chars: %s\n",
ais_context->bitlen, clen,
gpsd_hexdump_wrapper(ais_context->bits, clen, LOG_INF));
+ /* clear waiting fragments count */
+ ais_context->decoded_frags = 0;
#define BITS_PER_BYTE 8
#define UBITS(s, l) ubits((char *)ais_context->bits, s, l)
#define SBITS(s, l) sbits((char *)ais_context->bits, s, l)
#define UCHARS(s, to) from_sixbit((char *)ais_context->bits, s, sizeof(to), to)
-#define CLEAR(typ) memset(&ais->typ, '\0', sizeof(ais->typ))
ais->type = UBITS(0, 6);
ais->repeat = UBITS(6, 2);
ais->mmsi = UBITS(8, 30);
@@ -195,7 +223,6 @@ bool aivdm_decode(const char *buf, size_t buflen,
gpsd_report(LOG_WARN, "AIVDM message type %d size not 168 bits (%zd).\n",
ais->type,
ais_context->bitlen);
- CLEAR(type1);
return false;
}
ais->type1.status = UBITS(38, 4);
@@ -229,7 +256,6 @@ bool aivdm_decode(const char *buf, size_t buflen,
gpsd_report(LOG_WARN, "AIVDM message type %d size not 168 bits (%zd).\n",
ais->type,
ais_context->bitlen);
- CLEAR(type4);
return false;
}
ais->type4.year = UBITS(38, 14);
@@ -262,7 +288,6 @@ bool aivdm_decode(const char *buf, size_t buflen,
if (ais_context->bitlen != 424) {
gpsd_report(LOG_WARN, "AIVDM message type 5 size not 424 bits (%zd).\n",
ais_context->bitlen);
- CLEAR(type5);
return false;
}
ais->type5.ais_version = UBITS(38, 2);
@@ -294,7 +319,6 @@ bool aivdm_decode(const char *buf, size_t buflen,
if (ais_context->bitlen < 88 || ais_context->bitlen > 1008) {
gpsd_report(LOG_WARN, "AIVDM message type 6 size is out of range (%zd).\n",
ais_context->bitlen);
- CLEAR(type6);
return false;
}
ais->type6.seqno = UBITS(38, 2);
@@ -322,8 +346,7 @@ bool aivdm_decode(const char *buf, size_t buflen,
gpsd_report(LOG_WARN, "AIVDM message type %d size is out of range (%zd).\n",
ais->type,
ais_context->bitlen);
- CLEAR(type7);
- break;
+ return false;
}
for (i = 0; i < sizeof(mmsi)/sizeof(mmsi[0]); i++)
if (ais_context->bitlen > 40 + 32*i)
@@ -343,7 +366,6 @@ bool aivdm_decode(const char *buf, size_t buflen,
if (ais_context->bitlen < 56 || ais_context->bitlen > 1008) {
gpsd_report(LOG_WARN, "AIVDM message type 8 size is out of range (%zd).\n",
ais_context->bitlen);
- CLEAR(type8);
return false;
}
//ais->type8.spare = UBITS(38, 2);
@@ -362,7 +384,6 @@ bool aivdm_decode(const char *buf, size_t buflen,
if (ais_context->bitlen != 168) {
gpsd_report(LOG_WARN, "AIVDM message type 9 size not 168 bits (%zd).\n",
ais_context->bitlen);
- CLEAR(type9);
return false;
}
ais->type9.alt = UBITS(38, 12);
@@ -392,7 +413,6 @@ bool aivdm_decode(const char *buf, size_t buflen,
if (ais_context->bitlen != 72) {
gpsd_report(LOG_WARN, "AIVDM message type 10 size not 72 bits (%zd).\n",
ais_context->bitlen);
- CLEAR(type10);
return false;
}
//ais->type10.spare = UBITS(38, 2);
@@ -404,7 +424,6 @@ bool aivdm_decode(const char *buf, size_t buflen,
if (ais_context->bitlen < 72 || ais_context->bitlen > 1008) {
gpsd_report(LOG_WARN, "AIVDM message type 12 size is out of range (%zd).\n",
ais_context->bitlen);
- CLEAR(type12);
return false;
}
ais->type12.seqno = UBITS(38, 2);
@@ -422,8 +441,7 @@ bool aivdm_decode(const char *buf, size_t buflen,
if (ais_context->bitlen < 40 || ais_context->bitlen > 1008) {
gpsd_report(LOG_WARN, "AIVDM message type 14 size is out of range (%zd).\n",
ais_context->bitlen);
- CLEAR(type14);
- break;
+ return false;
}
//ais->type14.spare = UBITS(38, 2);
from_sixbit((char *)ais_context->bits,
@@ -435,7 +453,6 @@ bool aivdm_decode(const char *buf, size_t buflen,
if (ais_context->bitlen < 88 || ais_context->bitlen > 168) {
gpsd_report(LOG_WARN, "AIVDM message type 15 size is out of range (%zd).\n",
ais_context->bitlen);
- CLEAR(type15);
return false;
}
(void)memset(&ais->type15, '\0', sizeof(ais->type15));
@@ -462,7 +479,6 @@ bool aivdm_decode(const char *buf, size_t buflen,
if (ais_context->bitlen != 96 && ais_context->bitlen != 144) {
gpsd_report(LOG_WARN, "AIVDM message type 16 size is out of range (%zd).\n",
ais_context->bitlen);
- CLEAR(type16);
return false;
}
ais->type16.mmsi1 = UBITS(40, 30);
@@ -481,8 +497,7 @@ bool aivdm_decode(const char *buf, size_t buflen,
if (ais_context->bitlen < 80 || ais_context->bitlen > 816) {
gpsd_report(LOG_WARN, "AIVDM message type 17 size is out of range (%zd).\n",
ais_context->bitlen);
- CLEAR(type17);
- break;
+ return false;
}
//ais->type17.spare = UBITS(38, 2);
ais->type17.lon = UBITS(40, 18);
@@ -498,7 +513,6 @@ bool aivdm_decode(const char *buf, size_t buflen,
if (ais_context->bitlen != 168) {
gpsd_report(LOG_WARN, "AIVDM message type 18 size not 168 bits (%zd).\n",
ais_context->bitlen);
- CLEAR(type18);
return false;
}
ais->type18.reserved = UBITS(38, 8);
@@ -533,7 +547,6 @@ bool aivdm_decode(const char *buf, size_t buflen,
if (ais_context->bitlen != 312) {
gpsd_report(LOG_WARN, "AIVDM message type 19 size not 312 bits (%zd).\n",
ais_context->bitlen);
- CLEAR(type19);
return false;
}
ais->type19.reserved = UBITS(38, 8);
@@ -572,7 +585,6 @@ bool aivdm_decode(const char *buf, size_t buflen,
if (ais_context->bitlen < 72 || ais_context->bitlen > 160) {
gpsd_report(LOG_WARN, "AIVDM message type 20 size is out of range (%zd).\n",
ais_context->bitlen);
- CLEAR(type20);
return false;
}
//ais->type20.spare = UBITS(38, 2);
@@ -597,7 +609,7 @@ bool aivdm_decode(const char *buf, size_t buflen,
if (ais_context->bitlen < 272 || ais_context->bitlen > 360) {
gpsd_report(LOG_WARN, "AIVDM message type 21 size is out of range (%zd).\n",
ais_context->bitlen);
- break;
+ return false;
}
ais->type21.aid_type = UBITS(38, 5);
from_sixbit((char *)ais_context->bits,
@@ -633,7 +645,7 @@ bool aivdm_decode(const char *buf, size_t buflen,
if (ais_context->bitlen != 168) {
gpsd_report(LOG_WARN, "AIVDM message type 22 size not 168 bits (%zd).\n",
ais_context->bitlen);
- break;
+ return false;
}
ais->type22.channel_a = UBITS(40, 12);
ais->type22.channel_b = UBITS(52, 12);
@@ -684,7 +696,7 @@ bool aivdm_decode(const char *buf, size_t buflen,
if (ais_context->bitlen != 168) {
gpsd_report(LOG_WARN, "AIVDM message type 24B size not 168 bits (%zd).\n",
ais_context->bitlen);
- break;
+ return false;
}
(void)strlcpy(ais->type24.shipname,
ais_context->shipname,
@@ -702,6 +714,9 @@ bool aivdm_decode(const char *buf, size_t buflen,
}
//ais->type24.b.spare = UBITS(162, 8);
break;
+ default:
+ gpsd_report(LOG_WARN, "AIVDM message type 24 of subtype unknown.\n");
+ return false;
}
gpsd_report(LOG_INF, "\n");
break;
@@ -710,7 +725,7 @@ bool aivdm_decode(const char *buf, size_t buflen,
if (ais_context->bitlen < 40 || ais_context->bitlen > 168) {
gpsd_report(LOG_WARN, "AIVDM message type 25 size not between 40 to 168 bits (%zd).\n",
ais_context->bitlen);
- break;
+ return false;
}
ais->type25.addressed = (bool)UBITS(38, 1);
ais->type25.structured = (bool)UBITS(39, 1);
@@ -768,10 +783,9 @@ bool aivdm_decode(const char *buf, size_t buflen,
default:
gpsd_report(LOG_INF, "\n");
gpsd_report(LOG_ERROR, "Unparsed AIVDM message type %d.\n",ais->type);
- break;
+ return false;
}
/* *INDENT-ON* */
-#undef CLEAR
#undef UCHARS
#undef SBITS
#undef UBITS
@@ -782,6 +796,7 @@ bool aivdm_decode(const char *buf, size_t buflen,
}
/* we're still waiting on another sentence */
+ ais_context->decoded_frags++;
return false;
}
diff --git a/gpsd.h-tail b/gpsd.h-tail
index a66cec1..fdb44a1 100644
--- a/gpsd.h-tail
+++ b/gpsd.h-tail
@@ -194,10 +194,10 @@ struct gps_context_t {
struct aivdm_context_t {
/* hold context for decoding AIDVM packet sequences */
- int await; /* for tracking AIDVM parts in a multipart sequence */
+ int decoded_frags; /* for tracking AIDVM parts in a multipart sequence */
unsigned char bits[2048];
- char shipname[AIS_SHIPNAME_MAXLEN+1];
size_t bitlen;
+ char shipname[AIS_SHIPNAME_MAXLEN+1]; /* type 24 specific */
};
struct gps_device_t;
_______________________________________________
Gpsd-dev mailing list
Gpsd-dev@lists.berlios.de
https://lists.berlios.de/mailman/listinfo/gpsd-dev
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic