summaryrefslogtreecommitdiff
path: root/driver_sirf.c
diff options
context:
space:
mode:
Diffstat (limited to 'driver_sirf.c')
-rw-r--r--driver_sirf.c1037
1 files changed, 1037 insertions, 0 deletions
diff --git a/driver_sirf.c b/driver_sirf.c
new file mode 100644
index 00000000..dfd184c8
--- /dev/null
+++ b/driver_sirf.c
@@ -0,0 +1,1037 @@
+/* $Id$ */
+/*
+ * This is the gpsd driver for SiRF GPSes operating in binary mode.
+ * It also handles uBlox, a SiRF derivative.
+ *
+ * The advantage: Reports climb/sink rate (raw-mode clients won't see this).
+ * The disadvantages: Doesn't return PDOP or VDOP, just HDOP.
+ *
+ * Chris Kuethe, our SiRF expert, tells us:
+ *
+ * "I don't see any indication in any of my material that PDOP, GDOP
+ * or VDOP are output. There are quantities called Estimated
+ * {Horizontal Position, Vertical Position, Time, Horizonal Velocity}
+ * Error, but those are apparently only valid when SiRFDRive is
+ * active."
+ *
+ * "(SiRFdrive is their Dead Reckoning augmented firmware. It
+ * allows you to feed odometer ticks, gyro and possibly
+ * accelerometer inputs to the chip to allow it to continue
+ * to navigate in the absence of satellite information, and
+ * to improve fixes when you do have satellites.)"
+ *
+ * "[When we need RINEX data, we can get it from] SiRF Message #5.
+ * If it's no longer implemented on your receiver, messages
+ * 7, 28, 29 and 30 will give you the same information."
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <time.h>
+#include <stdio.h>
+
+#include "gpsd_config.h"
+#include "gpsd.h"
+#include "bits.h"
+#if defined(SIRF_ENABLE) && defined(BINARY_ENABLE)
+
+#define HI(n) ((n) >> 8)
+#define LO(n) ((n) & 0xff)
+
+#ifdef ALLOW_RECONFIGURE
+/*@ +charint @*/
+static unsigned char enablesubframe[] = {0xa0, 0xa2, 0x00, 0x19,
+ 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0C,
+ 0x10,
+ 0x00, 0x00, 0xb0, 0xb3};
+
+static unsigned char disablesubframe[] = {0xa0, 0xa2, 0x00, 0x19,
+ 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0C,
+ 0x00,
+ 0x00, 0x00, 0xb0, 0xb3};
+
+static unsigned char modecontrol[] = {0xa0, 0xa2, 0x00, 0x0e,
+ 0x88,
+ 0x00, 0x00, /* pad bytes */
+ 0x00, /* degraded mode off */
+ 0x00, 0x00, /* pad bytes */
+ 0x00, 0x00, /* altitude */
+ 0x00, /* altitude hold auto */
+ 0x00, /* use last computed alt */
+ 0x00, /* reserved */
+ 0x00, /* disable degraded mode */
+ 0x00, /* disable dead reckoning */
+ 0x01, /* enable track smoothing */
+ 0x00, 0x00, 0xb0, 0xb3};
+
+static unsigned char enablemid52[] = {
+ 0xa0, 0xa2, 0x00, 0x08,
+ 0xa6, 0x00, 0x34, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xdb, 0xb0, 0xb3};
+/*@ -charint @*/
+#endif /* ALLOW_RECONFIGURE */
+
+
+static gps_mask_t sirf_msg_debug(unsigned char *, size_t );
+static gps_mask_t sirf_msg_errors(unsigned char *, size_t );
+
+static gps_mask_t sirf_msg_swversion(struct gps_device_t *, unsigned char *, size_t );
+static gps_mask_t sirf_msg_navdata(struct gps_device_t *, unsigned char *, size_t );
+static gps_mask_t sirf_msg_svinfo(struct gps_device_t *, unsigned char *, size_t );
+static gps_mask_t sirf_msg_navsol(struct gps_device_t *, unsigned char *, size_t );
+static gps_mask_t sirf_msg_geodetic(struct gps_device_t *, unsigned char *, size_t );
+static gps_mask_t sirf_msg_sysparam(struct gps_device_t *, unsigned char *, size_t );
+static gps_mask_t sirf_msg_ublox(struct gps_device_t *, unsigned char *, size_t );
+static gps_mask_t sirf_msg_ppstime(struct gps_device_t *, unsigned char *, size_t );
+
+
+bool sirf_write(int fd, unsigned char *msg) {
+ unsigned int crc;
+ size_t i, len;
+ bool ok;
+
+ len = (size_t)((msg[2] << 8) | msg[3]);
+
+ /* calculate CRC */
+ crc = 0;
+ for (i = 0; i < len; i++)
+ crc += (int)msg[4 + i];
+ crc &= 0x7fff;
+
+ /* enter CRC after payload */
+ msg[len + 4] = (unsigned char)((crc & 0xff00) >> 8);
+ msg[len + 5] = (unsigned char)( crc & 0x00ff);
+
+ gpsd_report(LOG_IO, "Writing SiRF control type %02x:%s\n", msg[4],
+ gpsd_hexdump_wrapper(msg, len+8, LOG_IO));
+ ok = (write(fd, msg, len+8) == (ssize_t)(len+8));
+ (void)tcdrain(fd);
+ return(ok);
+}
+
+static ssize_t sirf_control_send(struct gps_device_t *session, char *msg, size_t len) {
+ /*@ +charint +matchanyintegral -initallelements -mayaliasunique @*/
+ session->msgbuf[0] = 0xa0;
+ session->msgbuf[1] = 0xa2;
+ session->msgbuf[2] = (len >> 8) & 0xff;
+ session->msgbuf[3] = len & 0xff;
+ memcpy(session->msgbuf+4, msg, len);
+ session->msgbuf[len + 6] = 0xb0;
+ session->msgbuf[len + 7] = 0xb3;
+ session->msgbuflen = len + 8;
+
+ return sirf_write(session->gpsdata.gps_fd,
+ (unsigned char *)session->msgbuf) ? session->msgbuflen : -1;
+ /*@ -charint -matchanyintegral +initallelements +mayaliasunique @*/
+}
+
+static bool sirf_speed(int ttyfd, speed_t speed, char parity, int stopbits)
+/* change speed in binary mode */
+{
+ /*@ +charint @*/
+ static unsigned char msg[] = {0xa0, 0xa2, 0x00, 0x09,
+ 0x86, /* byte 4: main serial port */
+ 0x00, 0x00, 0x12, 0xc0, /* bytes 5-8: 4800 bps */
+ 0x08, /* byte 9: 8 data bits */
+ 0x01, /* byte 10: 1 stop bit */
+ 0x00, /* byte 11: no parity */
+ 0x00, /* byte 12: reserved pad */
+ 0x00, 0x00, 0xb0, 0xb3};
+ /*@ -charint @*/
+
+ switch (parity) {
+ case 'E':
+ case 2:
+ parity = (char)2;
+ break;
+ case 'O':
+ case 1:
+ parity = (char)1;
+ break;
+ case 'N':
+ case 0:
+ default:
+ parity = (char)0;
+ break;
+ }
+ msg[7] = (unsigned char)HI(speed);
+ msg[8] = (unsigned char)LO(speed);
+ msg[10] = (unsigned char)stopbits;
+ msg[11] = (unsigned char)parity;
+ return (sirf_write(ttyfd, msg));
+}
+
+static bool sirf_to_nmea(int ttyfd, speed_t speed)
+/* switch from binary to NMEA at specified baud */
+{
+ /*@ +charint @*/
+ static unsigned char msg[] = {0xa0, 0xa2, 0x00, 0x18,
+ 0x81, 0x02,
+ 0x01, 0x01, /* GGA */
+ 0x00, 0x00, /* suppress GLL */
+ 0x01, 0x01, /* GSA */
+ 0x05, 0x01, /* GSV */
+ 0x01, 0x01, /* RMC */
+ 0x00, 0x00, /* suppress VTG */
+ 0x00, 0x01, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x01,
+ 0x12, 0xc0, /* 4800 bps */
+ 0x00, 0x00, 0xb0, 0xb3};
+ /*@ -charint @*/
+
+ msg[26] = (unsigned char)HI(speed);
+ msg[27] = (unsigned char)LO(speed);
+ return (sirf_write(ttyfd, msg));
+}
+
+static void sirfbin_mode(struct gps_device_t *session, int mode)
+{
+ if (mode == MODE_NMEA) {
+ (void)sirf_to_nmea(session->gpsdata.gps_fd,session->gpsdata.baudrate);
+ } else {
+ session->back_to_nmea = false;
+ }
+}
+
+static ssize_t sirf_get(struct gps_device_t *session)
+{
+ ssize_t len = generic_get(session);
+
+ if (session->packet.type == SIRF_PACKET) {
+ session->gpsdata.driver_mode = MODE_BINARY;
+ } else if (session->packet.type == NMEA_PACKET) {
+ session->gpsdata.driver_mode = MODE_NMEA;
+ (void)gpsd_switch_driver(session, "Generic NMEA");
+ } else {
+ /* should never happen */
+ gpsd_report(LOG_PROG, "Unexpected packet type %d\n",
+ session->packet.type);
+ (void)gpsd_switch_driver(session, "Generic NMEA");
+ }
+
+ return len;
+}
+
+static gps_mask_t sirf_msg_debug(unsigned char *buf, size_t len)
+{
+ char msgbuf[MAX_PACKET_LENGTH*3 + 2];
+ int i;
+
+ bzero(msgbuf, (int)sizeof(msgbuf));
+
+ /*@ +charint @*/
+ if (0xe1 == buf[0]) { /* Development statistics messages */
+ for (i = 2; i < (int)len; i++)
+ (void)snprintf(msgbuf+strlen(msgbuf),
+ sizeof(msgbuf)-strlen(msgbuf),
+ "%c", buf[i]^0xff);
+ gpsd_report(LOG_PROG, "DEV 0xe1: %s\n", msgbuf);
+ } else if (0xff == (unsigned char)buf[0]) { /* Debug messages */
+ for (i = 1; i < (int)len; i++)
+ if (isprint(buf[i]))
+ (void)snprintf(msgbuf+strlen(msgbuf),
+ sizeof(msgbuf)-strlen(msgbuf),
+ "%c", buf[i]);
+ else
+ (void)snprintf(msgbuf+strlen(msgbuf),
+ sizeof(msgbuf)-strlen(msgbuf),
+ "\\x%02x", (unsigned int)buf[i]);
+ gpsd_report(LOG_PROG, "DBG 0xff: %s\n", msgbuf);
+ }
+ /*@ -charint @*/
+ return 0;
+}
+
+static gps_mask_t sirf_msg_errors(unsigned char *buf, size_t len UNUSED)
+{
+ switch (getbeuw(buf, 1)) {
+ case 2:
+ gpsd_report(LOG_PROG, "EID 0x0a type 2: Subframe %u error on PRN %u\n", getbeul(buf, 9), getbeul(buf, 5));
+ break;
+
+ case 4107:
+ gpsd_report(LOG_PROG, "EID 0x0a type 4107: neither KF nor LSQ fix.\n");
+ break;
+
+ default:
+ gpsd_report(LOG_PROG, "EID 0x0a: Error ID type %d\n", getbeuw(buf, 1));
+ break;
+ }
+ return 0;
+}
+
+static gps_mask_t sirf_msg_swversion(struct gps_device_t *session, unsigned char *buf, size_t len)
+{
+ double fv;
+
+ if (len < 20)
+ return 0;
+
+ gpsd_report(LOG_INF, "FV 0x06: Firmware version: %s\n", buf+1);
+ (void)strlcpy(session->subtype, (char *)buf+1, sizeof(session->subtype));
+ fv = atof((char *)(buf+1));
+ if (fv < 231) {
+ session->driver.sirf.driverstate |= SIRF_LT_231;
+ if (fv > 200)
+ sirfbin_mode(session, 0);
+ } else if (fv < 232) {
+ session->driver.sirf.driverstate |= SIRF_EQ_231;
+ } else {
+#ifdef ALLOW_RECONFIGURE
+ gpsd_report(LOG_PROG, "Enabling PPS message...\n");
+ (void)sirf_write(session->gpsdata.gps_fd, enablemid52);
+#endif /* ALLOW_RECONFIGURE */
+ session->driver.sirf.driverstate |= SIRF_GE_232;
+ session->context->valid |= LEAP_SECOND_VALID;
+ }
+ if (strstr((char *)(buf+1), "ES"))
+ gpsd_report(LOG_INF, "Firmware has XTrac capability\n");
+ gpsd_report(LOG_PROG, "Driver state flags are: %0x\n", session->driver.sirf.driverstate);
+#ifdef NTPSHM_ENABLE
+ session->driver.sirf.time_seen = 0;
+#endif /* NTPSHM_ENABLE */
+#ifdef ALLOW_RECONFIGURE
+ if (session->gpsdata.baudrate >= 38400){
+ gpsd_report(LOG_PROG, "Enabling subframe transmission...\n");
+ (void)sirf_write(session->gpsdata.gps_fd, enablesubframe);
+ }
+#endif /* ALLOW_RECONFIGURE */
+ return DEVICEID_SET;
+}
+
+static gps_mask_t sirf_msg_navdata(struct gps_device_t *session, unsigned char *buf, size_t len)
+{
+ unsigned int words[10];
+
+ if (len != 43)
+ return 0;
+
+ //unsigned int chan = (unsigned int)getub(buf, 1);
+ //unsigned int svid = (unsigned int)getub(buf, 2);
+ words[0] = (unsigned int)getbeul(buf, 3);
+ words[1] = (unsigned int)getbeul(buf, 7);
+ words[2] = (unsigned int)getbeul(buf, 11);
+ words[3] = (unsigned int)getbeul(buf, 15);
+ words[4] = (unsigned int)getbeul(buf, 19);
+ words[5] = (unsigned int)getbeul(buf, 23);
+ words[6] = (unsigned int)getbeul(buf, 27);
+ words[7] = (unsigned int)getbeul(buf, 31);
+ words[8] = (unsigned int)getbeul(buf, 35);
+ words[9] = (unsigned int)getbeul(buf, 39);
+ gpsd_report(LOG_PROG, "50B 0x08\n");
+ gpsd_interpret_subframe(session, words);
+
+#ifdef ALLOW_RECONFIGURE
+ if (session->gpsdata.baudrate < 38400){
+ gpsd_report(LOG_PROG, "Disabling subframe transmission...\n");
+ (void)sirf_write(session->gpsdata.gps_fd, disablesubframe);
+ }
+#endif /* ALLOW_RECONFIGURE */
+ return 0;
+}
+
+static gps_mask_t sirf_msg_svinfo(struct gps_device_t *session, unsigned char *buf, size_t len)
+{
+ int st, i, j, cn;
+
+ if (len != 188)
+ return 0;
+
+ gpsd_zero_satellites(&session->gpsdata);
+ session->gpsdata.sentence_time
+ = gpstime_to_unix(getbesw(buf, 1), getbeul(buf, 3)*1e-2) - session->context->leap_seconds;
+ for (i = st = 0; i < SIRF_CHANNELS; i++) {
+ int off = 8 + 15 * i;
+ bool good;
+ session->gpsdata.PRN[st] = (int)getub(buf, off);
+ session->gpsdata.azimuth[st] = (int)(((unsigned)getub(buf, off+1)*3)/2.0);
+ session->gpsdata.elevation[st] = (int)((unsigned)getub(buf, off+2)/2.0);
+ cn = 0;
+ for (j = 0; j < 10; j++)
+ cn += (int)getub(buf, off+5+j);
+
+ session->gpsdata.ss[st] = cn/10;
+ good = session->gpsdata.PRN[st]!=0 &&
+ session->gpsdata.azimuth[st]!=0 &&
+ session->gpsdata.elevation[st]!=0;
+#ifdef __UNUSED__
+ gpsd_report(LOG_PROG, "PRN=%2d El=%3.2f Az=%3.2f ss=%3d stat=%04x %c\n",
+ getub(buf, off),
+ getub(buf, off+2)/2.0,
+ (getub(buf, off+1)*3)/2.0,
+ cn/10,
+ getbeuw(buf, off+3),
+ good ? '*' : ' ');
+#endif /* UNUSED */
+ if (good!=0)
+ st += 1;
+ }
+ session->gpsdata.satellites = st;
+#ifdef NTPSHM_ENABLE
+ if (st > 3) {
+ if ((session->driver.sirf.time_seen & TIME_SEEN_GPS_1)==0)
+ gpsd_report(LOG_PROG, "valid time in message 0x04, seen=0x%02x\n",
+ session->driver.sirf.time_seen);
+ session->driver.sirf.time_seen |= TIME_SEEN_GPS_1;
+ if (session->context->enable_ntpshm && IS_HIGHEST_BIT(session->driver.sirf.time_seen,TIME_SEEN_GPS_1))
+ (void)ntpshm_put(session,session->gpsdata.sentence_time+0.8);
+ }
+#endif /* NTPSHM_ENABLE */
+ /*
+ * The freaking brain-dead SiRF chip doesn't obey its own
+ * rate-control command for 04, at least at firmware rev. 231,
+ * so we have to do our own rate-limiting here...
+ */
+ gpsd_report(LOG_PROG, "MTD 0x04: %d satellites\n", st);
+ if ((session->driver.sirf.satcounter++ % 5) != 0)
+ return 0;
+ else
+ return TIME_SET | SATELLITE_SET;
+}
+
+static gps_mask_t sirf_msg_navsol(struct gps_device_t *session, unsigned char *buf, size_t len)
+{
+ int i;
+ unsigned short navtype;
+ gps_mask_t mask = 0;
+
+ if (len != 41)
+ return 0;
+
+ session->gpsdata.satellites_used = (int)getub(buf, 28);
+ memset(session->gpsdata.used,0,sizeof(session->gpsdata.used));
+ for (i = 0; i < SIRF_CHANNELS; i++)
+ session->gpsdata.used[i] = (int)getub(buf, 29+i);
+ if ((session->driver.sirf.driverstate & (SIRF_GE_232 | UBLOX))==0) {
+ /* position/velocity is bytes 1-18 */
+ ecef_to_wgs84fix(&session->gpsdata,
+ getbesl(buf, 1)*1.0, getbesl(buf, 5)*1.0, getbesl(buf, 9)*1.0,
+ getbesw(buf, 13)/8.0, getbesw(buf, 15)/8.0, getbesw(buf, 17)/8.0);
+ /* fix status is byte 19 */
+ navtype = (unsigned short)getub(buf, 19);
+ session->gpsdata.status = STATUS_NO_FIX;
+ session->gpsdata.fix.mode = MODE_NO_FIX;
+ if ((navtype & 0x80) != 0)
+ session->gpsdata.status = STATUS_DGPS_FIX;
+ else if ((navtype & 0x07) > 0 && (navtype & 0x07) < 7)
+ session->gpsdata.status = STATUS_FIX;
+ if ((navtype & 0x07) == 4 || (navtype & 0x07) == 6)
+ session->gpsdata.fix.mode = MODE_3D;
+ else if (session->gpsdata.status != 0)
+ session->gpsdata.fix.mode = MODE_2D;
+ if (session->gpsdata.fix.mode == MODE_3D)
+ mask |= ALTITUDE_SET | CLIMB_SET;
+ gpsd_report(LOG_PROG, "MND 0x02: Navtype = 0x%0x, Status = %d, mode = %d\n",
+ navtype,session->gpsdata.status,session->gpsdata.fix.mode);
+ /* byte 20 is HDOP, see below */
+ /* byte 21 is "mode 2", not clear how to interpret that */
+ session->gpsdata.fix.time = session->gpsdata.sentence_time =
+ gpstime_to_unix(getbesw(buf, 22), getbeul(buf, 24)*1e-2) -
+ session->context->leap_seconds;
+#ifdef NTPSHM_ENABLE
+ if (session->gpsdata.fix.mode > MODE_NO_FIX) {
+ if ((session->driver.sirf.time_seen & TIME_SEEN_GPS_2) == 0)
+ gpsd_report(LOG_PROG, "valid time in message 0x02, seen=0x%02x\n",
+ session->driver.sirf.time_seen);
+ session->driver.sirf.time_seen |= TIME_SEEN_GPS_2;
+ if (session->context->enable_ntpshm && IS_HIGHEST_BIT(session->driver.sirf.time_seen,TIME_SEEN_GPS_2))
+ (void)ntpshm_put(session, session->gpsdata.fix.time + 0.8);
+ }
+#endif /* NTPSHM_ENABLE */
+ /* fix quality data */
+ session->gpsdata.hdop = (double)getub(buf, 20)/5.0;
+ mask |= TIME_SET | LATLON_SET | TRACK_SET | SPEED_SET | STATUS_SET | MODE_SET | HDOP_SET | USED_SET | CYCLE_START_SET;
+ }
+ return mask;
+}
+
+static gps_mask_t sirf_msg_geodetic(struct gps_device_t *session, unsigned char *buf, size_t len)
+{
+ unsigned short navtype;
+ gps_mask_t mask = 0;
+
+ if (len != 91)
+ return 0;
+
+ session->gpsdata.sentence_length = 91;
+ (void)strlcpy(session->gpsdata.tag, "GND",MAXTAGLEN+1);
+
+ navtype = (unsigned short)getbeuw(buf, 3);
+ session->gpsdata.status = STATUS_NO_FIX;
+ session->gpsdata.fix.mode = MODE_NO_FIX;
+ if (navtype & 0x80)
+ session->gpsdata.status = STATUS_DGPS_FIX;
+ else if ((navtype & 0x07) > 0 && (navtype & 0x07) < 7)
+ session->gpsdata.status = STATUS_FIX;
+ session->gpsdata.fix.mode = MODE_NO_FIX;
+ if ((navtype & 0x07) == 4 || (navtype & 0x07) == 6)
+ session->gpsdata.fix.mode = MODE_3D;
+ else if (session->gpsdata.status)
+ session->gpsdata.fix.mode = MODE_2D;
+ gpsd_report(LOG_PROG, "GND 0x29: Navtype = 0x%0x, Status = %d, mode = %d\n",
+ navtype, session->gpsdata.status, session->gpsdata.fix.mode);
+ mask |= STATUS_SET | MODE_SET;
+
+ session->gpsdata.fix.latitude = getbesl(buf, 23)*1e-7;
+ session->gpsdata.fix.longitude = getbesl(buf, 27)*1e-7;
+ if (session->gpsdata.fix.latitude!=0 && session->gpsdata.fix.latitude!=0)
+ mask |= LATLON_SET;
+
+ if ((session->gpsdata.fix.eph = getbesl(buf, 50)*1e-2) > 0)
+ mask |= HERR_SET;
+ if ((session->gpsdata.fix.epv = getbesl(buf, 54)*1e-2) > 0)
+ mask |= VERR_SET;
+ if ((session->gpsdata.fix.eps = getbesw(buf, 62)*1e-2) > 0)
+ mask |= SPEEDERR_SET;
+
+ /* HDOP should be available at byte 89, but in 231 it's zero. */
+ if ((session->gpsdata.hdop = (unsigned int)getub(buf, 89) * 0.2) > 0)
+ mask |= HDOP_SET;
+
+ if (session->driver.sirf.driverstate & SIRF_GE_232) {
+ struct tm unpacked_date;
+ double subseconds;
+ /*
+ * Many versions of the SiRF protocol manual don't document
+ * this sentence at all. Those that do may incorrectly
+ * describe UTC Day, Hour, and Minute as 2-byte quantities,
+ * not 1-byte. Chris Kuethe, our SiRF expert, tells us:
+ *
+ * "The Geodetic Navigation packet (0x29) was not fully
+ * implemented in firmware prior to version 2.3.2. So for
+ * anyone running 231.000.000 or earlier (including ES,
+ * SiRFDRive, XTrac trains) you won't get UTC time. I don't
+ * know what's broken in firmwares before 2.3.1..."
+ *
+ * To work around the incomplete implementation of this
+ * packet in 231, we used to assume that only the altitude field
+ * from this packet is valid. But even this doesn't necessarily
+ * seem to be the case. Instead, we do our own computation
+ * of geoid separation now.
+ *
+ * UTC is left all zeros in 231 and older firmware versions,
+ * and misdocumented in the Protocol Reference (version 1.4).
+ * Documented: Real:
+ * UTC year 2 2
+ * UTC month 1 1
+ * UTC day 2 1
+ * UTC hour 2 1
+ * UTC minute 2 1
+ * UTC second 2 2
+ * 11 8
+ */
+ unpacked_date.tm_year = (int)getbeuw(buf, 11)-1900;
+ unpacked_date.tm_mon = (int)getub(buf, 13)-1;
+ unpacked_date.tm_mday = (int)getub(buf, 14);
+ unpacked_date.tm_hour = (int)getub(buf, 15);
+ unpacked_date.tm_min = (int)getub(buf, 16);
+ unpacked_date.tm_sec = 0;
+ subseconds = getbeuw(buf, 17)*1e-3;
+ /*@ -compdef -unrecog */
+ session->gpsdata.fix.time = session->gpsdata.sentence_time =
+ (double)timegm(&unpacked_date)+subseconds;
+ /*@ +compdef +unrecog */
+ gpsd_report(LOG_PROG, "MID 41 UTC: %lf\n", session->gpsdata.fix.time);
+#ifdef NTPSHM_ENABLE
+ if (session->gpsdata.fix.mode > MODE_NO_FIX && unpacked_date.tm_year != 0) {
+ if ((session->driver.sirf.time_seen & TIME_SEEN_UTC_1) == 0)
+ gpsd_report(LOG_PROG, "valid time in message 0x29, seen=0x%02x\n",
+ session->driver.sirf.time_seen);
+ session->driver.sirf.time_seen |= TIME_SEEN_UTC_1;
+ if (session->context->enable_ntpshm && IS_HIGHEST_BIT(session->driver.sirf.time_seen,TIME_SEEN_UTC_1))
+ (void)ntpshm_put(session, session->gpsdata.fix.time + 0.8);
+ }
+#endif /* NTPSHM_ENABLE */
+ /* skip 4 bytes of satellite map */
+ session->gpsdata.fix.altitude = getbesl(buf, 35)*1e-2;
+ /* skip 1 byte of map datum */
+ session->gpsdata.fix.speed = getbesw(buf, 40)*1e-2;
+ session->gpsdata.fix.track = getbesw(buf, 42)*1e-2;
+ /* skip 2 bytes of magnetic variation */
+ session->gpsdata.fix.climb = getbesw(buf, 46)*1e-2;
+ mask |= TIME_SET | SPEED_SET | TRACK_SET;
+ if (session->gpsdata.fix.mode == MODE_3D)
+ mask |= ALTITUDE_SET | CLIMB_SET;
+ }
+ return mask;
+}
+
+static gps_mask_t sirf_msg_sysparam(struct gps_device_t *session, unsigned char *buf, size_t len)
+{
+
+ if (len != 65)
+ return 0;
+
+#ifdef ALLOW_RECONFIGURE
+ /* save these to restore them in the revert method */
+ session->driver.sirf.nav_parameters_seen = true;
+ session->driver.sirf.altitude_hold_mode = getub(buf, 5);
+ session->driver.sirf.altitude_hold_source = getub(buf, 6);
+ session->driver.sirf.altitude_source_input = getbesw(buf, 7);
+ session->driver.sirf.degraded_mode = getub(buf, 9);
+ session->driver.sirf.degraded_timeout = getub(buf, 10);
+ session->driver.sirf.dr_timeout = getub(buf, 11);
+ session->driver.sirf.track_smooth_mode = getub(buf, 12);
+ gpsd_report(LOG_PROG, "Setting Navigation Parameters\n");
+ (void)sirf_write(session->gpsdata.gps_fd, modecontrol);
+#endif /* ALLOW_RECONFIGURE */
+ return 0;
+}
+
+static gps_mask_t sirf_msg_ublox(struct gps_device_t *session, unsigned char *buf, size_t len UNUSED)
+{
+ gps_mask_t mask;
+ unsigned short navtype;
+
+ if (len != 39)
+ return 0;
+
+ /* this packet is only sent by uBlox firmware from version 1.32 */
+ mask = LATLON_SET | ALTITUDE_SET | SPEED_SET | TRACK_SET | CLIMB_SET |
+ STATUS_SET | MODE_SET | HDOP_SET | VDOP_SET | PDOP_SET;
+ session->gpsdata.fix.latitude = getbesl(buf, 1) * RAD_2_DEG * 1e-8;
+ session->gpsdata.fix.longitude = getbesl(buf, 5) * RAD_2_DEG * 1e-8;
+ session->gpsdata.separation = wgs84_separation(session->gpsdata.fix.latitude, session->gpsdata.fix.longitude);
+ session->gpsdata.fix.altitude = getbesl(buf, 9) * 1e-3 - session->gpsdata.separation;
+ session->gpsdata.fix.speed = getbesl(buf, 13) * 1e-3;
+ session->gpsdata.fix.climb = getbesl(buf, 17) * 1e-3;
+ session->gpsdata.fix.track = getbesl(buf, 21) * RAD_2_DEG * 1e-8;
+
+ navtype = (unsigned short)getub(buf, 25);
+ session->gpsdata.status = STATUS_NO_FIX;
+ session->gpsdata.fix.mode = MODE_NO_FIX;
+ if (navtype & 0x80)
+ session->gpsdata.status = STATUS_DGPS_FIX;
+ else if ((navtype & 0x07) > 0 && (navtype & 0x07) < 7)
+ session->gpsdata.status = STATUS_FIX;
+ if ((navtype & 0x07) == 4 || (navtype & 0x07) == 6)
+ session->gpsdata.fix.mode = MODE_3D;
+ else if (session->gpsdata.status)
+ session->gpsdata.fix.mode = MODE_2D;
+ gpsd_report(LOG_PROG, "EMND 0x62: Navtype = 0x%0x, Status = %d, mode = %d\n",
+ navtype, session->gpsdata.status, session->gpsdata.fix.mode);
+
+ if (navtype & 0x40) { /* UTC corrected timestamp? */
+ struct tm unpacked_date;
+ double subseconds;
+ mask |= TIME_SET;
+ unpacked_date.tm_year = (int)getbeuw(buf, 26) - 1900;
+ unpacked_date.tm_mon = (int)getub(buf, 28) - 1;
+ unpacked_date.tm_mday = (int)getub(buf, 29);
+ unpacked_date.tm_hour = (int)getub(buf, 30);
+ unpacked_date.tm_min = (int)getub(buf, 31);
+ unpacked_date.tm_sec = 0;
+ subseconds = ((unsigned short)getbeuw(buf, 32))*1e-3;
+ /*@ -compdef */
+ session->gpsdata.fix.time = session->gpsdata.sentence_time =
+ (double)mkgmtime(&unpacked_date)+subseconds;
+ /*@ +compdef */
+#ifdef NTPSHM_ENABLE
+ if ((session->driver.sirf.time_seen & TIME_SEEN_UTC_2) == 0)
+ gpsd_report(LOG_PROG, "valid time in message 0x62, seen=0x%02x\n",
+ session->driver.sirf.time_seen);
+ session->driver.sirf.time_seen |= TIME_SEEN_UTC_2;
+ if (session->context->enable_ntpshm && IS_HIGHEST_BIT(session->driver.sirf.time_seen,TIME_SEEN_UTC_2))
+ (void)ntpshm_put(session, session->gpsdata.fix.time + 0.8);
+#endif /* NTPSHM_ENABLE */
+ session->context->valid |= LEAP_SECOND_VALID;
+ }
+
+ session->gpsdata.gdop = (int)getub(buf, 34) / 5.0;
+ session->gpsdata.pdop = (int)getub(buf, 35) / 5.0;
+ session->gpsdata.hdop = (int)getub(buf, 36) / 5.0;
+ session->gpsdata.vdop = (int)getub(buf, 37) / 5.0;
+ session->gpsdata.tdop = (int)getub(buf, 38) / 5.0;
+ session->driver.sirf.driverstate |= UBLOX;
+ return mask;
+}
+
+static gps_mask_t sirf_msg_ppstime(struct gps_device_t *session, unsigned char *buf, size_t len)
+{
+ gps_mask_t mask = 0;
+
+ if (len != 19)
+ return 0;
+
+ gpsd_report(LOG_PROG, "PPS 0x34: Status = 0x%02x\n", getub(buf, 14));
+ if (((int)getub(buf, 14) & 0x07) == 0x07) { /* valid UTC time? */
+ struct tm unpacked_date;
+ unpacked_date.tm_hour = (int)getub(buf, 1);
+ unpacked_date.tm_min = (int)getub(buf, 2);
+ unpacked_date.tm_sec = (int)getub(buf, 3);
+ unpacked_date.tm_mday = (int)getub(buf, 4);
+ unpacked_date.tm_mon = (int)getub(buf, 5) - 1;
+ unpacked_date.tm_year = (int)getbeuw(buf, 6) - 1900;
+ /*@ -compdef */
+ session->gpsdata.fix.time = session->gpsdata.sentence_time =
+ (double)mkgmtime(&unpacked_date);
+ /*@ +compdef */
+ session->context->leap_seconds = (int)getbeuw(buf, 8);
+ session->context->valid |= LEAP_SECOND_VALID;
+#ifdef NTPSHM_ENABLE
+ if ((session->driver.sirf.time_seen & TIME_SEEN_UTC_2) == 0)
+ gpsd_report(LOG_PROG, "valid time in message 0x34, seen=0x%02x\n",
+ session->driver.sirf.time_seen);
+ session->driver.sirf.time_seen |= TIME_SEEN_UTC_2;
+ if (session->context->enable_ntpshm && IS_HIGHEST_BIT(session->driver.sirf.time_seen,TIME_SEEN_UTC_2))
+ (void)ntpshm_put(session, session->gpsdata.fix.time + 0.3);
+#endif /* NTPSHM_ENABLE */
+ mask |= TIME_SET;
+ }
+ return mask;
+}
+
+gps_mask_t sirf_parse(struct gps_device_t *session, unsigned char *buf, size_t len)
+{
+
+ if (len == 0)
+ return 0;
+
+ buf += 4;
+ len -= 8;
+ gpsd_report(LOG_RAW, "Raw SiRF packet type 0x%02x length %zd: %s\n",
+ buf[0], len, gpsd_hexdump_wrapper(buf, len, LOG_RAW));
+ (void)snprintf(session->gpsdata.tag, sizeof(session->gpsdata.tag),
+ "MID%d",(int)buf[0]);
+
+ switch (buf[0])
+ {
+ case 0x02: /* Measure Navigation Data Out */
+ return sirf_msg_navsol(session, buf, len);
+
+ case 0x04: /* Measured tracker data out */
+ return sirf_msg_svinfo(session, buf, len);
+
+ case 0x05: /* Raw Tracker Data Out */
+ return 0;
+
+ case 0x06: /* Software Version String */
+ return sirf_msg_swversion(session, buf, len);
+
+ case 0x07: /* Clock Status Data */
+ gpsd_report(LOG_PROG, "CLK 0x07\n");
+ return 0;
+
+ case 0x08: /* subframe data -- extract leap-second from this */
+ /*
+ * Chris Kuethe says:
+ * "Message 8 is generated as the data is received. It is not
+ * buffered on the chip. So when you enable message 8, you'll
+ * get one subframe every 6 seconds. Of the data received, the
+ * almanac and ephemeris are buffered and stored, so you can
+ * query them at will. Alas, the time parameters are not
+ * stored, which is really lame, as the UTC-GPS correction
+ * changes 1 second every few years. Maybe."
+ */
+ return sirf_msg_navdata(session, buf, len);
+
+ case 0x09: /* CPU Throughput */
+ gpsd_report(LOG_PROG,
+ "THR 0x09: SegStatMax=%.3f, SegStatLat=%3.f, AveTrkTime=%.3f, Last MS=%u\n",
+ (float)getbeuw(buf, 1)/186, (float)getbeuw(buf, 3)/186,
+ (float)getbeuw(buf, 5)/186, getbeuw(buf, 7));
+ return 0;
+
+ case 0x0a: /* Error ID Data */
+ return sirf_msg_errors(buf, len);
+
+ case 0x0b: /* Command Acknowledgement */
+ gpsd_report(LOG_PROG, "ACK 0x0b: %02x\n",getub(buf, 1));
+ return 0;
+
+ case 0x0c: /* Command NAcknowledgement */
+ gpsd_report(LOG_PROG, "NAK 0x0c: %02x\n",getub(buf, 1));
+ return 0;
+
+ case 0x0d: /* Visible List */
+ gpsd_report(LOG_PROG, "VIS 0x0d\n");
+ return 0;
+
+ case 0x0e: /* Almanac Data */
+ gpsd_report(LOG_PROG, "ALM 0x0e: %s\n",
+ gpsd_hexdump_wrapper(buf, len, LOG_PROG));
+ return 0;
+
+ case 0x0f: /* Ephemeris Data */
+ gpsd_report(LOG_PROG, "EPH 0x0f: %s\n",
+ gpsd_hexdump_wrapper(buf, len, LOG_PROG));
+ return 0;
+
+ case 0x11: /* Differential Corrections */
+ gpsd_report(LOG_PROG, "DIFF 0x11: %s\n",
+ gpsd_hexdump_wrapper(buf, len, LOG_PROG));
+ return 0;
+
+ case 0x12: /* OK To Send */
+ gpsd_report(LOG_PROG, "OTS 0x12: send indicator = %d\n",getub(buf, 1));
+ return 0;
+
+#ifdef ALLOW_RECONFIGURE
+ case 0x13: /* Navigation Parameters */
+ return sirf_msg_sysparam(session, buf, len);
+#endif /* ALLOW_RECONFIGURE */
+
+ case 0x1b: /* DGPS status (undocumented) */
+ /******************************************************************
+ Not actually documented in any published materials.
+ Here is what Chris Kuethe got from the SiRF folks,
+ (plus some corrections from the GpsPaSsion forums):
+
+ Start of message
+ ----------------
+ Message ID 1 byte 27
+ Correction Source 1 byte 0=None, 1=SBAS, 2=Serial, 3=Beacon,
+ 4=Software
+
+ total: 2 bytes
+
+ Middle part of message varies if using beacon or other:
+ -------------------------------------------------------
+ If Beacon:
+ Receiver Freq Hz 4 bytes
+ Bit rate BPS 1 byte
+ Status bit map 1 byte 01=Signal Valid,
+ 02=Auto frequency detect
+ 04=Auto bit rate detect
+ Signal Magnitude 4 bytes Note: in internal units
+ Signal Strength dB 2 bytes derived from Signal Magnitude
+ SNR dB 2 bytes
+
+ total: 14 bytes
+
+ If Not Beacon:
+ Correction Age[12] 1 byte x 12 Age in seconds in same order as follows
+ Reserved 2 bytes
+
+ total: 14 bytes
+
+ End of Message
+ --------------
+ Repeated 12 times (pad with 0 if less than 12 SV corrections):
+ SVID 1 byte
+ Correction (cm) 2 bytes (signed short)
+
+ total 3 x 12 = 36 bytes
+ ******************************************************************/
+ return 0;
+
+ case 0x1c: /* Navigation Library Measurement Data */
+ gpsd_report(LOG_PROG, "NLMD 0x1c: %s\n",
+ gpsd_hexdump_wrapper(buf, len, LOG_PROG));
+ return 0;
+
+ case 0x1d: /* Navigation Library DGPS Data */
+ gpsd_report(LOG_PROG, "NLDG 0x1d: %s\n",
+ gpsd_hexdump_wrapper(buf, len, LOG_PROG));
+ return 0;
+
+ case 0x1e: /* Navigation Library SV State Data */
+ gpsd_report(LOG_PROG, "NLSV 0x1e: %s\n",
+ gpsd_hexdump_wrapper(buf, len, LOG_PROG));
+ return 0;
+
+ case 0x1f: /* Navigation Library Initialization Data */
+ gpsd_report(LOG_PROG, "NLID 0x1f: %s\n",
+ gpsd_hexdump_wrapper(buf, len, LOG_PROG));
+ return 0;
+
+ case 0x29: /* Geodetic Navigation Information */
+ return sirf_msg_geodetic(session, buf, len);
+
+ case 0x32: /* SBAS corrections */
+ return 0;
+
+ case 0x34: /* PPS Time */
+ /*
+ * Carl Carter from SiRF writes: "We do not output on the
+ * second (unless you are using message ID 52). We make
+ * measurements in the receiver in time with an internal
+ * counter that is not slaved to GPS time, so the measurements
+ * are made at a time that wanders around the second. Then,
+ * after the measurements are made (all normalized to the same
+ * point in time) we dispatch the navigation software to make
+ * a solution, and that solution comes out some 200 to 300 ms
+ * after the measurement time. So you may get a message at
+ * 700 ms after the second that uses measurements time tagged
+ * 450 ms after the second. And if some other task jumps up
+ * and delays things, that message may not come out until 900
+ * ms after the second. Things can get out of sync to the
+ * point that if you try to resolve the GPS time of our 1 PPS
+ * pulses using the navigation messages, you will find it
+ * impossible to be consistent. That is why I added message
+ * ID 52 to our system -- it is tied to the creation of the 1
+ * PPS and always comes out right around the top of the
+ * second."
+ */
+ return sirf_msg_ppstime(session, buf, len);
+
+ case 0x62: /* uBlox Extended Measured Navigation Data */
+ return sirf_msg_ublox(session, buf, len);
+
+ case 0x80: /* Initialize Data Source */
+ gpsd_report(LOG_PROG, "INIT 0x80: %s\n",
+ gpsd_hexdump_wrapper(buf, len, LOG_PROG));
+ return 0;
+
+ case 0xe1: /* Development statistics messages */
+ /* FALLTHROUGH */
+ case 0xff: /* Debug messages */
+ (void)sirf_msg_debug(buf, len);
+ return 0;
+
+ default:
+ gpsd_report(LOG_WARN, "Unknown SiRF packet id %d length %zd: %s\n",
+ buf[0], len, gpsd_hexdump_wrapper(buf, len, LOG_WARN));
+ return 0;
+ }
+}
+
+static gps_mask_t sirfbin_parse_input(struct gps_device_t *session)
+{
+ gps_mask_t st;
+
+ if (session->packet.type == SIRF_PACKET){
+ st = sirf_parse(session, session->packet.outbuffer,
+ session->packet.outbuflen);
+ session->gpsdata.driver_mode = MODE_BINARY;
+ return st;
+#ifdef NMEA_ENABLE
+ } else if (session->packet.type == NMEA_PACKET) {
+ st = nmea_parse((char *)session->packet.outbuffer, session);
+ session->gpsdata.driver_mode = MODE_NMEA;
+ return st;
+#endif /* NMEA_ENABLE */
+ } else
+ return 0;
+}
+
+#ifdef ALLOW_RECONFIGURE
+static void sirfbin_configure(struct gps_device_t *session, unsigned int seq)
+{
+ if (seq != 0)
+ return;
+ if (session->packet.type == NMEA_PACKET) {
+ gpsd_report(LOG_PROG, "Switching chip mode to SiRF binary.\n");
+ (void)nmea_send(session,
+ "$PSRF100,0,%d,8,1,0", session->gpsdata.baudrate);
+ }
+ /* do this every time*/
+ {
+ /*@ +charint @*/
+ static unsigned char navparams[] = {0xa0, 0xa2, 0x00, 0x02,
+ 0x98, 0x00,
+ 0x00, 0x00, 0xb0, 0xb3};
+ static unsigned char dgpscontrol[] = {0xa0, 0xa2, 0x00, 0x07,
+ 0x85, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xb0, 0xb3};
+ static unsigned char sbasparams[] = {0xa0, 0xa2, 0x00, 0x06,
+ 0xaa, 0x00, 0x01, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00, 0xb0, 0xb3};
+ static unsigned char versionprobe[] = {0xa0, 0xa2, 0x00, 0x02,
+ 0x84, 0x00,
+ 0x00, 0x00, 0xb0, 0xb3};
+ static unsigned char requestecef[] = {0xa0, 0xa2, 0x00, 0x08,
+ 0xa6, 0x00, 0x02, 0x01,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xb0, 0xb3};
+ static unsigned char requesttracker[] = {0xa0, 0xa2, 0x00, 0x08,
+ 0xa6, 0x00, 0x04, 0x03,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xb0, 0xb3};
+ /*@ -charint @*/
+ gpsd_report(LOG_PROG, "Requesting periodic ecef reports...\n");
+ (void)sirf_write(session->gpsdata.gps_fd, requestecef);
+ gpsd_report(LOG_PROG, "Requesting periodic tracker reports...\n");
+ (void)sirf_write(session->gpsdata.gps_fd, requesttracker);
+ gpsd_report(LOG_PROG, "Setting DGPS control to use SBAS...\n");
+ (void)sirf_write(session->gpsdata.gps_fd, dgpscontrol);
+ gpsd_report(LOG_PROG, "Setting SBAS to auto/integrity mode...\n");
+ (void)sirf_write(session->gpsdata.gps_fd, sbasparams);
+ gpsd_report(LOG_PROG, "Probing for firmware version...\n");
+ (void)sirf_write(session->gpsdata.gps_fd, versionprobe);
+ gpsd_report(LOG_PROG, "Requesting navigation parameters...\n");
+ (void)sirf_write(session->gpsdata.gps_fd, navparams);
+ }
+}
+
+static void sirfbin_revert(struct gps_device_t *session)
+{
+ /*@ +charint @*/
+ static unsigned char moderevert[] = {0xa0, 0xa2, 0x00, 0x0e,
+ 0x88,
+ 0x00, 0x00, /* pad bytes */
+ 0x00, /* degraded mode */
+ 0x00, 0x00, /* pad bytes */
+ 0x00, 0x00, /* altitude source */
+ 0x00, /* altitude hold mode */
+ 0x00, /* use last computed alt */
+ 0x00, /* reserved */
+ 0x00, /* degraded mode timeout */
+ 0x00, /* dead reckoning timeout */
+ 0x00, /* track smoothing */
+ 0x00, 0x00, 0xb0, 0xb3};
+ /*@ -charint -shiftimplementation @*/
+ putbyte(moderevert, 7, session->driver.sirf.degraded_mode);
+ putbeword(moderevert, 10, session->driver.sirf.altitude_source_input);
+ putbyte(moderevert, 12, session->driver.sirf.altitude_hold_mode);
+ putbyte(moderevert, 13, session->driver.sirf.altitude_hold_source);
+ putbyte(moderevert, 15, session->driver.sirf.degraded_timeout);
+ putbyte(moderevert, 16, session->driver.sirf.dr_timeout);
+ putbyte(moderevert, 17, session->driver.sirf.track_smooth_mode);
+ /*@ +shiftimplementation @*/
+ gpsd_report(LOG_PROG, "Reverting navigation parameters...\n");
+ (void)sirf_write(session->gpsdata.gps_fd, moderevert);
+}
+#endif /* ALLOW_RECONFIGURE */
+
+static bool sirfbin_speed(struct gps_device_t *session,
+ speed_t speed, char parity, int stopbits)
+{
+ return sirf_speed(session->gpsdata.gps_fd, speed, parity, stopbits);
+}
+
+/* this is everything we export */
+const struct gps_type_t sirf_binary =
+{
+ .type_name = "SiRF binary", /* full name of type */
+ .packet_type = SIRF_PACKET, /* associated lexer packet type */
+ .trigger = NULL, /* no trigger */
+ .channels = SIRF_CHANNELS, /* consumer-grade GPS */
+ .control_send = sirf_control_send,/* how to send a control string */
+ .probe_wakeup = NULL, /* no wakeup to be done before hunt */
+ .probe_detect = NULL, /* no probe */
+ .probe_subtype = NULL, /* can't probe more in NMEA mode */
+#ifdef ALLOW_RECONFIGURE
+ .configurator = sirfbin_configure,/* initialize the device */
+#endif /* ALLOW_RECONFIGURE */
+ .get_packet = sirf_get, /* be prepared for SiRF or NMEA */
+ .parse_packet = sirfbin_parse_input,/* parse message packets */
+ .rtcm_writer = pass_rtcm, /* send RTCM data straight */
+ .speed_switcher = sirfbin_speed, /* we can change baud rate */
+ .mode_switcher = sirfbin_mode, /* there's a mode switcher */
+ .rate_switcher = NULL, /* no sample-rate switcher */
+ .cycle_chars = -1, /* not relevant, no rate switch */
+#ifdef ALLOW_RECONFIGURE
+ .revert = sirfbin_revert, /* no reversion code */
+#endif /* ALLOW_RECONFIGURE */
+ .wrapup = NULL, /* no close hook */
+ .cycle = 1, /* updates every second */
+};
+#endif /* defined(SIRF_ENABLE) && defined(BINARY_ENABLE) */