diff options
-rw-r--r-- | SConstruct | 1 | ||||
-rwxr-xr-x | devtools/sizes | 1 | ||||
-rw-r--r-- | drivers.c | 5 | ||||
-rw-r--r-- | gpsd.c | 10 | ||||
-rw-r--r-- | gpsd.h-tail | 14 | ||||
-rw-r--r-- | gpsdecode.c | 12 | ||||
-rw-r--r-- | libgpsd_core.c | 12 | ||||
-rw-r--r-- | packet.c | 112 | ||||
-rw-r--r-- | packet_states.h | 12 |
9 files changed, 171 insertions, 8 deletions
@@ -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) @@ -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; @@ -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 @@ -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 */ |