summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ais_json.c28
-rw-r--r--driver_ais.c24
-rw-r--r--gps.h27
-rw-r--r--gpsd_json.c71
-rw-r--r--jsongen.py.in40
-rw-r--r--www/AIVDM.txt63
6 files changed, 217 insertions, 36 deletions
diff --git a/ais_json.c b/ais_json.c
index 827f3264..e2d9223c 100644
--- a/ais_json.c
+++ b/ais_json.c
@@ -330,6 +330,34 @@ int json_ais_read(const char *buf,
status = json_read_object(buf, json_ais8_fid19, endptr);
imo = true;
}
+ else if (strstr(buf, "\"fid\":23,") != NULL) {
+ status = json_read_object(buf, json_ais8_fid23, endptr);
+ ais->type8.dac200fid23.start_year = AIS_YEAR_NOT_AVAILABLE;
+ ais->type8.dac200fid23.start_month = AIS_MONTH_NOT_AVAILABLE;
+ ais->type8.dac200fid23.start_day = AIS_DAY_NOT_AVAILABLE;
+ ais->type8.dac200fid23.start_hour = AIS_HOUR_NOT_AVAILABLE;
+ ais->type8.dac200fid23.start_minute = AIS_MINUTE_NOT_AVAILABLE;
+ ais->type8.dac200fid23.end_year = AIS_YEAR_NOT_AVAILABLE;
+ ais->type8.dac200fid23.end_month = AIS_MONTH_NOT_AVAILABLE;
+ ais->type8.dac200fid23.end_day = AIS_DAY_NOT_AVAILABLE;
+ ais->type8.dac200fid23.end_hour = AIS_HOUR_NOT_AVAILABLE;
+ ais->type8.dac200fid23.end_minute = AIS_MINUTE_NOT_AVAILABLE;
+ // cppcheck-suppress uninitvar
+ (void)sscanf(start, "%09u-%02u-%02uT%02u:%02u",
+ &ais->type8.dac200fid23.start_year,
+ &ais->type8.dac200fid23.start_month,
+ &ais->type8.dac200fid23.start_day,
+ &ais->type8.dac200fid23.start_hour,
+ &ais->type8.dac200fid23.start_minute);
+ // cppcheck-suppress uninitvar
+ (void)sscanf(end, "%09u-%02u-%02uT%02u:%02u",
+ &ais->type8.dac200fid23.end_year,
+ &ais->type8.dac200fid23.end_month,
+ &ais->type8.dac200fid23.end_day,
+ &ais->type8.dac200fid23.end_hour,
+ &ais->type8.dac200fid23.end_minute);
+ imo = true;
+ }
else if (strstr(buf, "\"fid\":27,") != NULL) {
status = json_read_object(buf, json_ais8_fid27, endptr);
if (status == 0) {
diff --git a/driver_ais.c b/driver_ais.c
index 4e566749..d3452255 100644
--- a/driver_ais.c
+++ b/driver_ais.c
@@ -653,6 +653,30 @@ bool ais_binary_decode(const int debug,
ais->type8.dac200fid10.course_q = (bool)UBITS(158, 1);
ais->type8.dac200fid10.heading_q = (bool)UBITS(159, 1);
/* skip 8 bits */
+ imo = true;
+ break;
+ case 23:
+ ais->type8.dac200fid23.start_year = UBITS(56, 8);
+ ais->type8.dac200fid23.start_month = UBITS(64, 4);
+ ais->type8.dac200fid23.start_day = UBITS(68, 5);
+ ais->type8.dac200fid23.end_year = UBITS(73, 8);
+ ais->type8.dac200fid23.end_month = UBITS(81, 4);
+ ais->type8.dac200fid23.end_day = UBITS(85, 5);
+ ais->type8.dac200fid23.start_hour = UBITS(90, 5);
+ ais->type8.dac200fid23.start_minute = UBITS(95, 6);
+ ais->type8.dac200fid23.end_hour = UBITS(101, 5);
+ ais->type8.dac200fid23.end_minute = UBITS(106, 6);
+ ais->type8.dac200fid23.start_lon = SBITS(112, 28);
+ ais->type8.dac200fid23.start_lat = SBITS(140, 27);
+ ais->type8.dac200fid23.end_lon = SBITS(167, 28);
+ ais->type8.dac200fid23.end_lat = SBITS(195, 27);
+ ais->type8.dac200fid23.type = UBITS(222, 4);
+ ais->type8.dac200fid23.min = SBITS(226, 9);
+ ais->type8.dac200fid23.max = SBITS(235, 9);
+ ais->type8.dac200fid23.class = UBITS(244, 2);
+ ais->type8.dac200fid23.wind = UBITS(246, 4);
+ /* skip 6 bits */
+ imo = true;
break;
}
}
diff --git a/gps.h b/gps.h
index e6ffab45..3d200b87 100644
--- a/gps.h
+++ b/gps.h
@@ -1261,6 +1261,33 @@ struct ais_t
bool course_q; /* Course inf. quality */
bool heading_q; /* Heading inf. quality */
} dac200fid10;
+ /* Inland AIS EMMA Warning */
+ struct {
+ unsigned int start_year; /* Start Year */
+ unsigned int start_month; /* Start Month */
+ unsigned int start_day; /* Start Day */
+ unsigned int end_year; /* End Year */
+ unsigned int end_month; /* End Month */
+ unsigned int end_day; /* End Day */
+ unsigned int start_hour; /* Start Hour */
+ unsigned int start_minute; /* Start Minute */
+ unsigned int end_hour; /* End Hour */
+ unsigned int end_minute; /* End Minute */
+ signed int start_lon; /* Start Longitude */
+ signed int start_lat; /* Start Latitude */
+ signed int end_lon; /* End Longitude */
+ signed int end_lat; /* End Latitude */
+ unsigned int type; /* Type */
+#define DAC200FID23_TYPE_UNKNOWN 0
+ signed int min; /* Min value */
+#define DAC200FID23_MIN_UNKNOWN 255
+ signed int max; /* Max value */
+#define DAC200FID23_MAX_UNKNOWN 255
+ unsigned int class; /* Classification */
+#define DAC200FID23_CLASS_UNKNOWN 0
+ unsigned int wind; /* Wind Direction */
+#define DAC200FID23_WIND_UNKNOWN 0
+ } dac200fid23;
/* IMO236 - Meteorological-Hydrological data
* Trial message, not to be used after January 2013
* Replaced by IMO289 (DAC 1, FID 31)
diff --git a/gpsd_json.c b/gpsd_json.c
index 7866f87a..722b8e09 100644
--- a/gpsd_json.c
+++ b/gpsd_json.c
@@ -2735,6 +2735,37 @@ void json_aivdm_dump(const struct ais_t *ais,
"Loaded",
};
#define LSTATUS_DISPLAY(n) (((n) < (unsigned int)NITEMS(lstatus_types)) ? lstatus_types[n] : "INVALID LOAD STATUS")
+ const char *emma_types[] = {
+ "Not Available",
+ "Wind",
+ "Rain",
+ "Snow and ice",
+ "Thunderstorm",
+ "Fog",
+ "Low temperature",
+ "High temperature",
+ "Flood",
+ "Forest Fire",
+ };
+#define EMMA_TYPE_DISPLAY(n) (((n) < (unsigned int)NITEMS(emma_types)) ? emma_types[n] : "INVALID EMMA TYPE")
+ const char *emma_classes[] = {
+ "Slight",
+ "Medium",
+ "Strong",
+ };
+#define EMMA_CLASS_DISPLAY(n) (((n) < (unsigned int)NITEMS(emma_classes)) ? emma_classes[n] : "INVALID EMMA TYPE")
+ const char *emma_winds[] = {
+ "N/A",
+ "North",
+ "North East",
+ "East",
+ "South East",
+ "South",
+ "South West",
+ "West",
+ "North West",
+ };
+#define EMMA_WIND_DISPLAY(n) (((n) < (unsigned int)NITEMS(emma_winds)) ? emma_winds[n] : "INVALID EMMA WIND DIRECTION")
switch (ais->type8.fid) {
case 10: /* Inland ship static and voyage-related data */
for (cp = shiptypes; cp < shiptypes + NITEMS(shiptypes); cp++)
@@ -2765,6 +2796,46 @@ void json_aivdm_dump(const struct ais_t *ais,
JSON_BOOL(ais->type8.dac200fid10.heading_q));
structured = true;
break;
+ case 23: /* EMMA warning */
+ (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
+ "\"start\":\"%4u-%02u-%02uT%02u:%02u\","
+ "\"end\":\"%4u-%02u-%02uT%02u:%02u\",",
+ ais->type8.dac200fid23.start_year + 2000,
+ ais->type8.dac200fid23.start_month,
+ ais->type8.dac200fid23.start_hour,
+ ais->type8.dac200fid23.start_minute,
+ ais->type8.dac200fid23.start_day,
+ ais->type8.dac200fid23.end_year + 2000,
+ ais->type8.dac200fid23.end_month,
+ ais->type8.dac200fid23.end_day,
+ ais->type8.dac200fid23.end_hour,
+ ais->type8.dac200fid23.end_minute);
+ if (scaled)
+ (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
+ "\"start_lon\":%.4f,\"start_lat\":%.4f,\"end_lon\":%.4f,\"end_lat\":%.4f,",
+ ais->type8.dac200fid23.start_lon / AIS_LATLON_DIV,
+ ais->type8.dac200fid23.start_lat / AIS_LATLON_DIV,
+ ais->type8.dac200fid23.end_lon / AIS_LATLON_DIV,
+ ais->type8.dac200fid23.end_lat / AIS_LATLON_DIV);
+ else
+ (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
+ "\"start_lon\":%d,\"start_lat\":%d,\"end_lon\":%d,\"end_lat\":%d,",
+ ais->type8.dac200fid23.start_lon,
+ ais->type8.dac200fid23.start_lat,
+ ais->type8.dac200fid23.end_lon,
+ ais->type8.dac200fid23.end_lat);
+ (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
+ "\"type\":%u,\"type_text\":\"%s\",\"min\":%d,\"max\":%d,\"class\":%u,\"class_text\":\"%s\",\"wind\":%u,\"wind_text\":\"%s\"}",
+
+ ais->type8.dac200fid23.type,
+ EMMA_TYPE_DISPLAY(ais->type8.dac200fid23.type),
+ ais->type8.dac200fid23.min,
+ ais->type8.dac200fid23.max,
+ ais->type8.dac200fid23.class,
+ EMMA_CLASS_DISPLAY(ais->type8.dac200fid23.class),
+ ais->type8.dac200fid23.wind,
+ EMMA_WIND_DISPLAY(ais->type8.dac200fid23.wind));
+ break;
}
}
if (!structured)
diff --git a/jsongen.py.in b/jsongen.py.in
index 27492af7..8a64c6dc 100644
--- a/jsongen.py.in
+++ b/jsongen.py.in
@@ -430,7 +430,7 @@ ais_specs = (
('thour', 'uinteger', 'AIS_HOUR_NOT_AVAILABLE'),
('tminute', 'uinteger', 'AIS_MINUTE_NOT_AVAILABLE'),
),
- 'stringbuffered' : ('from', 'to'),
+ 'stringbuffered' : ('closefrom', 'closeto'),
},
{
"initname" : "json_ais8_fid15",
@@ -491,6 +491,29 @@ ais_specs = (
),
},
{
+ "initname" : "json_ais8_fid23",
+ "headers": ("AIS_HEADER","AIS_TYPE8"),
+ "structname": "ais->type8.dac200fid23",
+ "fieldmap":(
+ # fieldname type default
+ ('start', 'string', None),
+ ('end', 'string', None),
+ ('start_lon', 'integer', 'AIS_LON4_NOT_AVAILABLE'),
+ ('start_lat', 'integer', 'AIS_LAT4_NOT_AVAILABLE'),
+ ('end_lon', 'integer', 'AIS_LON4_NOT_AVAILABLE'),
+ ('end_lat', 'integer', 'AIS_LAT4_NOT_AVAILABLE'),
+ ('type', 'uinteger', 'DAC200FID23_TYPE_UNKNOWN'),
+ ('type_text', 'ignore', None),
+ ('min', 'integer', 'DAC200FID23_MIN_UNKNOWN'),
+ ('max', 'integer', 'DAC200FID23_MAX_UNKNOWN'),
+ ('class', 'uinteger', 'DAC200FID23_CLASS_UNKNOWN'),
+ ('class_text', 'ignore', None),
+ ('wind', 'uinteger', 'DAC200FID23_WIND_UNKNOWN'),
+ ('wind_text', 'ignore', None),
+ ),
+ 'stringbuffered' : ('start', 'end'),
+ },
+ {
"initname" : "json_ais8_fid27",
"headers": ("AIS_HEADER","AIS_TYPE8",),
"structname": "ais->type8.dac1fid27",
@@ -879,11 +902,16 @@ def generate(spec):
initname = spec["initname"]
# Utter storage declarations for any fields that are declared to be
# stringbuffered. These will need to be postprocessed in json_ais_read().
- for (attr, itype, default) in spec["fieldmap"]:
- if attr in spec.get("stringbuffered", []):
- if attr not in outboard:
- report += " char %s[JSON_VAL_MAX+1];\n" % attr
- outboard.append(attr)
+ attributes = [t[0] for t in spec["fieldmap"]]
+ for attr in spec.get("stringbuffered", []):
+ if attr not in attributes:
+ print >>sys.stderr, "buffered %s is not in base attributes of %s"\
+ % (attr, initname)
+ raise SystemExit, 1
+ elif attr not in outboard:
+ report += " char %s[JSON_VAL_MAX+1];\n" % attr
+ outboard.append(attr)
+
structname = spec["structname"]
# If there are structarrays describing array subobjects, we need
# to make a separate parse control initializer for each one. The
diff --git a/www/AIVDM.txt b/www/AIVDM.txt
index 7d333ca4..8bd26eed 100644
--- a/www/AIVDM.txt
+++ b/www/AIVDM.txt
@@ -3605,37 +3605,37 @@ replace the Notices to Skippers warnings.
[frame="topbot",options="header"]
|===============================================================================
-|Field |Len |Description |Member |T|Units
-|0-5 | 6 |Message Type |type |u|Constant: 8
-|6-7 | 2 |Repeat Indicator |repeat |u|As in Common Navigation Block
-|8-37 | 30 |Source MMSI |mmsi |u|9 decimal digits
-|38-39 | 2 |Spare | |x|Not used
-|40-49 | 10 |Designated Area Code|dac |u|Constant: 200
-|50-55 | 6 |Functional ID |fid |u|Constant: 23
-|56-63 | 8 |Start Year |start_year |u|1-55, year since 2000
- 0 = N/A (default)
-|64-67 | 4 |Start Month |start_month|u|1-12; 0 = N/A (default)
-|68-72 | 5 |Start Day |start_day |u|1-31; 0 = N/A (default)
-|73-80 | 8 |End Year |end_year |u|1-55, year since 2000
+|Field |Len |Description |Member |T|Units
+|0-5 | 6 |Message Type |type |u|Constant: 8
+|6-7 | 2 |Repeat Indicator |repeat |u|As in Common Navigation Block
+|8-37 | 30 |Source MMSI |mmsi |u|9 decimal digits
+|38-39 | 2 |Spare | |x|Not used
+|40-49 | 10 |Designated Area Code|dac |u|Constant: 200
+|50-55 | 6 |Functional ID |fid |u|Constant: 23
+|56-63 | 8 |Start Year |start_year |u|1-55, year since 2000
+ 0 = N/A (default)
+|64-67 | 4 |Start Month |start_month |u|1-12; 0 = N/A (default)
+|68-72 | 5 |Start Day |start_day |u|1-31; 0 = N/A (default)
+|73-80 | 8 |End Year |end_year |u|1-55, year since 2000
0 = N/A (default)
-|81-84 | 4 |End Month |end_month |u|1-12; 0 = N/A (default)
-|85-89 | 5 |End Day |end_day |u|1-31; 0 = N/A (default)
-|90-94 | 5 |Start Hour |start_hour |u|0-23; 24 = N/A (default)
-|95-100 | 6 |Start Minute |start_min |u|0-59; 60 = N/A (default)
-|101-105 | 5 |End Hour |end_hour |u|0-23; 24 = N/A (default)
-|106-111 | 6 |End Minute |end_min |u|0-59; 60 = N/A (default)
-|112-139 | 28 |Start Longitude |start_lon |I4|Minutes/10000 (as in CNB)
-|140-166 | 27 |Start Latitude |start_lat |I4|Minutes/10000 (as in CNB)
-|167-194 | 28 |End Longitude |end_lon |I4|Minutes/10000 (as in CNB)
-|195-221 | 27 |End Latitude |end_lat |I4|Minutes/10000 (as in CNB)
-|222-225 | 4 |Type |type |e|See "EMMA Type Codes" below
-|226-234 | 9 |Min value |min |i|Signed Integer, see below
-|235-243 | 9 |Max value |max |i|Signed Integer, see below
-|244-245 | 2 |Classification |class |e|1 = Slight,
- 2 = Medium,
- 3 = Strong
-|246-249 | 4 |Wind Direction |wind |e|See "EMMA Winds" below
-|250-255 | 6 |Spare | |x|Not used
+|81-84 | 4 |End Month |end_month |u|1-12; 0 = N/A (default)
+|85-89 | 5 |End Day |end_day |u|1-31; 0 = N/A (default)
+|90-94 | 5 |Start Hour |start_hour |u|0-23; 24 = N/A (default)
+|95-100 | 6 |Start Minute |start_minute|u|0-59; 60 = N/A (default)
+|101-105 | 5 |End Hour |end_hour |u|0-23; 24 = N/A (default)
+|106-111 | 6 |End Minute |end_minute |u|0-59; 60 = N/A (default)
+|112-139 | 28 |Start Longitude |start_lon |I4|Minutes/10000 (as in CNB)
+|140-166 | 27 |Start Latitude |start_lat |I4|Minutes/10000 (as in CNB)
+|167-194 | 28 |End Longitude |end_lon |I4|Minutes/10000 (as in CNB)
+|195-221 | 27 |End Latitude |end_lat |I4|Minutes/10000 (as in CNB)
+|222-225 | 4 |Type |type |e|See "EMMA Type Codes" below
+|226-234 | 9 |Min value |min |i|Signed Integer, see below
+|235-243 | 9 |Max value |max |i|Signed Integer, see below
+|244-245 | 2 |Classification |class |e|1 = Slight,
+ 2 = Medium,
+ 3 = Strong
+|246-249 | 4 |Wind Direction |wind |e|See "EMMA Winds" below
+|250-255 | 6 |Spare | |x|Not used
|===============================================================================
OPEN-QUESTION: <<INLAND>> is not explicit about the interpretation of
@@ -3657,6 +3657,7 @@ are UTC or local.
.EMMA Type Codes
[frame="topbot",options="header"]
|==============================
+| 0 | NA | Not Available
| 1 | WI | Wind
| 2 | RA | Rain
| 3 | SN | Snow and ice
@@ -4812,6 +4813,8 @@ ISO8601 format.
|8(1/13)| tmonth,tday,thour,tminute | to | %02u-%02uT%02u:%02uZ
|8(1/22)| month,day,hour,minute | timestamp | %02u-%02uT%02u:%02uZ
|8(1/27)| month,day,hour,minute | start | %02u-%02uT%02u:%02uZ
+|8(200/23)| year,month,day,hour,minute | start |%4u-%02u-%02uT%02u:%02u
+|8(200/23)| year,month,day,hour,minute | end |%4u-%02u-%02uT%02u:%02u
|===========================================================================
4. There are two variants of the encoding, one scaled and one