summaryrefslogtreecommitdiff
path: root/drivers.c
diff options
context:
space:
mode:
authorMichael Brown <mbrown@fensystems.co.uk>2016-02-03 22:40:26 +0000
committerEric S. Raymond <esr@thyrsus.com>2016-02-09 16:24:10 -0500
commitbf65d4033a451b1a274cbe1a59904e8300bf02dc (patch)
tree99f8e693f6122854240d305e3eb2fd3eb1d3d29c /drivers.c
parent58a352431b563ca46e071eced3e8445133cd0b80 (diff)
downloadgpsd-bf65d4033a451b1a274cbe1a59904e8300bf02dc.tar.gz
Autodetect and configure Spectratime iSync device
The Spectratime iSync devices comprise a u-blox 6 attached to a separate iSync microcontroller which drives a rubidium oscillator. The oscillator status messages may appear in the middle of the underlying GPS messages; these are handled via the "stashed partial message" support. This patch modifies the u-blox driver's parse_input() method to delegate NMEA messages to generic_parse_input() rather than nmea_parse(). This is done to allow the iSync trigger string to be detected after reactivation despite the "stickiness" of the u-blox driver. The initial delay time in gpsfake is extended from 1.0 seconds to 1.4 seconds to allow for the additional two 200ms delays introduced by the calls to gpsd_set_speed() in isync_detect(). The iSync driver legitimately uses both a probe_detect() method and a trigger string. The guard against such drivers is therefore removed from test_packet.c. The regression test data includes one artificially induced packet collision (where an oscillator status message appears in the middle of a GPS message), since this corner case is difficult to trigger deliberately in normal operation. Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
Diffstat (limited to 'drivers.c')
-rw-r--r--drivers.c170
1 files changed, 170 insertions, 0 deletions
diff --git a/drivers.c b/drivers.c
index 0ce47e8d..5d62706b 100644
--- a/drivers.c
+++ b/drivers.c
@@ -1152,6 +1152,173 @@ const struct gps_type_t driver_mtk3301 = {
/* *INDENT-ON* */
#endif /* MTK3301_ENABLE */
+#ifdef ISYNC_ENABLE
+/**************************************************************************
+ *
+ * Spectratime LNRCLOK / GRCLOK iSync GPS-disciplined rubidium oscillators
+ *
+ * These devices comprise a u-blox 6 attached to a separate iSync
+ * microcontroller which drives the rubidium oscillator. The iSync
+ * microcontroller can be configured to pass through the underlying
+ * GPS communication channel, while still using the GPS PPSREF signal
+ * to discipline the rubidium oscillator.
+ *
+ * The iSync can also generate its own periodic status packets in NMEA
+ * format. These describe the state of the oscillator (including
+ * whether or not the oscillator PPSOUT is synced to the GPS PPSREF).
+ * These packets are transmitted in the middle of the underlying GPS
+ * packets, forcing us to handle interrupted NMEA packets.
+ *
+ * The default state of the device is to generate no periodic output.
+ * We send a probe string to initiate beating of the iSync-proprietary
+ * $PTNTS,B message, which is then detected as a NMEA trigger.
+ *
+ **************************************************************************/
+
+static ssize_t isync_write(struct gps_device_t *session, const char *data)
+
+{
+ return gpsd_write(session, data, strlen(data));
+}
+
+static bool isync_detect(struct gps_device_t *session)
+{
+ speed_t old_baudrate;
+ char old_parity;
+ unsigned int old_stopbits;
+
+ /* Set 9600 8N1 */
+ old_baudrate = session->gpsdata.dev.baudrate;
+ old_parity = session->gpsdata.dev.parity;
+ old_stopbits = session->gpsdata.dev.stopbits;
+ gpsd_set_speed(session, 9600, 'N', 1);
+
+ /* Cancel pass-through mode and initiate beating of $PTNTS,B
+ * message, which can subsequently be detected as a trigger.
+ */
+ (void)isync_write(session, "@@@@\r\nMAW0C0B\r\n");
+
+ /* return serial port to original settings */
+ gpsd_set_speed(session, old_baudrate, old_parity, old_stopbits);
+
+ return false;
+}
+
+static void isync_event_hook(struct gps_device_t *session, event_t event)
+{
+ if (session->context->readonly)
+ return;
+
+ if (event == event_driver_switch) {
+ session->lexer.counter = 0;
+ }
+
+ if (event == event_configure) {
+ switch (session->lexer.counter) {
+ case 1:
+ /* Configure timing and frequency flags:
+ * - Thermal compensation active
+ * - PPSREF active
+ * - PPSOUT active
+ */
+ (void)isync_write(session, "MAW040B\r\n");
+ /* Configure tracking flags:
+ * - Save frequency every 24 hours
+ * - Align PPSOUT to PPSINT
+ * - Track PPSREF
+ */
+ (void)isync_write(session, "MAW0513\r\n");
+ /* Configure tracking start flags:
+ * - Tracking restart allowed
+ * - Align to PPSREF
+ */
+ (void)isync_write(session, "MAW0606\r\n");
+ /* Configure tracking window:
+ * - 4us
+ */
+ (void)isync_write(session, "MAW1304\r\n");
+ /* Configure alarm window:
+ * - 4us
+ */
+ (void)isync_write(session, "MAW1404\r\n");
+ break;
+ case 2:
+ /* Configure pulse every d second:
+ * - pulse every second
+ */
+ (void)isync_write(session, "MAW1701\r\n");
+ /* Configure pulse origin:
+ * - zero offset
+ */
+ (void)isync_write(session, "MAW1800\r\n");
+ /* Configure pulse width:
+ * - 600ms
+ */
+ (void)isync_write(session, "MAW1223C34600\r\n");
+ break;
+ case 3:
+ /* Configure GPS resource utilization:
+ * - do not consider GPS messages
+ */
+ (void)isync_write(session, "MAW2200\r\n");
+ /* Restart sync */
+ (void)isync_write(session, "SY1\r\n");
+ /* Restart tracking */
+ (void)isync_write(session, "TR1\r\n");
+ break;
+ case 4:
+ /* Cancel BTx messages (if any) */
+ (void)isync_write(session, "BT0\r\n");
+ /* Configure messages coming out every second:
+ * - Oscillator status ($PTNTA) at 750ms
+ */
+ (void)isync_write(session, "MAW0B00\r\n");
+ (void)isync_write(session, "MAW0C0A\r\n");
+ break;
+ case 5:
+ /* Enable GPS passthrough and force u-blox driver to
+ * select NMEA mode.
+ */
+ session->mode = 0;
+ session->drivers_identified = 0;
+ (void)isync_write(session, "@@@@GPS\r\n");
+ break;
+ case 6:
+ /* Trigger detection of underlying u-blox (if necessary) */
+ (void)ubx_write(session, 0x06, 0x00, NULL, 0);
+ break;
+ }
+ }
+}
+
+/* *INDENT-OFF* */
+const struct gps_type_t driver_isync = {
+ .type_name = "iSync", /* full name of type */
+ .packet_type = NMEA_PACKET, /* associated lexer packet type */
+ .flags = DRIVER_STICKY, /* remember this */
+ .trigger = "$PTNTS,B,", /* iSync status message */
+ .channels = 50, /* copied from driver_ubx */
+ .probe_detect = isync_detect, /* how to detect at startup time */
+ .get_packet = generic_get, /* how to get a packet */
+ .parse_packet = generic_parse_input, /* how to interpret a packet */
+ .init_query = NULL, /* non-perturbing initial query */
+ .event_hook = isync_event_hook, /* lifetime event handler */
+#ifdef RECONFIGURE_ENABLE
+ .speed_switcher = NULL, /* no speed switcher */
+ .mode_switcher = NULL, /* no mode switcher */
+ .rate_switcher = NULL, /* no sample-rate switcher */
+ .min_cycle = 1, /* not relevant, no rate switch */
+#endif /* RECONFIGURE_ENABLE */
+#ifdef CONTROLSEND_ENABLE
+ .control_send = nmea_write, /* how to send control strings */
+#endif /* CONTROLSEND_ENABLE */
+#ifdef TIMEHINT_ENABLE
+ .time_offset = NULL, /* no method for NTP fudge factor */
+#endif /* TIMEHINT_ENABLE */
+};
+/* *INDENT-ON* */
+#endif /* ISYNC_ENABLE */
+
#ifdef AIVDM_ENABLE
/**************************************************************************
*
@@ -1626,6 +1793,9 @@ static const struct gps_type_t *gpsd_driver_array[] = {
#ifdef TSIP_ENABLE
&driver_tsip,
#endif /* TSIP_ENABLE */
+#ifdef ISYNC_ENABLE
+ &driver_isync,
+#endif /* ISYNC_ENABLE */
#ifdef UBLOX_ENABLE
&driver_ubx,
#endif /* UBLOX_ENABLE */