summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Brown <mbrown@fensystems.co.uk>2016-02-03 22:40:23 +0000
committerEric S. Raymond <esr@thyrsus.com>2016-02-09 16:04:52 -0500
commit6a94e2254d02bc4d9e1d7d4015204c32855e8316 (patch)
tree4fd74d260c2abf9e58709e769a937e32ffad8778
parentd019151fc5ce02cbaf4ae56556614d320eb80347 (diff)
downloadgpsd-6a94e2254d02bc4d9e1d7d4015204c32855e8316.tar.gz
Add concept of a GPS-disciplined oscillator
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
-rw-r--r--SConstruct1
-rw-r--r--gps.h15
-rw-r--r--gps_json.h1
-rw-r--r--gpsd.h-tail3
-rw-r--r--gpsd_json.c21
-rw-r--r--gpsd_json.xml71
-rw-r--r--libgps_json.c41
-rw-r--r--test_json.c38
8 files changed, 177 insertions, 14 deletions
diff --git a/SConstruct b/SConstruct
index 0c2da085..3b4cb89c 100644
--- a/SConstruct
+++ b/SConstruct
@@ -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"),
diff --git a/gps.h b/gps.h
index cc51cd62..c5e1a5a2 100644
--- a/gps.h
+++ b/gps.h
@@ -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 */
diff --git a/gps_json.h b/gps_json.h
index a77b2679..1d4cf586 100644
--- a/gps_json.h
+++ b/gps_json.h
@@ -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: