diff options
author | Michael Brown <mbrown@fensystems.co.uk> | 2016-02-03 22:40:23 +0000 |
---|---|---|
committer | Eric S. Raymond <esr@thyrsus.com> | 2016-02-09 16:04:52 -0500 |
commit | 6a94e2254d02bc4d9e1d7d4015204c32855e8316 (patch) | |
tree | 4fd74d260c2abf9e58709e769a937e32ffad8778 | |
parent | d019151fc5ce02cbaf4ae56556614d320eb80347 (diff) | |
download | gpsd-6a94e2254d02bc4d9e1d7d4015204c32855e8316.tar.gz |
Add concept of a GPS-disciplined oscillator
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
-rw-r--r-- | SConstruct | 1 | ||||
-rw-r--r-- | gps.h | 15 | ||||
-rw-r--r-- | gps_json.h | 1 | ||||
-rw-r--r-- | gpsd.h-tail | 3 | ||||
-rw-r--r-- | gpsd_json.c | 21 | ||||
-rw-r--r-- | gpsd_json.xml | 71 | ||||
-rw-r--r-- | libgps_json.c | 41 | ||||
-rw-r--r-- | test_json.c | 38 |
8 files changed, 177 insertions, 14 deletions
@@ -131,6 +131,7 @@ boolopts = ( ("ntp", True, "NTP time hinting support"), ("ntpshm", True, "NTP time hinting via shared memory"), ("pps", True, "PPS time syncing support"), + ("oscillator", True, "Disciplined oscillator support"), # Export methods ("socket_export", True, "data export over sockets"), ("dbus_export", True, "enable DBUS export support"), @@ -1907,6 +1907,13 @@ struct timedelta_t { }; #endif /* TIMEDELTA_DEFINED */ +struct oscillator_t { + bool running; /* oscillator is running */ + bool reference; /* PPS reference is available */ + bool disciplined; /* oscillator is GPS-disciplined */ + int delta; /* last observed PPS delta */ +}; + /* * Someday we may support Windows, under which socket_t is a separate type. * In the meantime, having a typedef for this semantic kind is no bad thing, @@ -1971,7 +1978,8 @@ struct gps_data_t { #define TOFF_SET (1llu<<32) /* not yet used */ #define PPS_SET (1llu<<33) #define NAVDATA_SET (1llu<<34) -#define SET_HIGH_BIT 35 +#define OSCILLATOR_SET (1llu<<35) +#define SET_HIGH_BIT 36 timestamp_t online; /* NZ if GPS is on line, 0 if not. * * Note: gpsd clears this time when sentences @@ -2021,7 +2029,7 @@ struct gps_data_t { } devices; /* pack things never reported together to reduce structure size */ -#define UNION_SET (RTCM2_SET|RTCM3_SET|SUBFRAME_SET|AIS_SET|ATTITUDE_SET|GST_SET|VERSION_SET|LOGMESSAGE_SET|ERROR_SET|TOFF_SET|PPS_SET) +#define UNION_SET (RTCM2_SET|RTCM3_SET|SUBFRAME_SET|AIS_SET|ATTITUDE_SET|GST_SET|OSCILLATOR_SET|VERSION_SET|LOGMESSAGE_SET|ERROR_SET|TOFF_SET|PPS_SET) union { /* unusual forms of sensor data that might come up the pipe */ struct rtcm2_t rtcm2; @@ -2032,6 +2040,7 @@ struct gps_data_t { struct navdata_t navdata; struct rawdata_t raw; struct gst_t gst; + struct oscillator_t osc; /* "artificial" structures for various protocol responses */ struct version_t version; char error[256]; @@ -2061,6 +2070,8 @@ int json_toff_read(const char *buf, struct gps_data_t *, const char **); int json_pps_read(const char *buf, struct gps_data_t *, const char **); +int json_oscillator_read(const char *buf, struct gps_data_t *, + const char **); /* dependencies on struct gpsdata_t end here */ @@ -23,6 +23,7 @@ void json_tpv_dump(const struct gps_device_t *, void json_noise_dump(const struct gps_data_t *, char *, size_t); void json_sky_dump(const struct gps_data_t *, char *, size_t); void json_att_dump(const struct gps_data_t *, char *, size_t); +void json_oscillator_dump(const struct gps_data_t *, char *, size_t); void json_subframe_dump(const struct gps_data_t *, char buf[], size_t); void json_device_dump(const struct gps_device_t *, char *, size_t); void json_watch_dump(const struct policy_t *, char *, size_t); diff --git a/gpsd.h-tail b/gpsd.h-tail index cfe1a754..9516573d 100644 --- a/gpsd.h-tail +++ b/gpsd.h-tail @@ -32,9 +32,10 @@ * 3.10 The obsolete tag field has been dropped from JSON. * 3.11 A precision field, log2 of the time source jitter, has been added * to the PPS report. See ntpshm.h for more details. + * 3.12 OSC message added to repertoire. */ #define GPSD_PROTO_MAJOR_VERSION 3 /* bump on incompatible changes */ -#define GPSD_PROTO_MINOR_VERSION 11 /* bump on compatible changes */ +#define GPSD_PROTO_MINOR_VERSION 12 /* 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 aca3955a..44b2c0e7 100644 --- a/gpsd_json.c +++ b/gpsd_json.c @@ -3366,6 +3366,21 @@ void json_att_dump(const struct gps_data_t *gpsdata, } #endif /* COMPASS_ENABLE */ +#ifdef OSCILLATOR_ENABLE +void json_oscillator_dump(const struct gps_data_t *datap, + char *reply, size_t replylen) +/* dump the contents of an oscillator_t structure as JSON */ +{ + (void)snprintf(reply, replylen, + "{\"class\":\"OSC\",\"device\":\"%s\",\"running\":%s,\"reference\":%s,\"disciplined\":%s,\"delta\":%d}\r\n", + datap->dev.path, + JSON_BOOL(datap->osc.running), + JSON_BOOL(datap->osc.reference), + JSON_BOOL(datap->osc.disciplined), + datap->osc.delta); +} +#endif /* OSCILLATOR_ENABLE */ + void json_data_report(const gps_mask_t changed, const struct gps_device_t *session, const struct policy_t *policy, @@ -3418,6 +3433,12 @@ void json_data_report(const gps_mask_t changed, buf+strlen(buf), buflen-strlen(buf)); } #endif /* AIVDM_ENABLE */ + +#ifdef OSCILLATOR_ENABLE + if ((changed & OSCILLATOR_SET) != 0) { + json_oscillator_dump(datap, buf+strlen(buf), buflen-strlen(buf)); + } +#endif /* OSCILLATOR_ENABLE */ } #undef JSON_BOOL diff --git a/gpsd_json.xml b/gpsd_json.xml index 03d3cb59..46bcdc0b 100644 --- a/gpsd_json.xml +++ b/gpsd_json.xml @@ -1341,6 +1341,77 @@ limited to about 1 millisecond. seconds.</para> </varlistentry> <varlistentry> +<term>OSC</term> +<listitem> + +<para>This message reports the status of a GPS-disciplined oscillator +(GPSDO). The GPS PPS output (which has excellent long-term stability) +is typically used to discipline a local oscillator with much better +short-term stability (such as a rubidium atomic clock).</para> + +<para>An OSC object has the following elements:</para> + +<table frame="all" pgwide="0"><title>OSC object</title> +<tgroup cols="3" align="left" colsep="1" rowsep="1"> +<thead> +<row> + <entry>Name</entry> + <entry>Always?</entry> + <entry>Type</entry> + <entry>Description</entry> +</row> +</thead> +<tbody> +<row> + <entry>class</entry> + <entry>Yes</entry> + <entry>string</entry> + <entry>Fixed: "OSC"</entry> +</row> +<row> + <entry>device</entry> + <entry>Yes</entry> + <entry>string</entry> + <entry>Name of originating device.</entry> +</row> +<row> + <entry>running</entry> + <entry>Yes</entry> + <entry>boolean</entry> + <entry>If true, the oscillator is currently running. Oscillators may require warm-up time at start of day.</entry> +</row> +<row> + <entry>reference</entry> + <entry>Yes</entry> + <entry>boolean</entry> + <entry>If true, the oscillator is receiving a GPS PPS signal.</entry> +</row> +<row> + <entry>disciplined</entry> + <entry>Yes</entry> + <entry>boolean</entry> + <entry>If true, the GPS PPS signal is sufficiently stable and is being used to discipline the local oscillator.</entry> +</row> +<row> + <entry>delta</entry> + <entry>Yes</entry> + <entry>numeric</entry> + <entry>The time difference (in nanoseconds) between the GPS-disciplined oscillator PPS output pulse and the most recent GPS PPS input pulse.</entry> +</row> +</tbody> +</tgroup> +</table> + +<para>Here's an example:</para> + +<programlisting> +{"class":"OSC","running":true,"device":"/dev/ttyUSB0", + "reference":true,"disciplined":true,"delta":67} +</programlisting> +</listitem> +</varlistentry> + +<varlistentry> <term>?DEVICE</term> <listitem> diff --git a/libgps_json.c b/libgps_json.c index 7ebb0f78..1d751682 100644 --- a/libgps_json.c +++ b/libgps_json.c @@ -395,6 +395,40 @@ int json_pps_read(const char *buf, struct gps_data_t *gpsdata, return status; } +int json_oscillator_read(const char *buf, struct gps_data_t *gpsdata, + const char **endptr) +{ + bool running = false, reference = false, disciplined = false; + int delta = 0; + const struct json_attr_t json_attrs_osc[] = { + /* *INDENT-OFF* */ + {"class", t_check, .dflt.check = "OSC"}, + {"device", t_string, .addr.string = gpsdata->dev.path, + .len = sizeof(gpsdata->dev.path)}, + {"running", t_boolean, .addr.boolean = &running, + .dflt.boolean = false}, + {"reference", t_boolean, .addr.boolean = &reference, + .dflt.boolean = false}, + {"disciplined", t_boolean, .addr.boolean = &disciplined, + .dflt.boolean = false}, + {"delta", t_integer, .addr.integer = &delta, + .dflt.integer = 0}, + {NULL}, + /* *INDENT-ON* */ + }; + int status; + + memset(&gpsdata->osc, '\0', sizeof(gpsdata->osc)); + status = json_read_object(buf, json_attrs_osc, endptr); + + gpsdata->osc.running = running; + gpsdata->osc.reference = reference; + gpsdata->osc.disciplined = disciplined; + gpsdata->osc.delta = delta; + + return status; +} + int libgps_json_unpack(const char *buf, struct gps_data_t *gpsdata, const char **end) /* the only entry point - unpack a JSON object into gpsdata_t substructures */ @@ -536,6 +570,13 @@ int libgps_json_unpack(const char *buf, gpsdata->set |= PPS_SET; } return status; + } else if (str_starts_with(classtag, "\"class\":\"OSC\"")) { + status = json_oscillator_read(buf, gpsdata, end); + if (status == 0) { + gpsdata->set &= ~UNION_SET; + gpsdata->set |= OSCILLATOR_SET; + } + return status; } else return -1; } diff --git a/test_json.c b/test_json.c index aff1aa08..84c86fa7 100644 --- a/test_json.c +++ b/test_json.c @@ -223,8 +223,14 @@ static const char *json_strTOFF = "{\"class\":\"TOFF\",\"device\":\"GPS#1\"," \ "\"real_sec\":1428001514, \"real_nsec\":1000000," \ "\"clock_sec\":1428001513,\"clock_nsec\":999999999}"; +/* Case 12: test parsing of OSC message */ + +static const char *json_strOSC = "{\"class\":\"OSC\",\"device\":\"GPS#1\"," \ + "\"running\":true,\"reference\":true,\"disciplined\":false," \ + "\"delta\":67}"; + #ifndef JSON_MINIMAL -/* Case 12: Read array of integers */ +/* Case 13: Read array of integers */ static const char *json_strInt = "[23,-17,5]"; static int intstore[4], intcount; @@ -236,7 +242,7 @@ static const struct json_array_t json_array_Int = { .maxlen = sizeof(intstore)/sizeof(intstore[0]), }; -/* Case 13: Read array of booleans */ +/* Case 14: Read array of booleans */ static const char *json_strBool = "[true,false,true]"; static bool boolstore[4]; @@ -249,13 +255,13 @@ static const struct json_array_t json_array_Bool = { .maxlen = sizeof(boolstore)/sizeof(boolstore[0]), }; -/* Case 14: Read array of reals */ +/* Case 15: Read array of reals */ -static const char *json_str14 = "[23.1,-17.2,5.3]"; +static const char *json_str15 = "[23.1,-17.2,5.3]"; static double realstore[4]; static int realcount; -static const struct json_array_t json_array_14 = { +static const struct json_array_t json_array_15 = { .element_type = t_real, .arr.reals.store = realstore, .count = &realcount, @@ -386,10 +392,20 @@ static void jsontest(int i) assert_integer("clock_nsec", gpsdata.pps.clock.tv_nsec, 999999999); break; + case 12: + status = json_oscillator_read(json_strOSC, &gpsdata, NULL); + assert_case(12,status); + assert_string("device", gpsdata.dev.path, "GPS#1"); + assert_boolean("running", gpsdata.osc.running, true); + assert_boolean("reference", gpsdata.osc.reference, true); + assert_boolean("disciplined", gpsdata.osc.disciplined, false); + assert_integer("delta", gpsdata.osc.delta, 67); + break; + #ifdef JSON_MINIMAL -#define MAXTEST 11 +#define MAXTEST 12 #else - case 12: + case 13: status = json_read_array(json_strInt, &json_array_Int, NULL); assert_integer("count", intcount, 3); assert_integer("intstore[0]", intstore[0], 23); @@ -398,7 +414,7 @@ static void jsontest(int i) assert_integer("intstore[3]", intstore[3], 0); break; - case 13: + case 14: status = json_read_array(json_strBool, &json_array_Bool, NULL); assert_integer("count", boolcount, 3); assert_boolean("boolstore[0]", boolstore[0], true); @@ -407,8 +423,8 @@ static void jsontest(int i) assert_boolean("boolstore[3]", boolstore[3], false); break; - case 14: - status = json_read_array(json_str14, &json_array_14, NULL); + case 15: + status = json_read_array(json_str15, &json_array_15, NULL); assert_integer("count", realcount, 3); assert_real("realstore[0]", realstore[0], 23.1); assert_real("realstore[1]", realstore[1], -17.2); @@ -416,7 +432,7 @@ static void jsontest(int i) assert_real("realstore[3]", realstore[3], 0); break; -#define MAXTEST 14 +#define MAXTEST 15 #endif /* JSON_MINIMAL */ default: |