cleanup specfile for packaging
[profile/ivi/gpsd.git] / driver_sirf.c
1 /*
2  * This is the gpsd driver for SiRF GPSes operating in binary mode.
3  * It also handles uBlox, a SiRF derivative.
4  *
5  * The advantage: Reports climb/sink rate (raw-mode clients won't see this).
6  * The disadvantages: Doesn't return PDOP or VDOP, just HDOP.
7  *
8  * Chris Kuethe, our SiRF expert, tells us:
9  *
10  * "I don't see any indication in any of my material that PDOP, GDOP
11  * or VDOP are output. There are quantities called Estimated
12  * {Horizontal Position, Vertical Position, Time, Horizonal Velocity}
13  * Error, but those are apparently only valid when SiRFDRive is
14  * active."
15  *
16  * "(SiRFdrive is their Dead Reckoning augmented firmware. It
17  * allows you to feed odometer ticks, gyro and possibly
18  * accelerometer inputs to the chip to allow it to continue
19  * to navigate in the absence of satellite information, and
20  * to improve fixes when you do have satellites.)"
21  *
22  * "[When we need RINEX data, we can get it from] SiRF Message #5.
23  *  If it's no longer implemented on your receiver, messages
24  * 7, 28, 29 and 30 will give you the same information."
25  *
26  * This file is Copyright (c) 2010 by the GPSD project
27  * BSD terms apply: see the file COPYING in the distribution root for details.
28  */
29
30 #include <sys/types.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <math.h>
35 #include <ctype.h>
36 #ifndef S_SPLINT_S
37 #include <unistd.h>
38 #endif /* S_SPLINT_S */
39 #include <time.h>
40 #include <stdio.h>
41
42 #include "gpsd.h"
43 #include "bits.h"
44 #include "timebase.h"
45 #if defined(SIRF_ENABLE) && defined(BINARY_ENABLE)
46
47 #define HI(n)           ((n) >> 8)
48 #define LO(n)           ((n) & 0xff)
49
50 #ifdef ALLOW_RECONFIGURE
51 /*@ +charint @*/
52 /* message to enable:
53  *   MID 7 Clock Status
54  *   MID 8 50Bps subframe data
55  *   MID 17 Differential  Corrections
56  *   MID 28 Nav Lib Measurement Data
57  *   MID 29 Nav Lib DGPS Data
58  *   MID 30 Nav Lib SV State Data
59  *   MID 31 Nav Lib Initialization data
60  * at 1Hz rate */
61 static unsigned char enablesubframe[] = {
62     0xa0, 0xa2, 0x00, 0x19,
63     0x80,                       /* MID 128 initialize Data Source */
64     0x00, 0x00, 0x00, 0x00,     /* EXEF X */
65     0x00, 0x00, 0x00, 0x00,     /* ECEF Y */
66     0x00, 0x00, 0x00, 0x00,     /* ECEF Z */
67     0x00, 0x00, 0x00, 0x00,     /* clock drift */
68     0x00, 0x00, 0x00, 0x00,     /* time of week */
69     0x00, 0x00,                 /* week number */
70     0x0C,                       /* Chans 1-12 */
71     /* change the next 0x10 to 0x08
72      * for factory reset */
73     0x10,
74     0x00, 0x00, 0xb0, 0xb3
75 };
76
77 static unsigned char disablesubframe[] = {
78     0xa0, 0xa2, 0x00, 0x19,
79     0x80,                       /* MID 128 initialize Data Source */
80     0x00, 0x00, 0x00, 0x00,     /* EXEF X */
81     0x00, 0x00, 0x00, 0x00,     /* ECEF Y */
82     0x00, 0x00, 0x00, 0x00,     /* ECEF Z */
83     0x00, 0x00, 0x00, 0x00,     /* clock drift */
84     0x00, 0x00, 0x00, 0x00,     /* time of week */
85     0x00, 0x00,                 /* week number */
86     0x0C,                       /* Chans 1-12 */
87
88     0x00,
89     0x00, 0x00, 0xb0, 0xb3
90 };
91
92 static unsigned char modecontrol[] = {
93     0xa0, 0xa2, 0x00, 0x0e,
94     0x88,                       /* MID 136 Mode Control */
95     0x00, 0x00,                 /* pad bytes */
96     0x00,                       /* degraded mode off */
97     0x00, 0x00,                 /* pad bytes */
98     0x00, 0x00,                 /* altitude */
99     0x00,                       /* altitude hold auto */
100     0x00,                       /* use last computed alt */
101     0x00,                       /* reserved */
102     0x00,                       /* disable degraded mode */
103     0x00,                       /* disable dead reckoning */
104     0x01,                       /* enable track smoothing */
105     0x00, 0x00, 0xb0, 0xb3
106 };
107
108 /* enable 1 PPS Time MID 52 *
109  * using Set Message Rate MID 166 */
110 static unsigned char enablemid52[] = {
111     0xa0, 0xa2, 0x00, 0x08,
112     0xa6,                       /* MID 166 */
113     0x00,                       /* enable/disable one message */
114     0x34,                       /* MID 52 */
115     0x01,                       /* sent once per second */
116     0x00, 0x00, 0x00, 0x00,     /* unused, set to zero */
117     0x00, 0xdb, 0xb0, 0xb3
118 };
119
120 /*@ -charint @*/
121 #endif /* ALLOW_RECONFIGURE */
122
123
124 static gps_mask_t sirf_msg_debug(unsigned char *, size_t);
125 static gps_mask_t sirf_msg_errors(unsigned char *, size_t);
126
127 static gps_mask_t sirf_msg_navdata(struct gps_device_t *, unsigned char *,
128                                    size_t);
129 static gps_mask_t sirf_msg_navsol(struct gps_device_t *, unsigned char *,
130                                   size_t);
131 static gps_mask_t sirf_msg_nlmd(struct gps_device_t *, unsigned char *,
132                                 size_t);
133 static gps_mask_t sirf_msg_ppstime(struct gps_device_t *, unsigned char *,
134                                    size_t);
135 static gps_mask_t sirf_msg_svinfo(struct gps_device_t *, unsigned char *,
136                                   size_t);
137 #ifdef ALLOW_RECONFIGURE
138 static gps_mask_t sirf_msg_swversion(struct gps_device_t *, unsigned char *,
139                                      size_t);
140 static gps_mask_t sirf_msg_sysparam(struct gps_device_t *, unsigned char *,
141                                     size_t);
142 #endif /* ALLOW_RECONFIGURE */
143 static gps_mask_t sirf_msg_ublox(struct gps_device_t *, unsigned char *,
144                                  size_t);
145
146
147 static bool sirf_write(int fd, unsigned char *msg)
148 {
149     unsigned int crc;
150     size_t i, len;
151     bool ok;
152
153     len = (size_t) ((msg[2] << 8) | msg[3]);
154
155     /* calculate CRC */
156     crc = 0;
157     for (i = 0; i < len; i++)
158         crc += (int)msg[4 + i];
159     crc &= 0x7fff;
160
161     /* enter CRC after payload */
162     msg[len + 4] = (unsigned char)((crc & 0xff00) >> 8);
163     msg[len + 5] = (unsigned char)(crc & 0x00ff);
164
165     gpsd_report(LOG_IO, "SiRF: Writing control type %02x:%s\n", msg[4],
166                 gpsd_hexdump_wrapper(msg, len + 8, LOG_IO));
167     ok = (write(fd, msg, len + 8) == (ssize_t) (len + 8));
168     if (!ok) {
169         gpsd_report(LOG_WARN, "SiRF: Writing error.\n");
170     }
171     (void)tcdrain(fd);
172     return (ok);
173 }
174
175 #ifdef ALLOW_CONTROLSEND
176 static ssize_t sirf_control_send(struct gps_device_t *session, char *msg,
177                                  size_t len)
178 {
179     /*@ +charint +matchanyintegral -initallelements -mayaliasunique @*/
180     session->msgbuf[0] = (char)0xa0;
181     session->msgbuf[1] = (char)0xa2;
182     session->msgbuf[2] = (len >> 8) & 0xff;
183     session->msgbuf[3] = len & 0xff;
184     memcpy(session->msgbuf + 4, msg, len);
185     session->msgbuf[len + 6] = (char)0xb0;
186     session->msgbuf[len + 7] = (char)0xb3;
187     session->msgbuflen = len + 8;
188
189     /* *INDENT-OFF* */
190     return sirf_write(session->gpsdata.gps_fd,
191               (unsigned char *)session->msgbuf) ? (int)session->msgbuflen : -1;
192     /* *INDENT-ON* */
193     /*@ -charint -matchanyintegral +initallelements +mayaliasunique @*/
194 }
195 #endif /* ALLOW_CONTROLSEND */
196
197 #ifdef ALLOW_RECONFIGURE
198 static bool sirf_speed(int ttyfd, speed_t speed, char parity, int stopbits)
199 /* change speed in binary mode */
200 {
201     /*@ +charint @*/
202     static unsigned char msg[] = {
203         0xa0, 0xa2, 0x00, 0x09,
204         0x86,                   /* byte 4:
205                                  * Set Binary Serial Port
206                                  * MID 134 */
207         0x00, 0x00, 0x12, 0xc0, /* bytes 5-8: 4800 bps */
208         0x08,                   /* byte  9: 8 data bits */
209         0x01,                   /* byte 10: 1 stop bit */
210         0x00,                   /* byte 11: no parity */
211         0x00,                   /* byte 12: reserved pad */
212         0x00, 0x00, 0xb0, 0xb3
213     };
214     /*@ -charint @*/
215     gpsd_report(LOG_PROG, "SiRF: sirf_speed(%d,%c,%d)\n",
216                 speed, parity, stopbits);
217     if (9600 > speed) {
218         gpsd_report(LOG_WARN, "NTPD: SiRF may lag at less than 9600bps\n");
219     }
220
221     switch (parity) {
222     case 'E':
223     case 2:
224         parity = (char)2;
225         break;
226     case 'O':
227     case 1:
228         parity = (char)1;
229         break;
230     case 'N':
231     case 0:
232     default:
233         parity = (char)0;
234         break;
235     }
236     msg[7] = (unsigned char)HI(speed);
237     msg[8] = (unsigned char)LO(speed);
238     msg[10] = (unsigned char)stopbits;
239     msg[11] = (unsigned char)parity;
240     return (sirf_write(ttyfd, msg));
241 }
242
243 static bool sirf_to_nmea(int ttyfd, speed_t speed)
244 /* switch from binary to NMEA at specified baud */
245 {
246     /*@ +charint @*/
247     static unsigned char msg[] = { 0xa0, 0xa2, 0x00, 0x18,
248         0x81, 0x02,
249         0x01, 0x01,             /* GGA */
250         0x00, 0x00,             /* suppress GLL */
251         0x01, 0x01,             /* GSA */
252         0x05, 0x01,             /* GSV */
253         0x01, 0x01,             /* RMC */
254         0x00, 0x00,             /* suppress VTG */
255         0x00, 0x01,             /* suppress MSS */
256         0x00, 0x01,             /* suppress EPE */
257         0x00, 0x01,             /* suppress EPE */
258         0x00, 0x01,             /* suppress ZDA */
259         0x00, 0x00,             /* unused */
260         0x12, 0xc0,             /* 4800 bps */
261         0xb0, 0xb3
262     };
263     /*@ -charint @*/
264
265     msg[26] = (unsigned char)HI(speed);
266     msg[27] = (unsigned char)LO(speed);
267     return (sirf_write(ttyfd, msg));
268 }
269
270 static void sirfbin_mode(struct gps_device_t *session, int mode)
271 {
272     char parity = '0';
273     if (mode == MODE_NMEA) {
274         (void)sirf_to_nmea(session->gpsdata.gps_fd,
275                            session->gpsdata.dev.baudrate);
276     } else if (mode == MODE_BINARY) {
277         switch (session->gpsdata.dev.parity) {
278         default:
279         case 'N':
280             parity = '0';
281             break;
282         case 'O':
283             parity = '1';
284             break;
285         case 'E':
286             parity = '2';
287             break;
288
289         }
290         // gpsd only supports 8[NO]1 or 7[EO]2
291         // thus the strange us of stopbits
292         (void)nmea_send(session,
293                         "$PSRF100,0,%d,%d,%d,%c",
294                         session->gpsdata.dev.baudrate,
295                         9 - session->gpsdata.dev.stopbits,
296                         session->gpsdata.dev.stopbits, parity);
297         (void)usleep(333);      /* guessed settling time */
298         session->gpsdata.dev.driver_mode = MODE_BINARY;
299     }
300     session->back_to_nmea = false;
301 }
302 #endif /* ALLOW_RECONFIGURE */
303
304 static ssize_t sirf_get(struct gps_device_t *session)
305 {
306     ssize_t len = generic_get(session);
307
308     if (session->packet.type == SIRF_PACKET) {
309         session->gpsdata.dev.driver_mode = MODE_BINARY;
310     } else if (session->packet.type == NMEA_PACKET) {
311         session->gpsdata.dev.driver_mode = MODE_NMEA;
312         (void)gpsd_switch_driver(session, "Generic NMEA");
313     } else {
314         /* should never happen */
315         gpsd_report(LOG_PROG, "SiRF: Unexpected packet type %d\n",
316                     session->packet.type);
317         (void)gpsd_switch_driver(session, "Generic NMEA");
318     }
319
320     return len;
321 }
322
323 static gps_mask_t sirf_msg_debug(unsigned char *buf, size_t len)
324 {
325     char msgbuf[MAX_PACKET_LENGTH * 3 + 2];
326     int i;
327
328     bzero(msgbuf, (int)sizeof(msgbuf));
329
330     /*@ +charint @*/
331     if (0xe1 == buf[0]) {       /* Development statistics messages */
332         for (i = 2; i < (int)len; i++)
333             (void)snprintf(msgbuf + strlen(msgbuf),
334                            sizeof(msgbuf) - strlen(msgbuf),
335                            "%c", buf[i] ^ 0xff);
336         gpsd_report(LOG_PROG, "SiRF: DEV 0xe1: %s\n", msgbuf);
337     } else if (0xff == (unsigned char)buf[0]) { /* Debug messages */
338         for (i = 1; i < (int)len; i++)
339             if (isprint(buf[i]))
340                 (void)snprintf(msgbuf + strlen(msgbuf),
341                                sizeof(msgbuf) - strlen(msgbuf), "%c", buf[i]);
342             else
343                 (void)snprintf(msgbuf + strlen(msgbuf),
344                                sizeof(msgbuf) - strlen(msgbuf),
345                                "\\x%02x", (unsigned int)buf[i]);
346         gpsd_report(LOG_PROG, "SiRF: DBG 0xff: %s\n", msgbuf);
347     }
348     /*@ -charint @*/
349     return 0;
350 }
351
352 static gps_mask_t sirf_msg_errors(unsigned char *buf, size_t len UNUSED)
353 {
354     switch (getbeuw(buf, 1)) {
355     case 2:
356         gpsd_report(LOG_PROG,
357                     "SiRF: EID 0x0a type 2: Subframe %u error on PRN %u\n",
358                     getbeul(buf, 9), getbeul(buf, 5));
359         break;
360
361     case 4107:
362         gpsd_report(LOG_PROG,
363                     "SiRF: EID 0x0a type 4107: neither KF nor LSQ fix.\n");
364         break;
365
366     default:
367         gpsd_report(LOG_PROG, "SiRF: EID 0x0a: Error MID %d\n",
368                     getbeuw(buf, 1));
369         break;
370     }
371     return 0;
372 }
373
374 /* Navigation Library Measurement Data MID 28 */
375 static gps_mask_t sirf_msg_nlmd(struct gps_device_t *session,
376                                 unsigned char *buf, size_t len)
377 {
378
379     double gps_tow = 0.0;
380
381     if (len != 56)
382         return 0;
383
384     /* oh barf, SiRF claims to be IEEE754 but supports two
385      * different double orders, neither IEEE754 */
386     /* Todo - decode the time, since this is the first MID with a
387      * good time stamp this will be good for ntpshm time */
388     gpsd_report(LOG_PROG, "SiRF: MID 0x1c, NLMD, gps_tow: %f, %s\n",
389                 (double)gps_tow, gpsd_hexdump_wrapper(&gps_tow, 8, LOG_PROG));
390
391     return 0;
392 }
393
394 #ifdef ALLOW_RECONFIGURE
395 static gps_mask_t sirf_msg_swversion(struct gps_device_t *session,
396                                      unsigned char *buf, size_t len)
397 {
398     double fv;
399
400     if (len < 20)
401         return 0;
402
403     (void)strlcpy(session->subtype, (char *)buf + 1,
404                   sizeof(session->subtype));
405     fv = atof((char *)(buf + 1));
406     if (fv < 231) {
407         session->driver.sirf.driverstate |= SIRF_LT_231;
408         if (fv > 200)
409             sirfbin_mode(session, 0);
410     } else if (fv < 232) {
411         session->driver.sirf.driverstate |= SIRF_EQ_231;
412     } else {
413         gpsd_report(LOG_PROG, "SiRF: Enabling PPS message...\n");
414         (void)sirf_write(session->gpsdata.gps_fd, enablemid52);
415         session->driver.sirf.driverstate |= SIRF_GE_232;
416         session->context->valid |= LEAP_SECOND_VALID;
417     }
418     if (strstr((char *)(buf + 1), "ES"))
419         gpsd_report(LOG_INF, "SiRF: Firmware has XTrac capability\n");
420     gpsd_report(LOG_PROG, "SiRF: fv: %0.2f, Driver state flags are: %0x\n",
421                 fv, session->driver.sirf.driverstate);
422 #ifdef NTPSHM_ENABLE
423     session->driver.sirf.time_seen = 0;
424 #endif /* NTPSHM_ENABLE */
425     if (session->gpsdata.dev.baudrate >= 38400) {
426         gpsd_report(LOG_PROG, "SiRF: Enabling subframe transmission...\n");
427         (void)sirf_write(session->gpsdata.gps_fd, enablesubframe);
428     }
429     gpsd_report(LOG_DATA, "SiRF: FV 0x06: subtype='%s' mask={DEVICEID}\n",
430                 session->subtype);
431     return DEVICEID_IS;
432 }
433 #endif /* ALLOW_RECONFIGURE */
434
435 static gps_mask_t sirf_msg_navdata(struct gps_device_t *session,
436                                    unsigned char *buf, size_t len)
437 {
438     unsigned int i, words[10], chan, svid;
439
440     if (len != 43)
441         return 0;
442
443     chan = (unsigned int)getub(buf, 1);
444     svid = (unsigned int)getub(buf, 2);
445
446     for (i = 0; i < 10; i++) {
447         words[i] = (unsigned int)getbeul(buf, 4 * i + 3);
448     }
449
450     (void)gpsd_interpret_subframe_raw(session, words);
451
452 #ifdef ALLOW_RECONFIGURE
453     if (session->gpsdata.dev.baudrate < 38400) {
454         gpsd_report(LOG_PROG, "SiRF: Disabling subframe transmission...\n");
455         (void)sirf_write(session->gpsdata.gps_fd, disablesubframe);
456     }
457 #endif /* ALLOW_RECONFIGURE */
458     return 0;
459 }
460
461 #define SIRF_CHANNELS   12      /* max channels allowed in SiRF format */
462
463 static gps_mask_t sirf_msg_svinfo(struct gps_device_t *session,
464                                   unsigned char *buf, size_t len)
465 {
466     int st, i, j, cn;
467     gps_mask_t mask = 0;
468
469     if (len != 188)
470         return 0;
471
472     gpsd_zero_satellites(&session->gpsdata);
473     session->context->gps_week = (unsigned short)getbesw(buf, 1);
474     session->context->gps_tow = (double)getbeul(buf, 3) * 1e-2;
475     /*@ ignore @*//*@ splint is confused @ */
476     session->gpsdata.skyview_time
477         =
478         gpstime_to_unix(session->context->gps_week, session->context->gps_tow)
479         - session->context->leap_seconds;
480     /*@ end @*/
481     for (i = st = 0; i < SIRF_CHANNELS; i++) {
482         int off = 8 + 15 * i;
483         bool good;
484         session->gpsdata.PRN[st] = (int)getub(buf, off);
485         session->gpsdata.azimuth[st] =
486             (int)(((unsigned)getub(buf, off + 1) * 3) / 2.0);
487         session->gpsdata.elevation[st] =
488             (int)((unsigned)getub(buf, off + 2) / 2.0);
489         cn = 0;
490         for (j = 0; j < 10; j++)
491             cn += (int)getub(buf, off + 5 + j);
492
493         session->gpsdata.ss[st] = (float)(cn / 10.0);
494         good = session->gpsdata.PRN[st] != 0 &&
495             session->gpsdata.azimuth[st] != 0 &&
496             session->gpsdata.elevation[st] != 0;
497 #ifdef __UNUSED__
498         gpsd_report(LOG_PROG,
499                     "SiRF: PRN=%2d El=%3.2f Az=%3.2f ss=%3d stat=%04x %c\n",
500                     getub(buf, off),
501                     getub(buf, off + 2) / 2.0,
502                     (getub(buf, off + 1) * 3) / 2.0,
503                     cn / 10, getbeuw(buf, off + 3), good ? '*' : ' ');
504 #endif /* UNUSED */
505         if (good != 0)
506             st += 1;
507     }
508     session->gpsdata.satellites_visible = st;
509 #ifdef NTPSHM_ENABLE
510     if (st <= 3) {
511         gpsd_report(LOG_PROG,
512                     "SiRF: NTPD not enough satellites seen: %d\n", st);
513     } else {
514         /* SiRF says if 3 sats in view the time is good */
515         if (0 == (session->driver.sirf.time_seen & TIME_SEEN_GPS_1)) {
516             gpsd_report(LOG_RAW, "SiRF: NTPD just seen GPS_1\n");
517         }
518         gpsd_report(LOG_PROG,
519                     "SiRF: NTPD valid time MID 0x04, seen=0x%02x, time:%.2lf, leap:%d\n",
520                     session->driver.sirf.time_seen,
521                     session->gpsdata.skyview_time,
522                     session->context->leap_seconds);
523         session->driver.sirf.time_seen |= TIME_SEEN_GPS_1;
524         mask |= TIME_IS;
525         /*
526          * This time stamp, at 4800bps, is so close to 1 sec old as to
527          * be confusing to ntpd, but ntpshm_put() will ignore it if a better
528          * time already seen
529          */
530     }
531 #endif /* NTPSHM_ENABLE */
532     gpsd_report(LOG_DATA, "SiRF: MTD 0x04: visible=%d mask={SATELLITE}\n",
533                 session->gpsdata.satellites_visible);
534     return SATELLITE_IS | mask;
535 }
536
537 #ifdef NTPSHM_ENABLE
538 static double sirf_ntp_offset(struct gps_device_t *session)
539 /* return NTP time-offset fudge factor for this device */
540 {
541     double retval = NAN;
542
543     /* we need to have seen UTC time with a valid leap-year offset */
544     if ((session->driver.sirf.time_seen & TIME_SEEN_UTC_2) != 0) {
545         retval = NAN;
546     }
547
548     /* the PPS time message */
549     else if (strcmp(session->gpsdata.tag, "MID52") == 0) {
550         retval = 0.3;
551     }
552
553     /* uBlox EMND message */
554     else if (strcmp(session->gpsdata.tag, "MID98") == 0) {
555         retval = 0.570;
556     }
557 #ifdef __UNUSED__
558     /* geodetic-data message */
559     else if (strcmp(session->gpsdata.tag, "MID41") == 0) {
560         retval = 0.570;
561     }
562 #endif /* __UNUSED__ */
563
564     /* the Navigation Solution message */
565     else if (strcmp(session->gpsdata.tag, "MID2") == 0) {
566         if (session->sourcetype == source_usb) {
567             retval = 0.640;     /* USB, expect +/- 50mS jitter */
568         } else {
569             switch (session->gpsdata.dev.baudrate) {
570             default:
571                 retval = 0.704; /* WAG */
572                 break;
573             case 4800:
574                 retval = 0.704; /* fudge valid at 4800bps */
575                 break;
576             case 9600:
577                 retval = 0.688;
578                 break;
579             case 19200:
580                 retval = 0.484;
581                 break;
582             case 38400:
583                 retval = 0.845; /*  0.388; ?? */
584                 break;
585             }
586         }
587     }
588
589     return retval;
590 }
591 #endif /* NTPSHM_ENABLE */
592
593 static gps_mask_t sirf_msg_navsol(struct gps_device_t *session,
594                                   unsigned char *buf, size_t len)
595 {
596     int i;
597     unsigned short navtype;
598     gps_mask_t mask = 0;
599
600     if (len != 41)
601         return 0;
602
603     session->gpsdata.satellites_used = (int)getub(buf, 28);
604     memset(session->gpsdata.used, 0, sizeof(session->gpsdata.used));
605     for (i = 0; i < SIRF_CHANNELS; i++)
606         session->gpsdata.used[i] = (int)getub(buf, 29 + i);
607     /* position/velocity is bytes 1-18 */
608     ecef_to_wgs84fix(&session->newdata, &session->gpsdata.separation,
609                      getbesl(buf, 1) * 1.0, getbesl(buf, 5) * 1.0,
610                      getbesl(buf, 9) * 1.0, getbesw(buf, 13) / 8.0,
611                      getbesw(buf, 15) / 8.0, getbesw(buf, 17) / 8.0);
612     /* fix status is byte 19 */
613     navtype = (unsigned short)getub(buf, 19);
614     session->gpsdata.status = STATUS_NO_FIX;
615     session->newdata.mode = MODE_NO_FIX;
616     if ((navtype & 0x80) != 0)
617         session->gpsdata.status = STATUS_DGPS_FIX;
618     else if ((navtype & 0x07) > 0 && (navtype & 0x07) < 7)
619         session->gpsdata.status = STATUS_FIX;
620     if ((navtype & 0x07) == 4 || (navtype & 0x07) == 6)
621         session->newdata.mode = MODE_3D;
622     else if (session->gpsdata.status != 0)
623         session->newdata.mode = MODE_2D;
624     if (session->newdata.mode == MODE_3D)
625         mask |= ALTITUDE_IS | CLIMB_IS;
626     gpsd_report(LOG_PROG,
627                 "SiRF: MND 0x02: Navtype = 0x%0x, Status = %d, mode = %d\n",
628                 navtype, session->gpsdata.status, session->newdata.mode);
629     /* byte 20 is HDOP, see below */
630     /* byte 21 is "mode 2", not clear how to interpret that */
631     session->context->gps_week = (unsigned short)getbesw(buf, 22);
632     session->context->gps_tow = (double)getbeul(buf, 24) * 1e-2;
633     /*@ ignore @*//*@ splint is confused @ */
634     session->newdata.time =
635         gpstime_to_unix(session->context->gps_week,
636                         session->context->gps_tow) -
637         session->context->leap_seconds;
638     /*@ end @*/
639 #ifdef NTPSHM_ENABLE
640     if (session->newdata.mode <= MODE_NO_FIX) {
641         gpsd_report(LOG_PROG, "SiRF: NTPD no fix, mode: %d\n",
642                     session->newdata.mode);
643     } else {
644         if (0 == (session->driver.sirf.time_seen & TIME_SEEN_GPS_2)) {
645             gpsd_report(LOG_PROG, "SiRF: NTPD SEEN_GPS_2\n");
646         }
647         gpsd_report(LOG_PROG,
648                     "SiRF: NTPD valid time MID 0x02, seen=0x%02x, time;%.2lf, leap:%d\n",
649                     session->driver.sirf.time_seen,
650                     session->newdata.time, session->context->leap_seconds);
651         session->driver.sirf.time_seen |= TIME_SEEN_GPS_2;
652     }
653 #endif /* NTPSHM_ENABLE */
654     /* fix quality data */
655     session->gpsdata.dop.hdop = (double)getub(buf, 20) / 5.0;
656     mask |=
657         TIME_IS | LATLON_IS | ALTITUDE_IS | TRACK_IS | SPEED_IS | STATUS_IS |
658         MODE_IS | DOP_IS | USED_IS;
659     gpsd_report(LOG_DATA,
660                 "SiRF: MND 0x02: time=%.2f lat=%.2f lon=%.2f alt=%.2f track=%.2f speed=%.2f mode=%d status=%d hdop=%.2f used=%d mask=%s\n",
661                 session->newdata.time, session->newdata.latitude,
662                 session->newdata.longitude, session->newdata.altitude,
663                 session->newdata.track, session->newdata.speed,
664                 session->newdata.mode, session->gpsdata.status,
665                 session->gpsdata.dop.hdop, session->gpsdata.satellites_used,
666                 gpsd_maskdump(mask));
667     return mask;
668 }
669
670 #ifdef __UNUSED__
671 /***************************************************************************
672  We've stopped interpreting GND (0x29) for the following reasons:
673
674 1) Versions of SiRF firmware still in wide circulation (and likely to be
675    so for a while) don't report a valid time field, leading to annoying
676    twice-per-second jitter in client displays.
677
678 2) What we wanted out of this that MND didn't give us was horizontal and
679    vertical error estimates. But we have to do our own error estimation by
680    computing DOPs from the skyview covariance matrix anyway, because we
681    want separate epx and epy errors a la NMEA 3.0.
682
683 3) The fix-merge logic in gpsd.c is (unavoidably) NMEA-centric and
684    thinks multiple sentences in one cycle should be treated as
685    incremental updates.  This leads to various silly results when (as
686    in GND) a subsequent sentence is (a) intended to be a complete fix
687    in itself, and (b) frequently broken.
688
689 4) Ignoring this dodgy sentence allows us to go to a nice clean single
690    fix update per cycle.
691
692 Code left in place in case we need to reverse this decision.
693
694 ***************************************************************************/
695 static gps_mask_t sirf_msg_geodetic(struct gps_device_t *session,
696                                     unsigned char *buf, size_t len)
697 {
698     unsigned short navtype;
699     gps_mask_t mask = 0;
700     double eph;
701
702     if (len != 91)
703         return 0;
704
705     session->gpsdata.sentence_length = 91;
706     (void)strlcpy(session->gpsdata.tag, "GND", MAXTAGLEN + 1);
707
708     navtype = (unsigned short)getbeuw(buf, 3);
709     session->gpsdata.status = STATUS_NO_FIX;
710     session->newdata.mode = MODE_NO_FIX;
711     if (navtype & 0x80)
712         session->gpsdata.status = STATUS_DGPS_FIX;
713     else if ((navtype & 0x07) > 0 && (navtype & 0x07) < 7)
714         session->gpsdata.status = STATUS_FIX;
715     session->newdata.mode = MODE_NO_FIX;
716     if ((navtype & 0x07) == 4 || (navtype & 0x07) == 6)
717         session->newdata.mode = MODE_3D;
718     else if (session->gpsdata.status)
719         session->newdata.mode = MODE_2D;
720     gpsd_report(LOG_PROG,
721                 "SiRF: GND 0x29: Navtype = 0x%0x, Status = %d, mode = %d\n",
722                 navtype, session->gpsdata.status, session->newdata.mode);
723     mask |= STATUS_IS | MODE_IS;
724
725     session->newdata.latitude = getbesl(buf, 23) * 1e-7;
726     session->newdata.longitude = getbesl(buf, 27) * 1e-7;
727     if (session->newdata.latitude != 0 && session->newdata.latitude != 0)
728         mask |= LATLON_IS;
729
730     if ((eph = getbesl(buf, 50) * 1e-2) > 0) {
731         session->newdata.epx = session->newdata.epy = eph / sqrt(2);
732         mask |= HERR_IS;
733     }
734     if ((session->newdata.epv = getbesl(buf, 54) * 1e-2) > 0)
735         mask |= VERR_IS;
736     if ((session->newdata.eps = getbesw(buf, 62) * 1e-2) > 0)
737         mask |= SPEEDERR_IS;
738
739     /* HDOP should be available at byte 89, but in 231 it's zero. */
740     //session->gpsdata.dop.hdop = (unsigned int)getub(buf, 89) * 0.2;
741
742     if ((session->newdata.mode > MODE_NO_FIX)
743         && (session->driver.sirf.driverstate & SIRF_GE_232)) {
744         struct tm unpacked_date;
745         double subseconds;
746         /*
747          * Early versions of the SiRF protocol manual don't document
748          * this sentence at all.  Some that do incorrectly
749          * describe UTC Day, Hour, and Minute as 2-byte quantities,
750          * not 1-byte. Chris Kuethe, our SiRF expert, tells us:
751          *
752          * "The Geodetic Navigation packet (0x29) was not fully
753          * implemented in firmware prior to version 2.3.2. So for
754          * anyone running 231.000.000 or earlier (including ES,
755          * SiRFDRive, XTrac trains) you won't get UTC time. I don't
756          * know what's broken in firmwares before 2.3.1..."
757          *
758          * To work around the incomplete implementation of this
759          * packet in 231, we used to assume that only the altitude field
760          * from this packet is valid.  But even this doesn't necessarily
761          * seem to be the case.  Instead, we do our own computation
762          * of geoid separation now.
763          *
764          * UTC is left all zeros in 231 and older firmware versions,
765          * and misdocumented in version 1.4 of the Protocol Reference.
766          *            Documented:        Real:
767          * UTC year       2               2
768          * UTC month      1               1
769          * UTC day        2               1
770          * UTC hour       2               1
771          * UTC minute     2               1
772          * UTC second     2               2
773          *                11              8
774          *
775          * Documentation of this field was corrected in the 1.6 version
776          * of the protocol manual.
777          */
778         unpacked_date.tm_year = (int)getbeuw(buf, 11) - 1900;
779         unpacked_date.tm_mon = (int)getub(buf, 13) - 1;
780         unpacked_date.tm_mday = (int)getub(buf, 14);
781         unpacked_date.tm_hour = (int)getub(buf, 15);
782         unpacked_date.tm_min = (int)getub(buf, 16);
783         unpacked_date.tm_sec = 0;
784         subseconds = getbeuw(buf, 17) * 1e-3;
785         /*@ -compdef -unrecog */
786         session->newdata.time = (double)timegm(&unpacked_date) + subseconds;
787         /*@ +compdef +unrecog */
788         gpsd_report(LOG_PROG, "SiRF: GND 0x29 UTC: %lf\n",
789                     session->newdata.time);
790 #ifdef NTPSHM_ENABLE
791         if (session->newdata.mode <= MODE_NO_FIX) {
792             gpsd_report(LOG_PROG, "SiRF: NTPD no fix, mode: $d\n",
793                         session->newdata.mode);
794         } else if (0 == unpacked_date.tm_year) {
795             gpsd_report(LOG_PROG, "SiRF: NTPD no year\n",
796                         session->newdata.mode);
797         } else {
798             if (0 == (session->driver.sirf.time_seen & TIME_SEEN_UTC_1)) {
799                 gpsd_report(LOG_RAW, "SiRF: NTPD just SEEN_UTC 1\n");
800             }
801             gpsd_report(LOG_PROG,
802                         "SiRF: NTPD valid time MID 0x29, seen=0x%02x\n",
803                         session->driver.sirf.time_seen);
804             session->driver.sirf.time_seen |= TIME_SEEN_UTC_1;
805         }
806
807 #endif /* NTPSHM_ENABLE */
808         /* skip 4 bytes of satellite map */
809         session->newdata.altitude = getbesl(buf, 35) * 1e-2;
810         /* skip 1 byte of map datum */
811         session->newdata.speed = getbeuw(buf, 40) * 1e-2;
812         session->newdata.track = getbeuw(buf, 42) * 1e-2;
813         /* skip 2 bytes of magnetic variation */
814         session->newdata.climb = getbesw(buf, 46) * 1e-2;
815         mask |= TIME_IS | SPEED_IS | TRACK_IS;
816         if (session->newdata.mode == MODE_3D)
817             mask |= ALTITUDE_IS | CLIMB_IS;
818     }
819     gpsd_report(LOG_DATA,
820                 "SiRF: GND 0x29: time=%.2f lat=%.2f lon=%.2f alt=%.2f track=%.2f speed=%.2f mode=%d status=%d mask=%s\n",
821                 session->newdata.time,
822                 session->newdata.latitude,
823                 session->newdata.longitude,
824                 session->newdata.altitude,
825                 session->newdata.track,
826                 session->newdata.speed,
827                 session->newdata.mode,
828                 session->gpsdata.status, gpsd_maskdump(mask));
829     return mask;
830 }
831 #endif /* __UNUSED__ */
832
833 #ifdef ALLOW_RECONFIGURE
834 static gps_mask_t sirf_msg_sysparam(struct gps_device_t *session,
835                                     unsigned char *buf, size_t len)
836 {
837
838     if (len != 65)
839         return 0;
840
841     /* save these to restore them in the revert method */
842     session->driver.sirf.nav_parameters_seen = true;
843     session->driver.sirf.altitude_hold_mode = (unsigned char)getub(buf, 5);
844     session->driver.sirf.altitude_hold_source = (unsigned char)getub(buf, 6);
845     session->driver.sirf.altitude_source_input = getbesw(buf, 7);
846     session->driver.sirf.degraded_mode = (unsigned char)getub(buf, 9);
847     session->driver.sirf.degraded_timeout = (unsigned char)getub(buf, 10);
848     session->driver.sirf.dr_timeout = (unsigned char)getub(buf, 11);
849     session->driver.sirf.track_smooth_mode = (unsigned char)getub(buf, 12);
850     gpsd_report(LOG_PROG, "SiRF: Setting Navigation Parameters\n");
851     (void)sirf_write(session->gpsdata.gps_fd, modecontrol);
852     return 0;
853 }
854 #endif /* ALLOW_RECONFIGURE */
855
856 static gps_mask_t sirf_msg_ublox(struct gps_device_t *session,
857                                  unsigned char *buf, size_t len UNUSED)
858 {
859     gps_mask_t mask;
860     unsigned short navtype;
861
862     if (len != 39)
863         return 0;
864
865     /* this packet is only sent by uBlox firmware from version 1.32 */
866     mask = LATLON_IS | ALTITUDE_IS | SPEED_IS | TRACK_IS | CLIMB_IS |
867         STATUS_IS | MODE_IS | DOP_IS;
868     session->newdata.latitude = getbesl(buf, 1) * RAD_2_DEG * 1e-8;
869     session->newdata.longitude = getbesl(buf, 5) * RAD_2_DEG * 1e-8;
870     session->gpsdata.separation =
871         wgs84_separation(session->newdata.latitude,
872                          session->newdata.longitude);
873     session->newdata.altitude =
874         getbesl(buf, 9) * 1e-3 - session->gpsdata.separation;
875     session->newdata.speed = getbesl(buf, 13) * 1e-3;
876     session->newdata.climb = getbesl(buf, 17) * 1e-3;
877     session->newdata.track = getbesl(buf, 21) * RAD_2_DEG * 1e-8;
878
879     navtype = (unsigned short)getub(buf, 25);
880     session->gpsdata.status = STATUS_NO_FIX;
881     session->newdata.mode = MODE_NO_FIX;
882     if (navtype & 0x80)
883         session->gpsdata.status = STATUS_DGPS_FIX;
884     else if ((navtype & 0x07) > 0 && (navtype & 0x07) < 7)
885         session->gpsdata.status = STATUS_FIX;
886     if ((navtype & 0x07) == 4 || (navtype & 0x07) == 6)
887         session->newdata.mode = MODE_3D;
888     else if (session->gpsdata.status)
889         session->newdata.mode = MODE_2D;
890     gpsd_report(LOG_PROG,
891                 "SiRF: EMND 0x62: Navtype = 0x%0x, Status = %d, mode = %d\n",
892                 navtype, session->gpsdata.status, session->newdata.mode);
893
894     if (navtype & 0x40) {       /* UTC corrected timestamp? */
895         struct tm unpacked_date;
896         double subseconds;
897         mask |= TIME_IS;
898         unpacked_date.tm_year = (int)getbeuw(buf, 26) - 1900;
899         unpacked_date.tm_mon = (int)getub(buf, 28) - 1;
900         unpacked_date.tm_mday = (int)getub(buf, 29);
901         unpacked_date.tm_hour = (int)getub(buf, 30);
902         unpacked_date.tm_min = (int)getub(buf, 31);
903         unpacked_date.tm_sec = 0;
904         subseconds = ((unsigned short)getbeuw(buf, 32)) * 1e-3;
905         /*@ -compdef */
906         session->newdata.time = (double)mkgmtime(&unpacked_date) + subseconds;
907         /*@ +compdef */
908 #ifdef NTPSHM_ENABLE
909         if (0 == (session->driver.sirf.time_seen & TIME_SEEN_UTC_2)) {
910             gpsd_report(LOG_RAW, "SiRF: NTPD just SEEN_UTC_2\n");
911         }
912         gpsd_report(LOG_PROG,
913                     "SiRF: NTPD valid time MID 0x62, seen=0x%02x\n",
914                     session->driver.sirf.time_seen);
915         session->driver.sirf.time_seen |= TIME_SEEN_UTC_2;
916 #endif /* NTPSHM_ENABLE */
917         session->context->valid |= LEAP_SECOND_VALID;
918     }
919
920     session->gpsdata.dop.gdop = (int)getub(buf, 34) / 5.0;
921     session->gpsdata.dop.pdop = (int)getub(buf, 35) / 5.0;
922     session->gpsdata.dop.hdop = (int)getub(buf, 36) / 5.0;
923     session->gpsdata.dop.vdop = (int)getub(buf, 37) / 5.0;
924     session->gpsdata.dop.tdop = (int)getub(buf, 38) / 5.0;
925     session->driver.sirf.driverstate |= UBLOX;
926     gpsd_report(LOG_DATA,
927                 "SiRF: EMD 0x62: time=%.2f lat=%.2f lon=%.2f alt=%.f speed=%.2f track=%.2f climb=%.2f mode=%d status=%d gdop=%.2f pdop=%.2f hdop=%.2f vdop=%.2f tdop=%.2f mask=%s\n",
928                 session->newdata.time, session->newdata.latitude,
929                 session->newdata.longitude, session->newdata.altitude,
930                 session->newdata.speed, session->newdata.track,
931                 session->newdata.climb, session->newdata.mode,
932                 session->gpsdata.status, session->gpsdata.dop.gdop,
933                 session->gpsdata.dop.pdop, session->gpsdata.dop.hdop,
934                 session->gpsdata.dop.vdop, session->gpsdata.dop.tdop,
935                 gpsd_maskdump(mask));
936     return mask;
937 }
938
939 static gps_mask_t sirf_msg_ppstime(struct gps_device_t *session,
940                                    unsigned char *buf, size_t len)
941 {
942     gps_mask_t mask = 0;
943
944     if (len != 19)
945         return 0;
946
947     gpsd_report(LOG_PROG, "SiRF: PPS 0x34: Status = 0x%02x\n",
948                 getub(buf, 14));
949     if (((int)getub(buf, 14) & 0x07) == 0x07) { /* valid UTC time? */
950         struct tm unpacked_date;
951         unpacked_date.tm_hour = (int)getub(buf, 1);
952         unpacked_date.tm_min = (int)getub(buf, 2);
953         unpacked_date.tm_sec = (int)getub(buf, 3);
954         unpacked_date.tm_mday = (int)getub(buf, 4);
955         unpacked_date.tm_mon = (int)getub(buf, 5) - 1;
956         unpacked_date.tm_year = (int)getbeuw(buf, 6) - 1900;
957         /*@ -compdef */
958         session->newdata.time = (double)mkgmtime(&unpacked_date);
959         /*@ +compdef */
960         session->context->leap_seconds = (int)getbeuw(buf, 8);
961         if (LEAP_SECONDS > session->context->leap_seconds) {
962             /* something wrong */
963             gpsd_report(LOG_ERROR, "SiRF: Invalid leap_seconds: %d\n",
964                         session->context->leap_seconds);
965             session->context->leap_seconds = LEAP_SECONDS;
966             session->context->valid &= ~LEAP_SECOND_VALID;
967         } else {
968             session->context->valid |= LEAP_SECOND_VALID;
969         }
970 #ifdef NTPSHM_ENABLE
971         if (0 == (session->driver.sirf.time_seen & TIME_SEEN_UTC_2)) {
972             gpsd_report(LOG_RAW, "SiRF: NTPD just SEEN_UTC_2\n");
973         }
974         gpsd_report(LOG_PROG,
975                     "SiRF: NTPD valid time MID 0x34, seen=0x%02x\n",
976                     session->driver.sirf.time_seen);
977         session->driver.sirf.time_seen |= TIME_SEEN_UTC_2;
978 #endif /* NTPSHM_ENABLE */
979         mask |= TIME_IS;
980     }
981     return mask;
982 }
983
984 gps_mask_t sirf_parse(struct gps_device_t * session, unsigned char *buf,
985                       size_t len)
986 {
987
988     if (len == 0)
989         return 0;
990
991     buf += 4;
992     len -= 8;
993     gpsd_report(LOG_RAW, "SiRF: Raw packet type 0x%02x length %zd: %s\n",
994                 buf[0], len, gpsd_hexdump_wrapper(buf, len, LOG_RAW));
995     (void)snprintf(session->gpsdata.tag, sizeof(session->gpsdata.tag),
996                    "MID%d", (int)buf[0]);
997
998     /* could change if the set of messages we enable does */
999     session->cycle_end_reliable = true;
1000
1001     switch (buf[0]) {
1002     case 0x02:                  /* Measure Navigation Data Out MID 2 */
1003         if ((session->driver.sirf.driverstate & UBLOX) == 0)
1004             return sirf_msg_navsol(session, buf,
1005                                    len) | (CLEAR_IS | REPORT_IS);
1006         else {
1007             gpsd_report(LOG_PROG,
1008                         "SiRF: MND 0x02 skipped, uBlox flag is on.\n");
1009             return 0;
1010         }
1011     case 0x04:                  /* Measured tracker data out MID 4 */
1012         return sirf_msg_svinfo(session, buf, len);
1013
1014     case 0x05:                  /* Raw Tracker Data Out MID 5 */
1015         gpsd_report(LOG_PROG, "SiRF: unused Raw Tracker Data 0x05\n");
1016         return 0;
1017
1018 #ifdef ALLOW_RECONFIGURE
1019     case 0x06:                  /* Software Version String MID 6 */
1020         return sirf_msg_swversion(session, buf, len);
1021 #endif /* ALLOW_RECONFIGURE */
1022
1023     case 0x07:                  /* Clock Status Data MID 7 */
1024         gpsd_report(LOG_PROG, "SiRF: unused CLK 0x07\n");
1025         return 0;
1026
1027     case 0x08:                  /* subframe data MID 8 */
1028         /* extract leap-second from this */
1029         /*
1030          * Chris Kuethe says:
1031          * "Message 8 is generated as the data is received. It is not
1032          * buffered on the chip. So when you enable message 8, you'll
1033          * get one subframe every 6 seconds.  Of the data received, the
1034          * almanac and ephemeris are buffered and stored, so you can
1035          * query them at will. Alas, the time parameters are not
1036          * stored, which is really lame, as the UTC-GPS correction
1037          * changes 1 second every few years. Maybe."
1038          */
1039         return sirf_msg_navdata(session, buf, len);
1040
1041     case 0x09:                  /* CPU Throughput MID 9 */
1042         gpsd_report(LOG_PROG,
1043                     "SiRF: THR 0x09: SegStatMax=%.3f, SegStatLat=%3.f, AveTrkTime=%.3f, Last MS=%u\n",
1044                     (float)getbeuw(buf, 1) / 186, (float)getbeuw(buf,
1045                                                                  3) / 186,
1046                     (float)getbeuw(buf, 5) / 186, getbeuw(buf, 7));
1047         return 0;
1048
1049     case 0x0a:                  /* Error ID Data MID 10 */
1050         return sirf_msg_errors(buf, len);
1051
1052     case 0x0b:                  /* Command Acknowledgement MID 11 */
1053         gpsd_report(LOG_PROG, "SiRF: ACK 0x0b: %02x\n", getub(buf, 1));
1054         return 0;
1055
1056     case 0x0c:                  /* Command NAcknowledgement MID 12 */
1057         gpsd_report(LOG_PROG, "SiRF: NAK 0x0c: %02x\n", getub(buf, 1));
1058         return 0;
1059
1060     case 0x0d:                  /* Visible List MID 13 */
1061         gpsd_report(LOG_PROG, "SiRF: unused VIS 0x0d\n");
1062         return 0;
1063
1064     case 0x0e:                  /* Almanac Data MID 14 */
1065         gpsd_report(LOG_PROG, "SiRF: unused ALM  0x0e: %s\n",
1066                     gpsd_hexdump_wrapper(buf, len, LOG_PROG));
1067         return 0;
1068
1069     case 0x0f:                  /* Ephemeris Data MID 15 */
1070         gpsd_report(LOG_PROG, "SiRF: unused EPH  0x0f: %s\n",
1071                     gpsd_hexdump_wrapper(buf, len, LOG_PROG));
1072         return 0;
1073
1074     case 0x11:                  /* Differential Corrections MID 17 */
1075         gpsd_report(LOG_PROG, "SiRF: unused DIFF 0x11: %s\n",
1076                     gpsd_hexdump_wrapper(buf, len, LOG_PROG));
1077         return 0;
1078
1079     case 0x12:                  /* OK To Send MID 18 */
1080         gpsd_report(LOG_PROG, "SiRF: OTS 0x12: send indicator = %d\n",
1081                     getub(buf, 1));
1082         return 0;
1083
1084 #ifdef ALLOW_RECONFIGURE
1085     case 0x13:                  /* Navigation Parameters MID 19 */
1086         return sirf_msg_sysparam(session, buf, len);
1087 #endif /* ALLOW_RECONFIGURE */
1088
1089     case 0x1b:                  /* DGPS status (undocumented) MID 27 */
1090         gpsd_report(LOG_PROG, "SiRF: unused DGPSF 0x1b %s\n",
1091                     gpsd_hexdump_wrapper(buf, len, LOG_PROG));
1092         return 0;
1093
1094     case 0x1c:                  /* Navigation Library Measurement Data MID 28 */
1095         gpsd_report(LOG_PROG, "SiRF: NLMD 0x1c: %s\n",
1096                     gpsd_hexdump_wrapper(buf, len, LOG_PROG));
1097         return sirf_msg_nlmd(session, buf, len);
1098
1099     case 0x1d:                  /* Navigation Library DGPS Data MID 29 */
1100         gpsd_report(LOG_PROG, "SiRF: unused NLDG 0x1d: %s\n",
1101                     gpsd_hexdump_wrapper(buf, len, LOG_PROG));
1102         return 0;
1103
1104     case 0x1e:                  /* Navigation Library SV State Data MID 30 */
1105         gpsd_report(LOG_PROG, "SiRF: unused NLSV 0x1e: %s\n",
1106                     gpsd_hexdump_wrapper(buf, len, LOG_PROG));
1107         return 0;
1108
1109     case 0x1f:                  /* Navigation Library Initialization Data MID 31 */
1110         gpsd_report(LOG_PROG, "SiRF: unused NLID 0x1f: %s\n",
1111                     gpsd_hexdump_wrapper(buf, len, LOG_PROG));
1112         return 0;
1113
1114     case 0x29:                  /* Geodetic Navigation Information MID 41 */
1115         gpsd_report(LOG_PROG, "SiRF: unused GND 0x29: %s\n",
1116                     gpsd_hexdump_wrapper(buf, len, LOG_PROG));
1117         return 0;
1118
1119     case 0x32:                  /* SBAS corrections MID 50 */
1120         gpsd_report(LOG_PROG, "SiRF: unused SBAS 0x32: %s\n",
1121                     gpsd_hexdump_wrapper(buf, len, LOG_PROG));
1122         return 0;
1123
1124     case 0x34:                  /* PPS Time MID 52 */
1125         /*
1126          * Carl Carter from SiRF writes: "We do not output on the
1127          * second (unless you are using MID 52).  We make
1128          * measurements in the receiver in time with an internal
1129          * counter that is not slaved to GPS time, so the measurements
1130          * are made at a time that wanders around the second.  Then,
1131          * after the measurements are made (all normalized to the same
1132          * point in time) we dispatch the navigation software to make
1133          * a solution, and that solution comes out some 200 to 300 ms
1134          * after the measurement time.  So you may get a message at
1135          * 700 ms after the second that uses measurements time tagged
1136          * 450 ms after the second.  And if some other task jumps up
1137          * and delays things, that message may not come out until 900
1138          * ms after the second.  Things can get out of sync to the
1139          * point that if you try to resolve the GPS time of our 1 PPS
1140          * pulses using the navigation messages, you will find it
1141          * impossible to be consistent.  That is why I added
1142          * MID 52 to our system -- it is tied to the creation of the 1
1143          * PPS and always comes out right around the top of the
1144          * second."
1145          */
1146         return sirf_msg_ppstime(session, buf, len);
1147
1148     case 0x62:                  /* uBlox Extended Measured Navigation Data MID 98 */
1149         gpsd_report(LOG_PROG, "SiRF: uBlox EMND 0x62: %s.\n",
1150                     gpsd_hexdump_wrapper(buf, len, LOG_PROG));
1151         return sirf_msg_ublox(session, buf, len) | (CLEAR_IS | REPORT_IS);
1152
1153     case 0x80:                  /* Initialize Data Source MID 128 */
1154         gpsd_report(LOG_PROG, "SiRF: unused INIT 0x80: %s\n",
1155                     gpsd_hexdump_wrapper(buf, len, LOG_PROG));
1156         return 0;
1157
1158     case 0xe1:                  /* Development statistics messages MID 225 */
1159         /* FALLTHROUGH */
1160     case 0xff:                  /* Debug messages MID 255 */
1161         (void)sirf_msg_debug(buf, len);
1162         return 0;
1163
1164     default:
1165         gpsd_report(LOG_WARN, "SiRF: Unknown packet id %d length %zd: %s\n",
1166                     buf[0], len, gpsd_hexdump_wrapper(buf, len, LOG_WARN));
1167         return 0;
1168     }
1169 }
1170
1171 static gps_mask_t sirfbin_parse_input(struct gps_device_t *session)
1172 {
1173     gps_mask_t st;
1174
1175     if (session->packet.type == SIRF_PACKET) {
1176         st = sirf_parse(session, session->packet.outbuffer,
1177                         session->packet.outbuflen);
1178         session->gpsdata.dev.driver_mode = MODE_BINARY;
1179         return st;
1180 #ifdef NMEA_ENABLE
1181     } else if (session->packet.type == NMEA_PACKET) {
1182         st = nmea_parse((char *)session->packet.outbuffer, session);
1183         session->gpsdata.dev.driver_mode = MODE_NMEA;
1184         return st;
1185 #endif /* NMEA_ENABLE */
1186     } else
1187         return 0;
1188 }
1189
1190 static void sirfbin_event_hook(struct gps_device_t *session, event_t event)
1191 {
1192     if (event == event_identified || event == event_reactivate) {
1193         if (session->packet.type == NMEA_PACKET) {
1194             gpsd_report(LOG_PROG, "SiRF: Switching chip mode to binary.\n");
1195             (void)nmea_send(session,
1196                             "$PSRF100,0,%d,8,1,0",
1197                             session->gpsdata.dev.baudrate);
1198         }
1199         /* do this every time */
1200         {
1201             /*@ +charint @*/
1202             /* Poll Navigation Parameters MID 152
1203              * query for MID 19 */
1204             static unsigned char navparams[] = {
1205                 0xa0, 0xa2, 0x00, 0x02,
1206                 0x98,           /* MID 152 */
1207                 0x00,
1208                 0x00, 0x00, 0xb0, 0xb3
1209             };
1210             /* DGPS Source MID 133 */
1211             static unsigned char dgpscontrol[] = {
1212                 0xa0, 0xa2, 0x00, 0x07,
1213                 0x85,           /* MID 133 */
1214                 0x01,           /* use SBAS */
1215                 0x00, 0x00,
1216                 0x00, 0x00, 0x00,
1217                 0x00, 0x00, 0xb0, 0xb3
1218             };
1219             /* Set SBAS Parameters MID 170 */
1220             static unsigned char sbasparams[] = {
1221                 0xa0, 0xa2, 0x00, 0x06,
1222                 0xaa,           /* MID 170 */
1223                 0x00,           /* SBAS PRN */
1224                 0x01,           /* SBAS Mode */
1225                 0x00,           /* Auto PRN */
1226                 0x00, 0x00,
1227                 0x00, 0x00, 0xb0, 0xb3
1228             };
1229             /* Poll Software Version MID 132 */
1230             static unsigned char versionprobe[] = {
1231                 0xa0, 0xa2, 0x00, 0x02,
1232                 0x84,           /* MID 132 */
1233                 0x00,           /* unused */
1234                 0x00, 0x00, 0xb0, 0xb3
1235             };
1236             /* Set Message Rate MID 166 */
1237             static unsigned char requestecef[] = {
1238                 0xa0, 0xa2, 0x00, 0x08,
1239                 0xa6,           /* MID 166 */
1240                 0x00,           /* enable 1 */
1241                 0x02,           /* MID 2 */
1242                 0x01,           /* once per Sec */
1243                 0x00, 0x00,     /* unused */
1244                 0x00, 0x00,     /* unused */
1245                 0x00, 0x00, 0xb0, 0xb3
1246             };
1247             /* Set Message Rate MID 166 */
1248             static unsigned char requesttracker[] = {
1249                 0xa0, 0xa2, 0x00, 0x08,
1250                 0xa6,           /* MID 166 */
1251                 0x00,           /* enable 1 */
1252                 0x04,           /* MID 4 */
1253                 0x03,           /* every 3 sec */
1254                 0x00, 0x00,     /* unused */
1255                 0x00, 0x00,     /* unused */
1256                 0x00, 0x00, 0xb0, 0xb3
1257             };
1258             /* unset MID 29 0x1d */
1259             /* we do not decode it, so don't send it */
1260             static unsigned char unsetmid29[] = {
1261                 0xa0, 0xa2, 0x00, 0x08,
1262                 0xa6,           /* MID 166 */
1263                 0x00,           /* enable 1 */
1264                 0x1d,           /* MID 29 */
1265                 0x00,           /* never */
1266                 0x00, 0x00,     /* unused */
1267                 0x00, 0x00,     /* unused */
1268                 0x00, 0x00, 0xb0, 0xb3
1269             };
1270             /* unset MID 30 0x1e */
1271             /* we do not decode it, so don't send it */
1272             static unsigned char unsetmid30[] = {
1273                 0xa0, 0xa2, 0x00, 0x08,
1274                 0xa6,           /* MID 166 */
1275                 0x00,           /* enable 1 */
1276                 0x1e,           /* MID 30 */
1277                 0x00,           /* never */
1278                 0x00, 0x00,     /* unused */
1279                 0x00, 0x00,     /* unused */
1280                 0x00, 0x00, 0xb0, 0xb3
1281             };
1282             /*@ -charint @*/
1283
1284             gpsd_report(LOG_PROG, "SiRF: baudrate: %d\n",
1285                         session->gpsdata.dev.baudrate);
1286             (void)usleep(3330); /* guessed settling time */
1287             gpsd_report(LOG_PROG, "SiRF: unset MID 30...\n");
1288             (void)sirf_write(session->gpsdata.gps_fd, unsetmid30);
1289             (void)usleep(3330); /* guessed settling time */
1290
1291             gpsd_report(LOG_PROG,
1292                         "SiRF: Requesting periodic ecef reports...\n");
1293             (void)sirf_write(session->gpsdata.gps_fd, requestecef);
1294             gpsd_report(LOG_PROG,
1295                         "SiRF: Requesting periodic tracker reports...\n");
1296             (void)sirf_write(session->gpsdata.gps_fd, requesttracker);
1297             gpsd_report(LOG_PROG,
1298                         "SiRF: Setting DGPS control to use SBAS...\n");
1299             (void)sirf_write(session->gpsdata.gps_fd, dgpscontrol);
1300             gpsd_report(LOG_PROG,
1301                         "SiRF: Setting SBAS to auto/integrity mode...\n");
1302             (void)sirf_write(session->gpsdata.gps_fd, sbasparams);
1303
1304             gpsd_report(LOG_PROG, "SiRF: unset MID 29...\n");
1305             (void)sirf_write(session->gpsdata.gps_fd, unsetmid29);
1306
1307             gpsd_report(LOG_PROG, "SiRF: Probing for firmware version...\n");
1308             (void)sirf_write(session->gpsdata.gps_fd, versionprobe);
1309             gpsd_report(LOG_PROG,
1310                         "SiRF: Requesting navigation parameters...\n");
1311             (void)sirf_write(session->gpsdata.gps_fd, navparams);
1312         }
1313     }
1314     if (event == event_deactivate) {
1315
1316         /*@ +charint @*/
1317         static unsigned char moderevert[] = { 0xa0, 0xa2, 0x00, 0x0e,
1318             0x88,
1319             0x00, 0x00,         /* pad bytes */
1320             0x00,               /* degraded mode */
1321             0x00, 0x00,         /* pad bytes */
1322             0x00, 0x00,         /* altitude source */
1323             0x00,               /* altitude hold mode */
1324             0x00,               /* use last computed alt */
1325             0x00,               /* reserved */
1326             0x00,               /* degraded mode timeout */
1327             0x00,               /* dead reckoning timeout */
1328             0x00,               /* track smoothing */
1329             0x00, 0x00, 0xb0, 0xb3
1330         };
1331         /*@ -charint -shiftimplementation @*/
1332         putbyte(moderevert, 7, session->driver.sirf.degraded_mode);
1333         putbeword(moderevert, 10, session->driver.sirf.altitude_source_input);
1334         putbyte(moderevert, 12, session->driver.sirf.altitude_hold_mode);
1335         putbyte(moderevert, 13, session->driver.sirf.altitude_hold_source);
1336         putbyte(moderevert, 15, session->driver.sirf.degraded_timeout);
1337         putbyte(moderevert, 16, session->driver.sirf.dr_timeout);
1338         putbyte(moderevert, 17, session->driver.sirf.track_smooth_mode);
1339         /*@ +shiftimplementation @*/
1340         gpsd_report(LOG_PROG, "SiRF: Reverting navigation parameters...\n");
1341         (void)sirf_write(session->gpsdata.gps_fd, moderevert);
1342     }
1343 }
1344
1345 #ifdef ALLOW_RECONFIGURE
1346 static bool sirfbin_speed(struct gps_device_t *session,
1347                           speed_t speed, char parity, int stopbits)
1348 {
1349     return sirf_speed(session->gpsdata.gps_fd, speed, parity, stopbits);
1350 }
1351 #endif /* ALLOW_RECONFIGURE */
1352
1353 /* this is everything we export */
1354 /* *INDENT-OFF* */
1355 const struct gps_type_t sirf_binary =
1356 {
1357     .type_name      = "SiRF binary",    /* full name of type */
1358     .packet_type    = SIRF_PACKET,      /* associated lexer packet type */
1359     .trigger        = NULL,             /* no trigger */
1360     .channels       = SIRF_CHANNELS,    /* consumer-grade GPS */
1361     .probe_detect   = NULL,             /* no probe */
1362     .get_packet     = sirf_get,         /* be prepared for SiRF or NMEA */
1363     .parse_packet   = sirfbin_parse_input,/* parse message packets */
1364     .rtcm_writer    = pass_rtcm,        /* send RTCM data straight */
1365     .event_hook     = sirfbin_event_hook,/* lifetime event handler */
1366 #ifdef ALLOW_RECONFIGURE
1367     .speed_switcher = sirfbin_speed,    /* we can change baud rate */
1368     .mode_switcher  = sirfbin_mode,     /* there's a mode switcher */
1369     .rate_switcher  = NULL,             /* no sample-rate switcher */
1370     .min_cycle      = 1,                /* not relevant, no rate switch */
1371 #endif /* ALLOW_RECONFIGURE */
1372 #ifdef ALLOW_CONTROLSEND
1373     .control_send   = sirf_control_send,/* how to send a control string */
1374 #endif /* ALLOW_CONTROLSEND */
1375 #ifdef NTPSHM_ENABLE
1376     .ntp_offset     = sirf_ntp_offset,
1377 #endif /* NTP_SHM_ENABLE */
1378 };
1379 /* *INDENT-ON* */
1380 #endif /* defined(SIRF_ENABLE) && defined(BINARY_ENABLE) */