summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--SConstruct1
-rwxr-xr-xdevtools/sizes1
-rw-r--r--drivers.c5
-rw-r--r--gpsd.c10
-rw-r--r--gpsd.h-tail14
-rw-r--r--gpsdecode.c12
-rw-r--r--libgpsd_core.c12
-rw-r--r--packet.c112
-rw-r--r--packet_states.h12
9 files changed, 171 insertions, 8 deletions
diff --git a/SConstruct b/SConstruct
index 309e15cc..1ea130ef 100644
--- a/SConstruct
+++ b/SConstruct
@@ -85,6 +85,7 @@ boolopts = (
("bluez", True, "BlueZ support for Bluetooth devices"),
("ipv6", True, "build IPv6 support"),
("netfeed", True, "build support for handling TCP/IP data sources"),
+ ("passthrough", False, "build support for passing through JSON"),
# Other daemon options
("timing", True, "latency timing support"),
("control_socket",True, "control socket for hotplug notifications"),
diff --git a/devtools/sizes b/devtools/sizes
index 45f2e63b..57617de4 100755
--- a/devtools/sizes
+++ b/devtools/sizes
@@ -65,6 +65,7 @@ sizeit("Minimalist build, stripped to NMEA only with shm interface",
"control_socket=no",
"ipv6=no",
"netfeed=no",
+ "passthrough=no",
"fixed_port_speed=9600",
"limited_max_devices=1",
] + nmea_variants + binary_gps + non_gps + time_service + debugging)
diff --git a/drivers.c b/drivers.c
index 9bd36a50..b6df16b6 100644
--- a/drivers.c
+++ b/drivers.c
@@ -46,6 +46,11 @@ gps_mask_t generic_parse_input(struct gps_device_t *session)
session->context->century = year - (year % 100);
}
return 0;
+#ifdef PASSTHROUGH_ENABLE
+ } else if (session->packet.type == JSON_PACKET) {
+ gpsd_report(LOG_IO, "<= GPS: %s\n", (char *)session->packet.outbuffer);
+ return PASSTHROUGH_IS;
+#endif /* PASSTHROUGH_ENABLE */
#ifdef NMEA_ENABLE
} else if (session->packet.type == NMEA_PACKET) {
gps_mask_t st = 0;
diff --git a/gpsd.c b/gpsd.c
index 6683e517..4d45d05d 100644
--- a/gpsd.c
+++ b/gpsd.c
@@ -1566,6 +1566,16 @@ static void consume_packets(struct gps_device_t *device)
if (sub == NULL || sub->active == 0 || !subscribed(sub, device))
continue;
+#ifdef PASSTHROUGH_ENABLE
+ /* this is for passing through JSON packets */
+ if ((changed & PASSTHROUGH_IS) != 0) {
+ (void)throttled_write(sub,
+ (char *)device->packet.outbuffer,
+ device->packet.outbuflen);
+ continue;
+ }
+#endif /* PASSTHROUGH_ENABLE */
+
/* report raw packets to users subscribed to those */
raw_report(sub, device);
diff --git a/gpsd.h-tail b/gpsd.h-tail
index 479ebbdd..7948ac3e 100644
--- a/gpsd.h-tail
+++ b/gpsd.h-tail
@@ -104,14 +104,15 @@ struct gps_packet_t {
#define SUPERSTAR2_PACKET 12
#define ONCORE_PACKET 13
#define GEOSTAR_PACKET 14
-#define MAX_PACKET_TYPE 14 /* increment this as necessary */
+#define MAX_GPSPACKET_TYPE 14 /* increment this as necessary */
#define RTCM2_PACKET 15
#define RTCM3_PACKET 16
-#define TEXTUAL_PACKET_TYPE(n) (((n)>=NMEA_PACKET) && ((n)<=MAX_TEXTUAL_TYPE))
-#define GPS_PACKET_TYPE(n) (((n)>=NMEA_PACKET) && ((n)<=MAX_PACKET_TYPE))
+#define JSON_PACKET 17
+#define TEXTUAL_PACKET_TYPE(n) ((((n)>=NMEA_PACKET) && ((n)<=MAX_TEXTUAL_TYPE)) || (n)==JSON_PACKET)
+#define GPS_PACKET_TYPE(n) (((n)>=NMEA_PACKET) && ((n)<=MAX_GPSPACKET_TYPE))
#define LOSSLESS_PACKET_TYPE(n) (((n)>=RTCM2_PACKET) && ((n)<=RTCM3_PACKET))
#define PACKET_TYPEMASK(n) (1 << (n))
-#define GPS_TYPEMASK (((2<<(MAX_PACKET_TYPE+1))-1) &~ PACKET_TYPEMASK(COMMENT_PACKET))
+#define GPS_TYPEMASK (((2<<(MAX_GPSPACKET_TYPE+1))-1) &~ PACKET_TYPEMASK(COMMENT_PACKET))
unsigned int state;
size_t length;
unsigned char inbuffer[MAX_PACKET_LENGTH*2+1];
@@ -142,6 +143,10 @@ struct gps_packet_t {
isgps30bits_t buf[RTCM2_WORDS_MAX]; /* packet data */
size_t buflen; /* packet length in bytes */
} isgps;
+#ifdef PASSTHROUGH_ENABLE
+ unsigned int json_depth;
+ unsigned int json_after;
+#endif /* PASSTHROUGH_ENABLE */
};
extern void packet_init(/*@out@*/struct gps_packet_t *);
@@ -252,6 +257,7 @@ typedef enum {
#define NODATA_IS INTERNAL_SET(6) /* no data read from fd */
#define PPSTIME_IS INTERNAL_SET(7) /* precision time is available */
#define PERR_IS INTERNAL_SET(8) /* PDOP set */
+#define PASSTHROUGH_IS INTERNAL_SET(9) /* passthrough mode */
#define DATA_IS ~(ONLINE_SET|PACKET_SET|CLEAR_IS|REPORT_IS)
typedef /*@unsignedintegraltype@*/ unsigned int driver_mask_t;
diff --git a/gpsdecode.c b/gpsdecode.c
index 50d3d52b..73ff6136 100644
--- a/gpsdecode.c
+++ b/gpsdecode.c
@@ -410,14 +410,18 @@ static void decode(FILE *fpin, FILE*fpout)
break;
if (verbose >= 1 && TEXTUAL_PACKET_TYPE(session.packet.type))
(void)fputs((char *)session.packet.outbuffer, fpout);
- if ((changed & (REPORT_IS|SUBFRAME_SET|AIS_SET|RTCM2_SET|RTCM3_SET)) == 0)
+ if ((changed & (REPORT_IS|SUBFRAME_SET|AIS_SET|RTCM2_SET|RTCM3_SET|PASSTHROUGH_IS)) == 0)
continue;
if (!filter(changed, &session))
continue;
else if (json) {
- json_data_report(changed,
- &session.gpsdata, &policy,
- buf, sizeof(buf));
+ if ((changed & PASSTHROUGH_IS) != 0) {
+ (void)fputs((char *)session.packet.outbuffer, fpout);
+ (void)fputs("\n", fpout);
+ } else
+ json_data_report(changed,
+ &session.gpsdata, &policy,
+ buf, sizeof(buf));
(void)fputs(buf, fpout);
#ifdef AIVDM_ENABLE
} else if (session.packet.type == AIVDM_PACKET) {
diff --git a/libgpsd_core.c b/libgpsd_core.c
index c2124bec..fa1181da 100644
--- a/libgpsd_core.c
+++ b/libgpsd_core.c
@@ -834,6 +834,10 @@ gps_mask_t gpsd_poll(struct gps_device_t *session)
session->gpsdata.dev.path, session->packet.type);
if (session->packet.type == COMMENT_PACKET) {
gpsd_report (LOG_PROG, "comment, sync lock deferred\n");
+#ifdef PASSTHROUGH_ENABLE
+ } if (session->packet.type == JSON_PACKET) {
+ gpsd_report (LOG_PROG, "JSON, sync lock deferred\n");
+#endif /* PASSTHROUGH_ENABLE */
} else if (session->packet.type > COMMENT_PACKET) {
first_sync = (session->device_type == NULL);
for (dp = gpsd_drivers; *dp; dp++)
@@ -919,6 +923,14 @@ gps_mask_t gpsd_poll(struct gps_device_t *session)
received |= DRIVER_IS;
}
+ /* Special case, JSON packets get passed through as us */
+#ifdef PASSTHROUGH_ENABLE
+ if (session->packet.type == JSON_PACKET) {
+ received |= PASSTHROUGH_IS;
+ }
+ else
+#endif /* PASSTHROUGH_ENABLE */
+
/* Get data from current packet into the fix structure */
if (session->packet.type != COMMENT_PACKET)
if (session->device_type != NULL
diff --git a/packet.c b/packet.c
index ba383284..43bd29e2 100644
--- a/packet.c
+++ b/packet.c
@@ -294,6 +294,12 @@ static void nextstate(struct gps_packet_t *lexer, unsigned char c)
break;
}
#endif /* RTCM104V3_ENABLE */
+#ifdef PASSTHROUGH_ENABLE
+ if (c == '{') {
+ lexer->state = JSON_LEADER;
+ character_pushback(lexer);
+ }
+#endif /* PASSTHROUGH_ENABLE */
break;
case COMMENT_BODY:
if (c == '\n')
@@ -1187,6 +1193,101 @@ static void nextstate(struct gps_packet_t *lexer, unsigned char c)
lexer->state = GROUND_STATE;
break;
#endif /* RTCM104V2_ENABLE */
+#ifdef PASSTHROUGH_ENABLE
+ case JSON_LEADER:
+ gpsd_report(LOG_RAW + 2,
+ "%08ld: JSON parser entered at depth %d with %c\n",
+ lexer->char_counter, lexer->json_depth, c);
+ if (c == '{' || c == '[') {
+ lexer->json_depth++;
+ } else if (c == '}' || c == ']') {
+ if (--lexer->json_depth == 0)
+ lexer->state = JSON_RECOGNIZED;
+ } else if (isspace(c) || c == ',')
+ break;
+ else if (c == '"') {
+ lexer->state = JSON_STRINGLITERAL;
+ lexer->json_after = JSON_END_ATTRIBUTE;
+ } else {
+ gpsd_report(LOG_RAW + 2,
+ "%08ld: missing attribute start after header\n",
+ lexer->char_counter);
+ lexer->state = GROUND_STATE;
+ }
+ break;
+ case JSON_STRINGLITERAL:
+ if (c == '\\')
+ lexer->state = JSON_STRING_SOLIDUS;
+ else if (c == '"')
+ lexer->state = lexer->json_after;
+ break;
+ case JSON_STRING_SOLIDUS:
+ lexer->state = JSON_STRINGLITERAL;
+ break;
+ case JSON_END_ATTRIBUTE:
+ if (isspace(c))
+ break;
+ else if (c == ':')
+ lexer->state = JSON_EXPECT_VALUE;
+ else
+ /* saw something other than value start after colon */
+ lexer->state = GROUND_STATE;
+ break;
+ case JSON_EXPECT_VALUE:
+ if (isspace(c))
+ break;
+ else if (c == '"') {
+ lexer->state = JSON_STRINGLITERAL;
+ lexer->json_after = JSON_END_VALUE;
+ } else if (c == '{' || c == '[') {
+ lexer->state = JSON_LEADER;
+ character_pushback(lexer);
+ } else if (strchr("-0123456789", c) != NULL) {
+ lexer->state = JSON_NUMBER;
+ } else if (c == 't' || c == 'f' || c == 'n')
+ /*
+ * This is a bit more permissive than strictly necessary, as
+ * GPSD JSON does not include the null token. Still, it's
+ * futureproofing.
+ */
+ lexer->state = JSON_SPECIAL;
+ else
+ /* couldn't recognize start of value literal */
+ lexer->state = GROUND_STATE;
+ break;
+ case JSON_NUMBER:
+ /*
+ * Will recognize some ill-formed numeric literals.
+ * Should be OK as we're already three stages deep inside
+ * JSON recognition; odds that we'll actually see an
+ * ill-formed literal are quite low. and the worst
+ * possible result if it happens is our JSON parser will
+ * quietly chuck out the object.
+ */
+ if (strchr("1234567890.eE+-", c) == NULL) {
+ lexer->state = JSON_END_VALUE;
+ character_pushback(lexer);
+ }
+ break;
+ case JSON_SPECIAL:
+ if (strchr("truefalsnil", c) == NULL) {
+ lexer->state = JSON_END_VALUE;
+ character_pushback(lexer);
+ }
+ break;
+ case JSON_END_VALUE:
+ if (isspace(c))
+ break;
+ else if (c == ',')
+ lexer->state = JSON_LEADER;
+ else if (c == '}' || c == ']') {
+ lexer->state = JSON_LEADER;
+ character_pushback(lexer);
+ } else
+ /* trailing garbage after JSON value */
+ lexer->state = GROUND_STATE;
+ break;
+#endif /* PASSTHROUGH_ENABLE */
}
/*@ -charint +casebreak @*/
}
@@ -1244,6 +1345,9 @@ void packet_init( /*@out@*/ struct gps_packet_t *lexer)
{
lexer->char_counter = 0;
lexer->retry_counter = 0;
+#ifdef PASSTHROUGH_ENABLE
+ lexer->json_depth = 0;
+#endif /* PASSTHROUGH_ENABLE */
packet_reset(lexer);
}
@@ -1814,6 +1918,14 @@ void packet_parse(struct gps_packet_t *lexer)
}
}
#endif
+#ifdef PASSTHROUGH_ENABLE
+ else if (lexer->state == JSON_RECOGNIZED) {
+ packet_accept(lexer, JSON_PACKET);
+ packet_discard(lexer);
+ lexer->state = GROUND_STATE;
+ break;
+ }
+#endif /* PASSTHROUGH_ENABLE */
} /* while */
}
diff --git a/packet_states.h b/packet_states.h
index 2d426444..07adaeda 100644
--- a/packet_states.h
+++ b/packet_states.h
@@ -182,4 +182,16 @@
RTCM3_RECOGNIZED, /* RTCM3 packet recognized */
#endif
+#ifdef PASSTHROUGH_ENABLE
+ JSON_LEADER, /* JSON leading { found */
+ JSON_STRINGLITERAL, /* start of JSON string literal seen */
+ JSON_STRING_SOLIDUS, /* backslash in string */
+ JSON_END_ATTRIBUTE, /* end of JSON attribute */
+ JSON_EXPECT_VALUE, /* just after colon */
+ JSON_END_VALUE, /* end of JSON value */
+ JSON_NUMBER, /* inside a JSON numeric literal */
+ JSON_SPECIAL, /* inside a JSON special literal (true,false,null) */
+ JSON_RECOGNIZED, /* JSON packet recognized */
+#endif
+
/* end of packet_states.h */