From bf65d4033a451b1a274cbe1a59904e8300bf02dc Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 3 Feb 2016 22:40:26 +0000 Subject: 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 --- SConstruct | 1 + driver_ubx.c | 8 ++- drivers.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ test_packet.c | 5 -- 4 files changed, 174 insertions(+), 10 deletions(-) diff --git a/SConstruct b/SConstruct index d136306f..6f36ff21 100644 --- a/SConstruct +++ b/SConstruct @@ -124,6 +124,7 @@ boolopts = ( ("gpsclock", True, "GPSClock support"), ("ntrip", True, "NTRIP support"), ("oceanserver", True, "OceanServer support"), + ("isync", True, "Spectratime iSync LNRClok/GRCLOK support"), ("rtcm104v2", True, "rtcm104v2 support"), ("rtcm104v3", True, "rtcm104v3 support"), ("passthrough", True, "build support for passing through JSON"), diff --git a/driver_ubx.c b/driver_ubx.c index 41ff7092..d1d29f8e 100644 --- a/driver_ubx.c +++ b/driver_ubx.c @@ -633,12 +633,8 @@ static gps_mask_t parse_input(struct gps_device_t *session) if (session->lexer.type == UBX_PACKET) { return ubx_parse(session, session->lexer.outbuffer, session->lexer.outbuflen); -#ifdef NMEA0183_ENABLE - } else if (session->lexer.type == NMEA_PACKET) { - return nmea_parse((char *)session->lexer.outbuffer, session); -#endif /* NMEA0183_ENABLE */ } else - return 0; + return generic_parse_input(session); } bool ubx_write(struct gps_device_t * session, @@ -730,6 +726,8 @@ static void ubx_event_hook(struct gps_device_t *session, event_t event) */ if (session->mode == O_OPTIMIZE) { ubx_mode(session, MODE_BINARY); + } else { + ubx_mode(session, MODE_NMEA); } #endif /* RECONFIGURE_ENABLE */ } else if (event == event_deactivate) { 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 */ diff --git a/test_packet.c b/test_packet.c index 156dfe08..274d7d62 100644 --- a/test_packet.c +++ b/test_packet.c @@ -363,11 +363,6 @@ static int property_check(void) (*dp)->type_name); status = EXIT_FAILURE; } - if ((*dp)->probe_detect != NULL && (*dp)->trigger != NULL) { - (void)fprintf(stderr, "%s both a probe and a trigger string\n", - (*dp)->type_name); - status = EXIT_FAILURE; - } #endif /* CONTROLSEND_ENABLE && RECONFIGURE_ENABLE*/ } -- cgit v1.2.1