cleanup specfile for packaging
[profile/ivi/gpsd.git] / drivers.c
1 /*
2  * This file is Copyright (c) 2010 by the GPSD project
3  * BSD terms apply: see the file COPYING in the distribution root for details.
4  */
5 #include <sys/types.h>
6 #include "gpsd_config.h"
7 #ifdef HAVE_SYS_IOCTL_H
8 #include <sys/ioctl.h>
9 #endif /* HAVE_SYS_IOCTL_H */
10 #include <sys/time.h>
11 #include <stdlib.h>
12 #ifndef S_SPLINT_S
13 #include <unistd.h>
14 #endif /* S_SPLINT_S */
15 #include <string.h>
16 #include <errno.h>
17 #include <stdio.h>
18 #include <math.h>
19 #include <stdarg.h>
20
21 #include "gpsd.h"
22 #include "bits.h"               /* for getbeuw(), to extract big-endian words */
23
24 extern const struct gps_type_t zodiac_binary;
25 extern const struct gps_type_t ubx_binary;
26 extern const struct gps_type_t sirf_binary;
27
28 ssize_t generic_get(struct gps_device_t *session)
29 {
30     return packet_get(session->gpsdata.gps_fd, &session->packet);
31 }
32
33 #if defined(NMEA_ENABLE) || defined(SIRF_ENABLE) || defined(EVERMORE_ENABLE)  || defined(ITRAX_ENABLE)  || defined(NAVCOM_ENABLE)
34 ssize_t pass_rtcm(struct gps_device_t * session, char *buf, size_t rtcmbytes)
35 /* most GPSes take their RTCM corrections straight up */
36 {
37     return gpsd_write(session, buf, rtcmbytes);
38 }
39 #endif
40
41 #ifdef NMEA_ENABLE
42 /**************************************************************************
43  *
44  * Generic driver -- straight NMEA 0183
45  *
46  **************************************************************************/
47
48 gps_mask_t nmea_parse_input(struct gps_device_t * session)
49 {
50     const struct gps_type_t **dp;
51
52     if (session->packet.type == COMMENT_PACKET) {
53         return 0;
54     } else if (session->packet.type != NMEA_PACKET) {
55         for (dp = gpsd_drivers; *dp; dp++) {
56             if (session->packet.type == (*dp)->packet_type) {
57                 gpsd_report(LOG_WARN, "%s packet seen when NMEA expected.\n",
58                             (*dp)->type_name);
59                 (void)gpsd_switch_driver(session, (*dp)->type_name);
60                 return (*dp)->parse_packet(session);
61             }
62         }
63         return 0;
64     } else {                    /* session->packet.type == NMEA_PACKET) */
65
66         gps_mask_t st = 0;
67         /*
68          * Some packets do not end in \n, append one
69          * for good logging
70          */
71         gpsd_report(LOG_IO, "<= GPS: %s\n", session->packet.outbuffer);
72
73         if ((st =
74              nmea_parse((char *)session->packet.outbuffer, session)) == 0) {
75             gpsd_report(LOG_WARN, "unknown sentence: \"%s\"\n",
76                         session->packet.outbuffer);
77         }
78         for (dp = gpsd_drivers; *dp; dp++) {
79             char *trigger = (*dp)->trigger;
80
81             if (trigger != NULL
82                 && strncmp((char *)session->packet.outbuffer, trigger,
83                            strlen(trigger)) == 0) {
84                 gpsd_report(LOG_PROG, "found trigger string %s.\n", trigger);
85                 if (*dp != session->device_type) {
86                     (void)gpsd_switch_driver(session, (*dp)->type_name);
87                     if (session->device_type != NULL
88                         && session->device_type->event_hook != NULL)
89                         session->device_type->event_hook(session,
90                                                          event_triggermatch);
91                     st |= DEVICEID_IS;
92                 }
93             }
94         }
95         return st;
96     }
97 }
98
99 static void nmea_event_hook(struct gps_device_t *session, event_t event)
100 {
101     /*
102      * This is where we try to tickle NMEA devices into erevrealing their
103      * inner natures.
104      */
105     if (event == event_configure) {
106         /* change this guard if the probe count goes up */
107         if (session->packet.counter <= 8)
108             gpsd_report(LOG_WARN, "=> Probing device subtype %d\n",
109                         session->packet.counter);
110         /*
111          * The reason for splitting these probes up by packet sequence
112          * number, interleaving them with the first few packet receives,
113          * is because many generic-NMEA devices get confused if you send
114          * too much at them in one go.
115          *
116          * A fast response to an early probe will change drivers so the
117          * later ones won't be sent at all.  Thus, for best overall
118          * performance, order these to probe for the most popular types
119          * soonest.
120          *
121          * Note: don't make the trigger strings identical to the probe,
122          * because some NMEA devices (notably SiRFs) will just echo
123          * unknown strings right back at you. A useful dodge is to append
124          * a comma to the trigger, because that won't be in the response
125          * unless there is actual following data.
126          */
127         switch (session->packet.counter) {
128 #ifdef NMEA_ENABLE
129         case 0:
130             /* probe for Garmin serial GPS -- expect $PGRMC followed by data */
131             (void)nmea_send(session, "$PGRMCE");
132             break;
133 #endif /* NMEA_ENABLE */
134 #ifdef SIRF_ENABLE
135         case 1:
136             /*
137              * We used to try to probe for SiRF by issuing "$PSRF105,1"
138              * and expecting "$Ack Input105.".  But it turns out this
139              * only works for SiRF-IIs; SiRF-I and SiRF-III don't respond.
140              * Thus the only reliable probe is to try to flip the SiRF into
141              * binary mode, cluing in the library to revert it on close.
142              *
143              * SiRFs dominate the GPS-mouse market, so we used to put this test
144              * first. Unfortunately this causes problems for gpsctl, as it cannot
145              * select the NMEA driver without switching the device back to
146              * binary mode!  Fix this if we ever find a nondisruptive probe string.
147              */
148             (void)nmea_send(session,
149                             "$PSRF100,0,%d,%d,%d,0",
150                             session->gpsdata.dev.baudrate,
151                             9 - session->gpsdata.dev.stopbits,
152                             session->gpsdata.dev.stopbits);
153             session->back_to_nmea = true;
154             break;
155 #endif /* SIRF_ENABLE */
156 #ifdef NMEA_ENABLE
157         case 2:
158             /* probe for the FV-18 -- expect $PFEC,GPint followed by data */
159             (void)nmea_send(session, "$PFEC,GPint");
160             break;
161         case 3:
162             /* probe for the Trimble Copernicus */
163             (void)nmea_send(session, "$PTNLSNM,0139,01");
164             break;
165 #endif /* NMEA_ENABLE */
166 #ifdef EVERMORE_ENABLE
167         case 4:
168             /* Enable checksum and GGA(1s), GLL(0s), GSA(1s), GSV(1s), RMC(1s), VTG(0s), PEMT101(1s) */
169             /* EverMore will reply with: \x10\x02\x04\x38\x8E\xC6\x10\x03 */
170             (void)gpsd_write(session,
171                              "\x10\x02\x12\x8E\x7F\x01\x01\x00\x01\x01\x01\x00\x01\x00\x00\x00\x00\x00\x00\x13\x10\x03",
172                              22);
173             break;
174 #endif /* EVERMORE_ENABLE */
175 #ifdef ITRAX_ENABLE
176         case 5:
177             /* probe for iTrax, looking for "$PFST,OK" */
178             (void)nmea_send(session, "$PFST");
179             break;
180 #endif /* ITRAX_ENABLE */
181 #ifdef GPSCLOCK_ENABLE
182         case 6:
183             /* probe for Furuno Electric GH-79L4-N (GPSClock); expect $PFEC,GPssd */
184             (void)nmea_send(session, "$PFEC,GPsrq");
185             break;
186 #endif /* GPSCLOCK_ENABLE */
187 #ifdef ASHTECH_ENABLE
188         case 7:
189             /* probe for Ashtech -- expect $PASHR,RID */
190             (void)nmea_send(session, "$PASHQ,RID");
191             break;
192 #endif /* ASHTECH_ENABLE */
193 #ifdef UBX_ENABLE
194         case 8:
195             /* probe for UBX -- query software version */
196             (void)ubx_write(session, 0x0au, 0x04, NULL, 0);
197             break;
198 #endif /* UBX_ENABLE */
199 #ifdef MTK3301_ENABLE
200         case 9:
201             /* probe for MTK-3301 -- expect $PMTK705 */
202             (void)nmea_send(session, "$PMTK605");
203             break;
204 #endif /* MTK3301_ENABLE */
205         default:
206             break;
207         }
208     }
209 }
210
211 #ifdef ALLOW_RECONFIGURE
212 static void nmea_mode_switch(struct gps_device_t *session, int mode)
213 {
214     if (mode == MODE_BINARY) {
215 #if defined(SIRF_ENABLE) && defined(BINARY_ENABLE)
216         if (0 != (SIRF_PACKET & session->observed)) {
217             /* it was SiRF binary once, do it again */
218             sirf_binary.mode_switcher(session, mode);
219         }
220 #endif
221     }
222 }
223 #endif /* ALLOW_RECONFIGURE */
224
225 /* *INDENT-OFF* */
226 const struct gps_type_t nmea = {
227     .type_name      = "Generic NMEA",   /* full name of type */
228     .packet_type    = NMEA_PACKET,      /* associated lexer packet type */
229     .trigger        = NULL,             /* it's the default */
230     .channels       = 12,               /* consumer-grade GPS */
231     .probe_detect   = NULL,             /* no probe */
232     .get_packet     = generic_get,      /* use generic packet getter */
233     .parse_packet   = nmea_parse_input, /* how to interpret a packet */
234     .rtcm_writer    = pass_rtcm,        /* write RTCM data straight */
235     .event_hook     = nmea_event_hook,  /* lifetime event handler */
236 #ifdef ALLOW_RECONFIGURE
237     .speed_switcher = NULL,             /* no speed switcher */
238     .mode_switcher  = nmea_mode_switch, /* no mode switcher */
239     .rate_switcher  = NULL,             /* no sample-rate switcher */
240     .min_cycle      = 1,                /* not relevant, no rate switch */
241 #endif /* ALLOW_RECONFIGURE */
242 #ifdef ALLOW_CONTROLSEND
243     .control_send   = nmea_write,       /* how to send control strings */
244 #endif /* ALLOW_CONTROLSEND */
245 #ifdef NTPSHM_ENABLE
246     .ntp_offset     = NULL,             /* no method for NTP fudge factor */
247 #endif /* NTPSHM_ ENABLE */
248 };
249 /* *INDENT-ON* */
250
251 #if defined(GARMIN_ENABLE) && defined(NMEA_ENABLE)
252 /**************************************************************************
253  *
254  * Garmin NMEA
255  *
256  **************************************************************************/
257
258 #ifdef ALLOW_RECONFIGURE
259 static void garmin_mode_switch(struct gps_device_t *session, int mode)
260 /* only does anything in one direction, going to Garmin binary driver */
261 {
262     if (mode == MODE_BINARY) {
263         (void)nmea_send(session, "$PGRMC1,1,2,1,,,,2,W,N");
264         (void)nmea_send(session, "$PGRMI,,,,,,,R");
265         (void)usleep(333);      /* standard Garmin settling time */
266         session->gpsdata.dev.driver_mode = MODE_BINARY;
267     }
268 }
269 #endif /* ALLOW_RECONFIGURE */
270
271 static void garmin_nmea_event_hook(struct gps_device_t *session,
272                                    event_t event)
273 {
274     if (event == event_driver_switch) {
275         /* forces a reconfigure as the following packets come in */
276         session->packet.counter = 0;
277     }
278     if (event == event_configure) {
279         /*
280          * And here's that reconfigure.  It's spplit up like this because
281          * receivers like the Garmin GPS-10 don't handle having having a lot of
282          * probes shoved at them very well.
283          */
284         switch (session->packet.counter) {
285         case 0:
286             /* reset some config, AutoFix, WGS84, PPS
287              * Set the PPS pulse length to 40ms which leaves the Garmin 18-5hz
288              * with a 160ms low state.
289              * NOTE: new PPS only takes effect after next power cycle
290              */
291             (void)nmea_send(session, "$PGRMC,A,,100,,,,,,A,,1,2,1,30");
292             break;
293         case 1:
294             /* once a sec, no averaging, NMEA 2.3, WAAS */
295             (void)nmea_send(session, "$PGRMC1,1,1,1,,,,2,W,N");
296             break;
297         case 2:
298             /* get some more config info */
299             (void)nmea_send(session, "$PGRMC1E");
300             break;
301         case 3:
302             /* turn off all output except GGA */
303             (void)nmea_send(session, "$PGRMO,,2");
304             (void)nmea_send(session, "$PGRMO,GPGGA,1");
305             break;
306         case 4:
307             /* enable GPGGA, GPGSA, GPGSV, GPRMC on Garmin serial GPS */
308             (void)nmea_send(session, "$PGRMO,GPGSA,1");
309             break;
310         case 5:
311             (void)nmea_send(session, "$PGRMO,GPGSV,1");
312             break;
313         case 6:
314             (void)nmea_send(session, "$PGRMO,GPRMC,1");
315             break;
316         case 7:
317             (void)nmea_send(session, "$PGRMO,PGRME,1");
318             break;
319         }
320     }
321 }
322
323 /* *INDENT-OFF* */
324 const struct gps_type_t garmin = {
325     .type_name      = "Garmin NMEA",    /* full name of type */
326     .packet_type    = NMEA_PACKET,      /* associated lexer packet type */
327     .trigger        = "$PGRMC,",        /* Garmin private */
328     .channels       = 12,               /* not used by this driver */
329     .probe_detect   = NULL,             /* no probe */
330     .get_packet     = generic_get,      /* use generic packet getter */
331     .parse_packet   = nmea_parse_input, /* how to interpret a packet */
332     .rtcm_writer    = NULL,             /* some do, some don't, skip for now */
333     .event_hook     = garmin_nmea_event_hook,   /* lifetime event handler */
334 #ifdef ALLOW_RECONFIGURE
335     .speed_switcher = NULL,                     /* no speed switcher */
336     .mode_switcher  = garmin_mode_switch,       /* mode switcher */
337     .rate_switcher  = NULL,             /* no sample-rate switcher */
338     .min_cycle      = 1,                /* not relevant, no rate switch */
339 #endif /*ALLOW_RECONFIGURE */
340 #ifdef ALLOW_CONTROLSEND
341     .control_send   = nmea_write,       /* how to send control strings */
342 #endif /* ALLOW_CONTROLSEND */
343 #ifdef NTPSHM_ENABLE
344     .ntp_offset     = NULL,             /* no method for NTP fudge factor */
345 #endif /* NTPSHM_ ENABLE */
346 };
347 /* *INDENT-ON* */
348 #endif /* GARMIN_ENABLE && NMEA_ENABLE */
349
350 #ifdef ASHTECH_ENABLE
351 /**************************************************************************
352  *
353  * Ashtech (then Thales, now Magellan Professional) Receivers
354  *
355  **************************************************************************/
356
357 static void ashtech_event_hook(struct gps_device_t *session, event_t event)
358 {
359     if (event == event_wakeup)
360         (void)nmea_send(session, "$PASHQ,RID");
361     if (event == event_identified) {
362         /* turn WAAS on. can't hurt... */
363         (void)nmea_send(session, "$PASHS,WAS,ON");
364         /* reset to known output state */
365         (void)nmea_send(session, "$PASHS,NME,ALL,A,OFF");
366         /* then turn on some useful sentences */
367 #ifdef ASHTECH_NOTYET
368         /* we could parse these, but they're oversize so they get dropped */
369         (void)nmea_send(session, "$PASHS,NME,POS,A,ON");
370         (void)nmea_send(session, "$PASHS,NME,SAT,A,ON");
371 #else
372         (void)nmea_send(session, "$PASHS,NME,GGA,A,ON");
373         (void)nmea_send(session, "$PASHS,NME,GSA,A,ON");
374         (void)nmea_send(session, "$PASHS,NME,GSV,A,ON");
375         (void)nmea_send(session, "$PASHS,NME,RMC,A,ON");
376 #endif
377         (void)nmea_send(session, "$PASHS,NME,ZDA,A,ON");
378     }
379 }
380
381 /* *INDENT-OFF* */
382 const struct gps_type_t ashtech = {
383     .type_name      = "Ashtech",        /* full name of type */
384     .packet_type    = NMEA_PACKET,      /* associated lexer packet type */
385     .trigger        = "$PASHR,RID,",    /* Ashtech receivers respond thus */
386     .channels       = 24,               /* not used, GG24 has 24 channels */
387     .probe_detect   = NULL,             /* no probe */
388     .get_packet     = generic_get,      /* how to get a packet */
389     .parse_packet   = nmea_parse_input, /* how to interpret a packet */
390     .rtcm_writer    = pass_rtcm,        /* write RTCM data straight */
391     .event_hook     = ashtech_event_hook, /* lifetime event handler */
392 #ifdef ALLOW_RECONFIGURE
393     .speed_switcher = NULL,             /* no speed switcher */
394     .mode_switcher  = NULL,             /* no mode switcher */
395     .rate_switcher  = NULL,             /* no sample-rate switcher */
396     .min_cycle      = 1,                /* not relevant, no rate switch */
397 #endif /* ALLOW_RECONFIGURE */
398 #ifdef ALLOW_CONTROLSEND
399     .control_send   = nmea_write,       /* how to send control strings */
400 #endif /* ALLOW_CONTROLSEND */
401 #ifdef NTPSHM_ENABLE
402     .ntp_offset     = NULL,             /* no method for NTP fudge factor */
403 #endif /* NTPSHM_ ENABLE */
404 };
405 /* *INDENT-ON* */
406 #endif /* ASHTECH_ENABLE */
407
408 #ifdef FV18_ENABLE
409 /**************************************************************************
410  *
411  * FV18 -- uses 2 stop bits, needs to be told to send GSAs
412  *
413  **************************************************************************/
414
415 static void fv18_event_hook(struct gps_device_t *session, event_t event)
416 {
417     /*
418      * Tell an FV18 to send GSAs so we'll know if 3D is accurate.
419      * Suppress GLL and VTG.  Enable ZDA so dates will be accurate for replay.
420      * It's possible we might not need to redo this on event_reactivate,
421      * but doing so is safe and cheap.
422      */
423     if (event == event_identified || event == event_reactivate)
424         (void)nmea_send(session,
425                         "$PFEC,GPint,GSA01,DTM00,ZDA01,RMC01,GLL00,VTG00,GSV05");
426 }
427
428 /* *INDENT-OFF* */
429 const struct gps_type_t fv18 = {
430     .type_name      = "San Jose Navigation FV18",       /* full name of type */
431     .packet_type    = NMEA_PACKET,      /* associated lexer packet type */
432     .trigger        = "$PFEC,GPint,",   /* FV18s should echo the probe */
433     .channels       = 12,               /* not used by this driver */
434     .probe_detect   = NULL,             /* no probe */
435     .get_packet     = generic_get,      /* how to get a packet */
436     .parse_packet   = nmea_parse_input, /* how to interpret a packet */
437     .rtcm_writer    = pass_rtcm,        /* write RTCM data straight */
438     .event_hook     = fv18_event_hook,  /* lifetime event handler */
439 #ifdef ALLOW_RECONFIGURE
440     .speed_switcher = NULL,             /* no speed switcher */
441     .mode_switcher  = NULL,             /* no mode switcher */
442     .rate_switcher  = NULL,             /* no sample-rate switcher */
443     .min_cycle      = 1,                /* not relevant, no rate switch */
444 #endif /* ALLOW_RECONFIGURE */
445 #ifdef ALLOW_CONTROLSEND
446     .control_send   = nmea_write,       /* how to send control strings */
447 #endif /* ALLOW_CONTROLSEND */
448 #ifdef NTPSHM_ENABLE
449     .ntp_offset     = NULL,             /* no method for NTP fudge factor */
450 #endif /* NTPSHM_ ENABLE */
451 };
452 /* *INDENT-ON* */
453 #endif /* FV18_ENABLE */
454
455 #ifdef GPSCLOCK_ENABLE
456 /**************************************************************************
457  *
458  * Furuno Electric GPSClock (GH-79L4)
459  *
460  **************************************************************************/
461
462 /*
463  * Based on http://www.tecsys.de/fileadmin/user_upload/pdf/gh79_1an_intant.pdf
464  */
465
466 static void gpsclock_event_hook(struct gps_device_t *session, event_t event)
467 {
468     /*
469      * Michael St. Laurent <mikes@hartwellcorp.com> reports that you have to
470      * ignore the trailing PPS edge when extracting time from this chip.
471      */
472     if (event == event_identified || event == event_reactivate) {
473         gpsd_report(LOG_INF, "PPS trailing edge will be ignored\n");
474         session->driver.nmea.ignore_trailing_edge = true;
475     }
476 }
477
478 /* *INDENT-OFF* */
479 const struct gps_type_t gpsclock = {
480     .type_name      = "Furuno Electric GH-79L4",        /* full name of type */
481     .packet_type    = NMEA_PACKET,      /* associated lexer packet type */
482     .trigger        = "$PFEC,GPssd",    /* GPSclock should return this */
483     .channels       = 12,               /* not used by this driver */
484     .probe_detect   = NULL,             /* no probe */
485     .get_packet     = generic_get,      /* how to get a packet */
486     .parse_packet   = nmea_parse_input, /* how to interpret a packet */
487     .rtcm_writer    = pass_rtcm,        /* write RTCM data straight */
488     .event_hook     = gpsclock_event_hook,      /* lifetime event handler */
489 #ifdef ALLOW_RECONFIGURE
490     .speed_switcher = NULL,             /* no speed switcher */
491     .mode_switcher  = NULL,             /* no mode switcher */
492     .rate_switcher  = NULL,             /* sample rate is fixed */
493     .min_cycle      = 1,                /* sample rate is fixed */
494 #endif /* ALLOW_RECONFIGURE */
495 #ifdef ALLOW_CONTROLSEND
496     .control_send   = nmea_write,       /* how to send control strings */
497 #endif /* ALLOW_CONTROLSEND */
498 #ifdef NTPSHM_ENABLE
499     .ntp_offset     = NULL,             /* no method for NTP fudge factor */
500 #endif /* NTPSHM_ ENABLE */
501 };
502 /* *INDENT-ON* */
503 #endif /* GPSCLOCK_ENABLE */
504
505 #ifdef TRIPMATE_ENABLE
506 /**************************************************************************
507  *
508  * TripMate -- extended NMEA, gets faster fix when primed with lat/long/time
509  *
510  **************************************************************************/
511
512 /*
513  * Some technical FAQs on the TripMate:
514  * http://vancouver-webpages.com/pub/peter/tripmate.faq
515  * http://www.asahi-net.or.jp/~KN6Y-GTU/tripmate/trmfaqe.html
516  * The TripMate was discontinued sometime before November 1998
517  * and was replaced by the Zodiac EarthMate.
518  */
519
520 static void tripmate_event_hook(struct gps_device_t *session, event_t event)
521 {
522     /* TripMate requires this response to the ASTRAL it sends at boot time */
523     if (event == event_identified)
524         (void)nmea_send(session, "$IIGPQ,ASTRAL");
525     /* stop it sending PRWIZCH */
526     if (event == event_identified || event == event_reactivate)
527         (void)nmea_send(session, "$PRWIILOG,ZCH,V,,");
528 }
529
530 /* *INDENT-OFF* */
531 static const struct gps_type_t tripmate = {
532     .type_name     = "Delorme TripMate",        /* full name of type */
533     .packet_type   = NMEA_PACKET,               /* lexer packet type */
534     .trigger       ="ASTRAL",                   /* tells us to switch */
535     .channels      = 12,                        /* consumer-grade GPS */
536     .probe_detect  = NULL,                      /* no probe */
537     .get_packet    = generic_get,               /* how to get a packet */
538     .parse_packet  = nmea_parse_input,          /* how to interpret a packet */
539     .rtcm_writer   = pass_rtcm,                 /* send RTCM data straight */
540     .event_hook    = tripmate_event_hook,       /* lifetime event handler */
541 #ifdef ALLOW_RECONFIGURE
542     .speed_switcher= NULL,                      /* no speed switcher */
543     .mode_switcher = NULL,                      /* no mode switcher */
544     .rate_switcher = NULL,                      /* no sample-rate switcher */
545     .min_cycle     = 1,                         /* no rate switch */
546 #endif /* ALLOW_RECONFIGURE */
547 #ifdef ALLOW_CONTROLSEND
548     .control_send  = nmea_write,        /* how to send control strings */
549 #endif /* ALLOW_CONTROLSEND */
550 #ifdef NTPSHM_ENABLE
551     .ntp_offset     = NULL,             /* no method for NTP fudge factor */
552 #endif /* NTPSHM_ ENABLE */
553 };
554 /* *INDENT-ON* */
555 #endif /* TRIPMATE_ENABLE */
556
557 #ifdef EARTHMATE_ENABLE
558 /**************************************************************************
559  *
560  * Zodiac EarthMate textual mode
561  *
562  * Note: This is the pre-2003 version using Zodiac binary protocol.
563  * There is a good HOWTO at <http://www.hamhud.net/ka9mva/earthmate.htm>.
564  * It has been replaced with a design that uses a SiRF chipset.
565  *
566  **************************************************************************/
567
568 static void earthmate_event_hook(struct gps_device_t *session, event_t event)
569 {
570     if (event == event_identified) {
571         (void)gpsd_write(session, "EARTHA\r\n", 8);
572         (void)usleep(10000);
573         (void)gpsd_switch_driver(session, "Zodiac Binary");
574     }
575 }
576
577 /*@ -redef @*/
578 /* *INDENT-OFF* */
579 static const struct gps_type_t earthmate = {
580     .type_name     = "Delorme EarthMate (pre-2003, Zodiac chipset)",
581     .packet_type   = NMEA_PACKET,       /* associated lexer packet type */
582     .trigger       = "EARTHA",                  /* Earthmate trigger string */
583     .channels      = 12,                        /* not used by NMEA parser */
584     .probe_detect  = NULL,                      /* no probe */
585     .get_packet    = generic_get,               /* how to get a packet */
586     .parse_packet  = nmea_parse_input,          /* how to interpret a packet */
587     .rtcm_writer   = NULL,                      /* don't send RTCM data */
588     .event_hook    = earthmate_event_hook,      /* lifetime event handler */
589 #ifdef ALLOW_RECONFIGURE
590     .speed_switcher= NULL,                      /* no speed switcher */
591     .mode_switcher = NULL,                      /* no mode switcher */
592     .rate_switcher = NULL,                      /* no sample-rate switcher */
593     .min_cycle     = 1,                         /* no rate switch */
594 #endif /* ALLOW_RECONFIGURE */
595 #ifdef ALLOW_CONTROLSEND
596     .control_send  = nmea_write,        /* how to send control strings */
597 #endif /* ALLOW_CONTROLSEND */
598 #ifdef NTPSHM_ENABLE
599     .ntp_offset     = NULL,             /* no method for NTP fudge factor */
600 #endif /* NTPSHM_ ENABLE */
601 };
602 /*@ -redef @*/
603 /* *INDENT-ON* */
604 #endif /* EARTHMATE_ENABLE */
605
606 #endif /* NMEA_ENABLE */
607
608 #ifdef TNT_ENABLE
609 /**************************************************************************
610  * True North Technologies - Revolution 2X Digital compass
611  *
612  * More info: http://www.tntc.com/
613  *
614  * This is a digital compass which uses magnetometers to measure the
615  * strength of the earth's magnetic field. Based on these measurements
616  * it provides a compass heading using NMEA formatted output strings.
617  * This is useful to supplement the heading provided by another GPS
618  * unit. A GPS heading is unreliable at slow speed or no speed.
619  *
620  **************************************************************************/
621
622 static void tnt_add_checksum(char *sentence)
623 /* add NMEA-style CRC checksum to a command */
624 {
625     unsigned char sum = '\0';
626     char c, *p = sentence;
627
628     if (*p == '@') {
629         p++;
630     } else {
631         gpsd_report(LOG_ERROR, "Bad TNT sentence: '%s'\n", sentence);
632     }
633     while (((c = *p) != '\0')) {
634         sum ^= c;
635         p++;
636     }
637     (void)snprintf(p, 6, "*%02X\r\n", (unsigned int)sum);
638 }
639
640
641 static ssize_t tnt_control_send(struct gps_device_t *session,
642                                 char *msg, size_t len)
643 /* send a control string in TNT native formal */
644 {
645     ssize_t status;
646
647     tnt_add_checksum(msg);
648     status = write(session->gpsdata.gps_fd, msg, strlen(msg));
649     (void)tcdrain(session->gpsdata.gps_fd);
650     return status;
651 }
652
653 static bool tnt_send(struct gps_device_t *session, const char *fmt, ...)
654 /* printf(3)-like TNT command generator */
655 {
656     char buf[BUFSIZ];
657     va_list ap;
658     ssize_t sent;
659
660     va_start(ap, fmt);
661     (void)vsnprintf(buf, sizeof(buf) - 5, fmt, ap);
662     va_end(ap);
663     sent = tnt_control_send(session, buf, strlen(buf));
664     if (sent == (ssize_t) strlen(buf)) {
665         gpsd_report(LOG_IO, "=> GPS: %s\n", buf);
666         return true;
667     } else {
668         gpsd_report(LOG_WARN, "=> GPS: %s FAILED\n", buf);
669         return false;
670     }
671 }
672
673 #ifdef ALLOW_RECONFIGURE
674 static bool tnt_speed(struct gps_device_t *session,
675                       speed_t speed, char parity, int stopbits)
676 {
677     /*
678      * Baud rate change followed by device reset.
679      * See page 40 of Technical Guide 1555-B.  We need:
680      * 2400 -> 1, 4800 -> 2, 9600 -> 3, 19200 -> 4, 38400 -> 5
681      */
682     unsigned int val = speed / 2400u;   /* 2400->1, 4800->2, 9600->4, 19200->8...  */
683     unsigned int i = 0;
684
685     /* fast way to compute log2(val) */
686     while ((val >> i) > 1)
687         ++i;
688     return tnt_send(session, "@B6=%d", i + 1)
689         && tnt_send(session, "@F28.6=1");
690 }
691 #endif /* ALLOW_RECONFIGURE */
692
693 static void tnt_event_hook(struct gps_device_t *session, event_t event)
694 /* TNT lifetime event hook */
695 {
696     if (event == event_wakeup) {
697         (void)tnt_send(session, "@F0.3=1");     /* set run mode */
698         (void)tnt_send(session, "@F2.2=1");     /* report in degrees */
699     }
700 }
701
702 /* *INDENT-OFF* */
703 const struct gps_type_t trueNorth = {
704     .type_name      = "True North",     /* full name of type */
705     .packet_type    = NMEA_PACKET,      /* associated lexer packet type */
706     .trigger        = "$PTNTHTM",       /* their proprietary sentence */
707     .channels       = 0,                /* not an actual GPS at all */
708     .probe_detect   = NULL,             /* no probe in run mode */
709     .get_packet     = generic_get,      /* how to get a packet */
710     .parse_packet   = nmea_parse_input, /* how to interpret a packet */
711     .rtcm_writer    = NULL,             /* Don't send */
712     .event_hook     = tnt_event_hook,   /* lifetime event handler */
713 #ifdef ALLOW_RECONFIGURE
714     .speed_switcher = tnt_speed,        /* no speed switcher */
715     .mode_switcher  = NULL,             /* no mode switcher */
716     .rate_switcher  = NULL,             /* no wrapup */
717     .min_cycle      = 0.5,              /* fixed at 20 samples per second */
718 #endif /* ALLOW_RECONFIGURE */
719 #ifdef ALLOW_CONTROLSEND
720     .control_send   = tnt_control_send, /* how to send control strings */
721 #endif /* ALLOW_CONTROLSEND */
722 #ifdef NTPSHM_ENABLE
723     .ntp_offset     = NULL,
724 #endif /* NTPSHM_ ENABLE */
725 };
726 /* *INDENT-ON* */
727 #endif
728
729 #ifdef OCEANSERVER_ENABLE
730 /**************************************************************************
731  * OceanServer - Digital Compass, OS5000 Series
732  *
733  * More info: http://www.ocean-server.com/download/OS5000_Compass_Manual.pdf
734  *
735  * This is a digital compass which uses magnetometers to measure the
736  * strength of the earth's magnetic field. Based on these measurements
737  * it provides a compass heading using NMEA formatted output strings.
738  * This is useful to supplement the heading provided by another GPS
739  * unit. A GPS heading is unreliable at slow speed or no speed.
740  *
741  **************************************************************************/
742
743 static int oceanserver_send(int fd, const char *fmt, ...)
744 {
745     int status;
746     char buf[BUFSIZ];
747     va_list ap;
748
749     va_start(ap, fmt);
750     (void)vsnprintf(buf, sizeof(buf) - 5, fmt, ap);
751     va_end(ap);
752     (void)strlcat(buf, "\e", BUFSIZ);
753     status = (int)write(fd, buf, strlen(buf));
754     (void)tcdrain(fd);
755     if (status == (int)strlen(buf)) {
756         gpsd_report(LOG_IO, "=> GPS: %s\n", buf);
757         return status;
758     } else {
759         gpsd_report(LOG_WARN, "=> GPS: %s FAILED\n", buf);
760         return -1;
761     }
762 }
763
764 static void oceanserver_event_hook(struct gps_device_t *session,
765                                    event_t event)
766 {
767     if (event == event_configure && session->packet.counter == 0) {
768         /* report in NMEA format */
769         (void)oceanserver_send(session->gpsdata.gps_fd, "2\n");
770         /* ship all fields */
771         (void)oceanserver_send(session->gpsdata.gps_fd, "X2047");
772     }
773 }
774
775 /* *INDENT-OFF* */
776 static const struct gps_type_t oceanServer = {
777     .type_name      = "OceanServer Digital Compass OS5000", /* full name of type */
778     .packet_type    = NMEA_PACKET,      /* associated lexer packet type */
779     .trigger        = "$OHPR,",         /* detect their main sentence */
780     .channels       = 0,                /* not an actual GPS at all */
781     .probe_detect   = NULL,
782     .get_packet     = generic_get,      /* how to get a packet */
783     .parse_packet   = nmea_parse_input, /* how to interpret a packet */
784     .rtcm_writer    = NULL,             /* Don't send */
785     .event_hook     = oceanserver_event_hook,
786 #ifdef ALLOW_RECONFIGURE
787     .speed_switcher = NULL,             /* no speed switcher */
788     .mode_switcher  = NULL,             /* no mode switcher */
789     .rate_switcher  = NULL,             /* no wrapup */
790     .min_cycle      = 1,                /* not relevant, no rate switch */
791 #endif /* ALLOW_RECONFIGURE */
792 #ifdef ALLOW_CONTROLSEND
793     .control_send   = nmea_write,       /* how to send control strings */
794 #endif /* ALLOW_CONTROLSEND */
795 #ifdef NTPSHM_ENABLE
796     .ntp_offset     = NULL,
797 #endif /* NTPSHM_ ENABLE */
798 };
799 /* *INDENT-ON* */
800 #endif
801
802 #ifdef RTCM104V2_ENABLE
803 /**************************************************************************
804  *
805  * RTCM-104 (v2), used for broadcasting DGPS corrections and by DGPS radios
806  *
807  **************************************************************************/
808
809 static gps_mask_t rtcm104v2_analyze(struct gps_device_t *session)
810 {
811     rtcm2_unpack(&session->gpsdata.rtcm2, (char *)session->packet.isgps.buf);
812     gpsd_report(LOG_RAW, "RTCM 2.x packet type 0x%02x length %d words: %s\n",
813                 session->gpsdata.rtcm2.type,
814                 session->gpsdata.rtcm2.length + 2,
815                 gpsd_hexdump_wrapper(session->packet.isgps.buf,
816                                      (session->gpsdata.rtcm2.length +
817                                       2) * sizeof(isgps30bits_t), LOG_RAW));
818     return RTCM2_IS;
819 }
820
821 /* *INDENT-OFF* */
822 static const struct gps_type_t rtcm104v2 = {
823     .type_name     = "RTCM104V2",       /* full name of type */
824     .packet_type   = RTCM2_PACKET,      /* associated lexer packet type */
825     .trigger       = NULL,              /* no recognition string */
826     .channels      = 0,                 /* not used */
827     .probe_detect  = NULL,              /* no probe */
828     .get_packet    = generic_get,       /* how to get a packet */
829     .parse_packet  = rtcm104v2_analyze, /*  */
830     .rtcm_writer   = NULL,              /* don't send RTCM data,  */
831     .event_hook    = NULL,              /* no event_hook */
832 #ifdef ALLOW_RECONFIGURE
833     .speed_switcher= NULL,              /* no speed switcher */
834     .mode_switcher = NULL,              /* no mode switcher */
835     .rate_switcher = NULL,              /* no sample-rate switcher */
836     .min_cycle     = 1,                 /* not relevant, no rate switch */
837 #endif /* ALLOW_RECONFIGURE */
838 #ifdef ALLOW_CONTROLSEND
839     .control_send   = nmea_write,       /* how to send control strings */
840 #endif /* ALLOW_CONTROLSEND */
841 #ifdef NTPSHM_ENABLE
842     .ntp_offset     = NULL,
843 #endif /* NTPSHM_ ENABLE */
844 };
845 /* *INDENT-ON* */
846 #endif /* RTCM104V2_ENABLE */
847 #ifdef RTCM104V3_ENABLE
848 /**************************************************************************
849  *
850  * RTCM-104 (v3), used for broadcasting DGPS corrections and by DGPS radios
851  *
852  **************************************************************************/
853
854 static gps_mask_t rtcm104v3_analyze(struct gps_device_t *session)
855 {
856     uint16_t length = getbeuw(session->packet.inbuffer, 1);
857     uint16_t type = getbeuw(session->packet.inbuffer, 3) >> 4;
858
859     /* *INDENT-OFF* */
860     gpsd_report(LOG_RAW, "RTCM 3.x packet type %d length %d words: %s\n",
861                 type, length, gpsd_hexdump_wrapper(session->packet.inbuffer,
862                                    (size_t) (session->gpsdata.rtcm3.length),
863                                    LOG_RAW));
864     /* *INDENT-ON* */
865     return RTCM3_IS;
866 }
867
868 /* *INDENT-OFF* */
869 static const struct gps_type_t rtcm104v3 = {
870     .type_name     = "RTCM104V3",       /* full name of type */
871     .packet_type   = RTCM3_PACKET,      /* associated lexer packet type */
872     .trigger       = NULL,              /* no recognition string */
873     .channels      = 0,                 /* not used */
874     .probe_detect  = NULL,              /* no probe */
875     .get_packet    = generic_get,       /* how to get a packet */
876     .parse_packet  = rtcm104v3_analyze, /*  */
877     .rtcm_writer   = NULL,              /* don't send RTCM data,  */
878     .event_hook    = NULL,              /* no event hook */
879 #ifdef ALLOW_RECONFIGURE
880     .speed_switcher= NULL,              /* no speed switcher */
881     .mode_switcher = NULL,              /* no mode switcher */
882     .rate_switcher = NULL,              /* no sample-rate switcher */
883     .min_cycle     = 1,                 /* not relevant, no rate switch */
884 #endif /* ALLOW_RECONFIGURE */
885 #ifdef ALLOW_CONTROLSEND
886     .control_send   = nmea_write,       /* how to send control strings */
887 #endif /* ALLOW_CONTROLSEND */
888 #ifdef NTPSHM_ENABLE
889     .ntp_offset     = NULL,
890 #endif /* NTPSHM_ ENABLE */
891 };
892 /* *INDENT-ON* */
893 #endif /* RTCM104V3_ENABLE */
894
895 #ifdef GARMINTXT_ENABLE
896 /**************************************************************************
897  *
898  * Garmin Simple Text protocol
899  *
900  **************************************************************************/
901
902 static gps_mask_t garmintxt_parse_input(struct gps_device_t *session)
903 {
904     if (session->packet.type == COMMENT_PACKET) {
905         return 0;
906     } else if (session->packet.type == GARMINTXT_PACKET) {      
907         //gpsd_report(LOG_PROG, "Garmin Simple Text packet\n");
908         return garmintxt_parse(session);
909     } else {
910         const struct gps_type_t **dp;
911
912         for (dp = gpsd_drivers; *dp; dp++) {
913             if (session->packet.type == (*dp)->packet_type) {
914                 gpsd_report(LOG_WARN, "%s packet seen when NMEA expected.\n",
915                             (*dp)->type_name);
916                 (void)gpsd_switch_driver(session, (*dp)->type_name);
917                 return (*dp)->parse_packet(session);
918             }
919         }
920         return 0;
921     }
922 }
923
924 /* *INDENT-OFF* */
925 static const struct gps_type_t garmintxt = {
926     .type_name     = "Garmin Simple Text",              /* full name of type */
927     .packet_type   = GARMINTXT_PACKET,  /* associated lexer packet type */
928     .trigger       = NULL,              /* no recognition string */
929     .channels      = 0,                 /* not used */
930     .probe_detect  = NULL,              /* no probe */
931     .get_packet    = generic_get,       /* how to get a packet */
932     .parse_packet  = garmintxt_parse_input,     /*  */
933     .rtcm_writer   = NULL,              /* don't send RTCM data,  */
934     .event_hook    = NULL,              /* no event hook */
935 #ifdef ALLOW_RECONFIGURE
936     .speed_switcher= NULL,              /* no speed switcher */
937     .mode_switcher = NULL,              /* no mode switcher */
938     .rate_switcher = NULL,              /* no sample-rate switcher */
939     .min_cycle     = 1,                 /* not relevant, no rate switch */
940 #endif /* ALLOW_RECONFIGURE */
941 #ifdef ALLOW_CONTROLSEND
942     .control_send   = nmea_write,       /* how to send control strings */
943 #endif /* ALLOW_CONTROLSEND */
944 #ifdef NTPSHM_ENABLE
945     .ntp_offset     = NULL,
946 #endif /* NTPSHM_ ENABLE */
947 };
948 /* *INDENT-ON* */
949 #endif /* GARMINTXT_ENABLE */
950
951 #ifdef MTK3301_ENABLE
952 /**************************************************************************
953  *
954  * MTK-3301
955  *
956  **************************************************************************/
957 const char *mtk_reasons[4] =
958     { "Invalid", "Unsupported", "Valid but Failed", "Valid success" };
959
960 gps_mask_t processMTK3301(int c UNUSED, char *field[],
961                           struct gps_device_t *session)
962 {
963     int msg, reason;
964     gps_mask_t mask;
965     mask = 1;                   //ONLINE_IS;
966
967     switch (msg = atoi(&(field[0])[4])) {
968     case 705:                   /*  */
969         (void)strlcat(session->subtype, field[1], sizeof(session->subtype));
970         (void)strlcat(session->subtype, "-", sizeof(session->subtype));
971         (void)strlcat(session->subtype, field[2], sizeof(session->subtype));
972         return 0;               /* return a unknown sentence, which will cause the driver switch */
973     case 001:                   /* ACK / NACK */
974         reason = atoi(field[2]);
975         if (atoi(field[1]) == -1)
976             gpsd_report(LOG_WARN, "MTK NACK: unknown sentence\n");
977         else if (reason < 3)
978             gpsd_report(LOG_WARN, "MTK NACK: %s, reason: %s\n", field[1],
979                         mtk_reasons[reason]);
980         else
981             gpsd_report(LOG_WARN, "MTK ACK: %s\n", field[1]);
982         break;
983     default:
984         return 0;               /* ignore */
985     }
986     return mask;
987 }
988
989 static void mtk3301_event_hook(struct gps_device_t *session, event_t event)
990 {
991 /*
992 0  NMEA_SEN_GLL,  GPGLL   interval - Geographic Position - Latitude longitude
993 1  NMEA_SEN_RMC,  GPRMC   interval - Recommended Minimum Specific GNSS Sentence
994 2  NMEA_SEN_VTG,  GPVTG   interval - Course Over Ground and Ground Speed
995 3  NMEA_SEN_GGA,  GPGGA   interval - GPS Fix Data
996 4  NMEA_SEN_GSA,  GPGSA   interval - GNSS DOPS and Active Satellites
997 5  NMEA_SEN_GSV,  GPGSV   interval - GNSS Satellites in View
998 6  NMEA_SEN_GRS,  GPGRS   interval - GNSS Range Residuals
999 7  NMEA_SEN_GST,  GPGST   interval - GNSS Pseudorange Errors Statistics
1000 13 NMEA_SEN_MALM, PMTKALM interval - GPS almanac information
1001 14 NMEA_SEN_MEPH, PMTKEPH interval - GPS ephemeris information
1002 15 NMEA_SEN_MDGP, PMTKDGP interval - GPS differential correction information
1003 16 NMEA_SEN_MDBG, PMTKDBG interval – MTK debug information
1004 17 NMEA_SEN_ZDA,  GPZDA   interval - Time & Date
1005 18 NMEA_SEN_MCHN, PMTKCHN interval – GPS channel status
1006
1007 "$PMTK314,1,1,1,1,1,5,1,1,0,0,0,0,0,0,0,0,0,1,0"
1008
1009 */
1010     /* FIX-ME: Do we need to resend this on reactivation? */
1011     if (event == event_identified) {
1012         (void)nmea_send(session, "$PMTK320,0"); /* power save off */
1013         (void)nmea_send(session, "$PMTK300,1000,0,0,0.0,0.0");  /* Fix interval */
1014         (void)nmea_send(session,
1015                         "$PMTK314,0,1,0,1,1,5,1,1,0,0,0,0,0,0,0,0,0,1,0");
1016         (void)nmea_send(session, "$PMTK301,2"); /* DGPS is WAAS */
1017         (void)nmea_send(session, "$PMTK313,1"); /* SBAS enable */
1018     }
1019 }
1020
1021 #ifdef ALLOW_RECONFIGURE
1022 static bool mtk3301_rate_switcher(struct gps_device_t *session, double rate)
1023 {
1024     char buf[78];
1025     /*@i1@*/ unsigned int milliseconds = 1000 * rate;
1026     if (rate > 1)
1027         milliseconds = 1000;
1028     else if (rate < 0.2)
1029         milliseconds = 200;
1030
1031     (void)snprintf(buf, 78, "$PMTK300,%u,0,0,0,0", milliseconds);
1032     (void)nmea_send(session, buf);      /* Fix interval */
1033     return true;
1034 }
1035 #endif /* ALLOW_RECONFIGURE */
1036
1037 /* *INDENT-OFF* */
1038 const struct gps_type_t mtk3301 = {
1039     .type_name      = "MTK-3301",       /* full name of type */
1040     .packet_type    = NMEA_PACKET,      /* associated lexer packet type */
1041     .trigger        = "$PMTK705,",      /* MTK-3301s send firmware release name and version */
1042     .channels       = 12,               /* not used by this driver */
1043     .probe_detect   = NULL,             /* no probe */
1044     .get_packet     = generic_get,      /* how to get a packet */
1045     .parse_packet   = nmea_parse_input, /* how to interpret a packet */
1046     .rtcm_writer    = pass_rtcm,        /* write RTCM data straight */
1047     .event_hook     = mtk3301_event_hook,       /* lifetime event handler */
1048 #ifdef ALLOW_RECONFIGURE
1049     .speed_switcher = NULL,             /* no speed switcher */
1050     .mode_switcher  = NULL,             /* no mode switcher */
1051     .rate_switcher  = mtk3301_rate_switcher,            /* sample rate switcher */
1052     .min_cycle      = 0.2,              /* max 5Hz */
1053 #endif /* ALLOW_RECONFIGURE */
1054 #ifdef ALLOW_CONTROLSEND
1055     .control_send   = nmea_write,       /* how to send control strings */
1056 #endif /* ALLOW_CONTROLSEND */
1057 #ifdef NTPSHM_ENABLE
1058     .ntp_offset     = NULL,
1059 #endif /* NTPSHM_ ENABLE */
1060 };
1061 /* *INDENT-ON* */
1062 #endif /* MTK3301_ENABLE */
1063
1064
1065 #ifdef AIVDM_ENABLE
1066 /**************************************************************************
1067  *
1068  * AIVDM
1069  *
1070  **************************************************************************/
1071
1072 static gps_mask_t aivdm_analyze(struct gps_device_t *session)
1073 {
1074     if (session->packet.type == AIVDM_PACKET) {
1075         if (aivdm_decode
1076             ((char *)session->packet.outbuffer, session->packet.outbuflen,
1077              session->aivdm, &session->gpsdata.ais)) {
1078             return ONLINE_IS | AIS_IS;
1079         } else
1080             return ONLINE_IS;
1081 #ifdef NMEA_ENABLE
1082     } else if (session->packet.type == NMEA_PACKET) {
1083         return nmea_parse((char *)session->packet.outbuffer, session);
1084 #endif /* NMEA_ENABLE */
1085     } else
1086         return 0;
1087 }
1088
1089 /* *INDENT-OFF* */
1090 static const struct gps_type_t aivdm = {
1091     /* Full name of type */
1092     .type_name        = "AIVDM",
1093     /* Associated lexer packet type */
1094     .packet_type      = AIVDM_PACKET,
1095     /* Response string that identifies device (not active) */
1096     .trigger          = NULL,
1097     /* Number of satellite channels supported by the device */
1098     .channels         = 0,
1099     /* Startup-time device detector */
1100     .probe_detect     = NULL,
1101     /* Packet getter (using default routine) */
1102     .get_packet       = generic_get,
1103     /* Parse message packets */
1104     .parse_packet     = aivdm_analyze,
1105     /* RTCM handler (using default routine) */
1106     .rtcm_writer      = NULL,
1107     /* Handle various lifetime events */
1108     .event_hook       = NULL,
1109 #ifdef ALLOW_RECONFIGURE
1110     /* Speed (baudrate) switch */
1111     .speed_switcher   = NULL,
1112     /* Switch to NMEA mode */
1113     .mode_switcher    = NULL,
1114     /* Message delivery rate switcher (not active) */
1115     .rate_switcher    = NULL,
1116     /* Minimum cycle time of the device */
1117     .min_cycle        = 1,
1118 #endif /* ALLOW_RECONFIGURE */
1119 #ifdef ALLOW_CONTROLSEND
1120     /* Control string sender - should provide checksum and headers/trailer */
1121     .control_send     = NULL,
1122 #endif /* ALLOW_CONTROLSEND */
1123 #ifdef NTPSHM_ENABLE
1124     .ntp_offset     = NULL,
1125 #endif /* NTPSHM_ ENABLE */
1126 };
1127 /* *INDENT-ON* */
1128 #endif /* AIVDM_ENABLE */
1129
1130 extern const struct gps_type_t garmin_usb_binary, garmin_ser_binary;
1131 extern const struct gps_type_t tsip_binary, oncore_binary;
1132 extern const struct gps_type_t evermore_binary, italk_binary;
1133 extern const struct gps_type_t navcom_binary, superstar2_binary;
1134
1135 /*@ -nullassign @*/
1136 /* the point of this rigamarole is to not have to export a table size */
1137 static const struct gps_type_t *gpsd_driver_array[] = {
1138 #ifdef NMEA_ENABLE
1139     &nmea,
1140 #ifdef ASHTECH_ENABLE
1141     &ashtech,
1142 #endif /* ASHTECHV18_ENABLE */
1143 #ifdef TRIPMATE_ENABLE
1144     &tripmate,
1145 #endif /* TRIPMATE_ENABLE */
1146 #ifdef EARTHMATE_ENABLE
1147     &earthmate,
1148 #endif /* EARTHMATE_ENABLE */
1149 #ifdef GPSCLOCK_ENABLE
1150     &gpsclock,
1151 #endif /* GPSCLOCK_ENABLE */
1152 #ifdef GARMIN_ENABLE
1153     &garmin,
1154 #endif /* GARMIN_ENABLE */
1155 #ifdef MTK3301_ENABLE
1156     &mtk3301,
1157 #endif /*  MTK3301_ENABLE */
1158 #ifdef OCEANSERVER_ENABLE
1159     &oceanServer,
1160 #endif /* OCEANSERVER_ENABLE */
1161 #ifdef FV18_ENABLE
1162     &fv18,
1163 #endif /* FV18_ENABLE */
1164 #ifdef TNT_ENABLE
1165     &trueNorth,
1166 #endif /* TNT_ENABLE */
1167 #ifdef AIVDM_ENABLE
1168     &aivdm,
1169 #endif /* AIVDM_ENABLE */
1170 #endif /* NMEA_ENABLE */
1171
1172
1173 #ifdef EVERMORE_ENABLE
1174     &evermore_binary,
1175 #endif /* EVERMORE_ENABLE */
1176 #ifdef GARMIN_ENABLE
1177     &garmin_usb_binary,
1178     &garmin_ser_binary,
1179 #endif /* GARMIN_ENABLE */
1180 #ifdef ITRAX_ENABLE
1181     &italk_binary,
1182 #endif /* ITRAX_ENABLE */
1183 #ifdef ONCORE_ENABLE
1184     &oncore_binary,
1185 #endif /* ONCORE_ENABLE */
1186 #ifdef NAVCOM_ENABLE
1187     &navcom_binary,
1188 #endif /* NAVCOM_ENABLE */
1189 #ifdef SIRF_ENABLE
1190     &sirf_binary,
1191 #endif /* SIRF_ENABLE */
1192 #ifdef SUPERSTAR2_ENABLE
1193     &superstar2_binary,
1194 #endif /* SUPERSTAR2_ENABLE */
1195 #ifdef TSIP_ENABLE
1196     &tsip_binary,
1197 #endif /* TSIP_ENABLE */
1198 #ifdef UBX_ENABLE
1199     &ubx_binary,
1200 #endif /* UBX_ENABLE */
1201 #ifdef ZODIAC_ENABLE
1202     &zodiac_binary,
1203 #endif /* ZODIAC_ENABLE */
1204
1205 #ifdef RTCM104V2_ENABLE
1206     &rtcm104v2,
1207 #endif /* RTCM104V2_ENABLE */
1208 #ifdef RTCM104V3_ENABLE
1209     &rtcm104v3,
1210 #endif /* RTCM104V3_ENABLE */
1211 #ifdef GARMINTXT_ENABLE
1212     &garmintxt,
1213 #endif /* GARMINTXT_ENABLE */
1214     NULL,
1215 };
1216
1217 /*@ +nullassign @*/
1218 const struct gps_type_t **gpsd_drivers = &gpsd_driver_array[0];