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.
6 #include "gpsd_config.h"
7 #ifdef HAVE_SYS_IOCTL_H
9 #endif /* HAVE_SYS_IOCTL_H */
14 #endif /* S_SPLINT_S */
22 #include "bits.h" /* for getbeuw(), to extract big-endian words */
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;
28 ssize_t generic_get(struct gps_device_t *session)
30 return packet_get(session->gpsdata.gps_fd, &session->packet);
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 */
37 return gpsd_write(session, buf, rtcmbytes);
42 /**************************************************************************
44 * Generic driver -- straight NMEA 0183
46 **************************************************************************/
48 gps_mask_t nmea_parse_input(struct gps_device_t * session)
50 const struct gps_type_t **dp;
52 if (session->packet.type == COMMENT_PACKET) {
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",
59 (void)gpsd_switch_driver(session, (*dp)->type_name);
60 return (*dp)->parse_packet(session);
64 } else { /* session->packet.type == NMEA_PACKET) */
68 * Some packets do not end in \n, append one
71 gpsd_report(LOG_IO, "<= GPS: %s\n", session->packet.outbuffer);
74 nmea_parse((char *)session->packet.outbuffer, session)) == 0) {
75 gpsd_report(LOG_WARN, "unknown sentence: \"%s\"\n",
76 session->packet.outbuffer);
78 for (dp = gpsd_drivers; *dp; dp++) {
79 char *trigger = (*dp)->trigger;
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,
99 static void nmea_event_hook(struct gps_device_t *session, event_t event)
102 * This is where we try to tickle NMEA devices into erevrealing their
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);
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.
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
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.
127 switch (session->packet.counter) {
130 /* probe for Garmin serial GPS -- expect $PGRMC followed by data */
131 (void)nmea_send(session, "$PGRMCE");
133 #endif /* NMEA_ENABLE */
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.
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.
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;
155 #endif /* SIRF_ENABLE */
158 /* probe for the FV-18 -- expect $PFEC,GPint followed by data */
159 (void)nmea_send(session, "$PFEC,GPint");
162 /* probe for the Trimble Copernicus */
163 (void)nmea_send(session, "$PTNLSNM,0139,01");
165 #endif /* NMEA_ENABLE */
166 #ifdef EVERMORE_ENABLE
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",
174 #endif /* EVERMORE_ENABLE */
177 /* probe for iTrax, looking for "$PFST,OK" */
178 (void)nmea_send(session, "$PFST");
180 #endif /* ITRAX_ENABLE */
181 #ifdef GPSCLOCK_ENABLE
183 /* probe for Furuno Electric GH-79L4-N (GPSClock); expect $PFEC,GPssd */
184 (void)nmea_send(session, "$PFEC,GPsrq");
186 #endif /* GPSCLOCK_ENABLE */
187 #ifdef ASHTECH_ENABLE
189 /* probe for Ashtech -- expect $PASHR,RID */
190 (void)nmea_send(session, "$PASHQ,RID");
192 #endif /* ASHTECH_ENABLE */
195 /* probe for UBX -- query software version */
196 (void)ubx_write(session, 0x0au, 0x04, NULL, 0);
198 #endif /* UBX_ENABLE */
199 #ifdef MTK3301_ENABLE
201 /* probe for MTK-3301 -- expect $PMTK705 */
202 (void)nmea_send(session, "$PMTK605");
204 #endif /* MTK3301_ENABLE */
211 #ifdef ALLOW_RECONFIGURE
212 static void nmea_mode_switch(struct gps_device_t *session, int mode)
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);
223 #endif /* ALLOW_RECONFIGURE */
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 */
246 .ntp_offset = NULL, /* no method for NTP fudge factor */
247 #endif /* NTPSHM_ ENABLE */
251 #if defined(GARMIN_ENABLE) && defined(NMEA_ENABLE)
252 /**************************************************************************
256 **************************************************************************/
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 */
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;
269 #endif /* ALLOW_RECONFIGURE */
271 static void garmin_nmea_event_hook(struct gps_device_t *session,
274 if (event == event_driver_switch) {
275 /* forces a reconfigure as the following packets come in */
276 session->packet.counter = 0;
278 if (event == event_configure) {
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.
284 switch (session->packet.counter) {
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
291 (void)nmea_send(session, "$PGRMC,A,,100,,,,,,A,,1,2,1,30");
294 /* once a sec, no averaging, NMEA 2.3, WAAS */
295 (void)nmea_send(session, "$PGRMC1,1,1,1,,,,2,W,N");
298 /* get some more config info */
299 (void)nmea_send(session, "$PGRMC1E");
302 /* turn off all output except GGA */
303 (void)nmea_send(session, "$PGRMO,,2");
304 (void)nmea_send(session, "$PGRMO,GPGGA,1");
307 /* enable GPGGA, GPGSA, GPGSV, GPRMC on Garmin serial GPS */
308 (void)nmea_send(session, "$PGRMO,GPGSA,1");
311 (void)nmea_send(session, "$PGRMO,GPGSV,1");
314 (void)nmea_send(session, "$PGRMO,GPRMC,1");
317 (void)nmea_send(session, "$PGRMO,PGRME,1");
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 */
344 .ntp_offset = NULL, /* no method for NTP fudge factor */
345 #endif /* NTPSHM_ ENABLE */
348 #endif /* GARMIN_ENABLE && NMEA_ENABLE */
350 #ifdef ASHTECH_ENABLE
351 /**************************************************************************
353 * Ashtech (then Thales, now Magellan Professional) Receivers
355 **************************************************************************/
357 static void ashtech_event_hook(struct gps_device_t *session, event_t event)
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");
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");
377 (void)nmea_send(session, "$PASHS,NME,ZDA,A,ON");
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 */
402 .ntp_offset = NULL, /* no method for NTP fudge factor */
403 #endif /* NTPSHM_ ENABLE */
406 #endif /* ASHTECH_ENABLE */
409 /**************************************************************************
411 * FV18 -- uses 2 stop bits, needs to be told to send GSAs
413 **************************************************************************/
415 static void fv18_event_hook(struct gps_device_t *session, event_t event)
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.
423 if (event == event_identified || event == event_reactivate)
424 (void)nmea_send(session,
425 "$PFEC,GPint,GSA01,DTM00,ZDA01,RMC01,GLL00,VTG00,GSV05");
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 */
449 .ntp_offset = NULL, /* no method for NTP fudge factor */
450 #endif /* NTPSHM_ ENABLE */
453 #endif /* FV18_ENABLE */
455 #ifdef GPSCLOCK_ENABLE
456 /**************************************************************************
458 * Furuno Electric GPSClock (GH-79L4)
460 **************************************************************************/
463 * Based on http://www.tecsys.de/fileadmin/user_upload/pdf/gh79_1an_intant.pdf
466 static void gpsclock_event_hook(struct gps_device_t *session, event_t event)
469 * Michael St. Laurent <mikes@hartwellcorp.com> reports that you have to
470 * ignore the trailing PPS edge when extracting time from this chip.
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;
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 */
499 .ntp_offset = NULL, /* no method for NTP fudge factor */
500 #endif /* NTPSHM_ ENABLE */
503 #endif /* GPSCLOCK_ENABLE */
505 #ifdef TRIPMATE_ENABLE
506 /**************************************************************************
508 * TripMate -- extended NMEA, gets faster fix when primed with lat/long/time
510 **************************************************************************/
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.
520 static void tripmate_event_hook(struct gps_device_t *session, event_t event)
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,,");
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 */
551 .ntp_offset = NULL, /* no method for NTP fudge factor */
552 #endif /* NTPSHM_ ENABLE */
555 #endif /* TRIPMATE_ENABLE */
557 #ifdef EARTHMATE_ENABLE
558 /**************************************************************************
560 * Zodiac EarthMate textual mode
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.
566 **************************************************************************/
568 static void earthmate_event_hook(struct gps_device_t *session, event_t event)
570 if (event == event_identified) {
571 (void)gpsd_write(session, "EARTHA\r\n", 8);
573 (void)gpsd_switch_driver(session, "Zodiac Binary");
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 */
599 .ntp_offset = NULL, /* no method for NTP fudge factor */
600 #endif /* NTPSHM_ ENABLE */
604 #endif /* EARTHMATE_ENABLE */
606 #endif /* NMEA_ENABLE */
609 /**************************************************************************
610 * True North Technologies - Revolution 2X Digital compass
612 * More info: http://www.tntc.com/
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.
620 **************************************************************************/
622 static void tnt_add_checksum(char *sentence)
623 /* add NMEA-style CRC checksum to a command */
625 unsigned char sum = '\0';
626 char c, *p = sentence;
631 gpsd_report(LOG_ERROR, "Bad TNT sentence: '%s'\n", sentence);
633 while (((c = *p) != '\0')) {
637 (void)snprintf(p, 6, "*%02X\r\n", (unsigned int)sum);
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 */
647 tnt_add_checksum(msg);
648 status = write(session->gpsdata.gps_fd, msg, strlen(msg));
649 (void)tcdrain(session->gpsdata.gps_fd);
653 static bool tnt_send(struct gps_device_t *session, const char *fmt, ...)
654 /* printf(3)-like TNT command generator */
661 (void)vsnprintf(buf, sizeof(buf) - 5, fmt, 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);
668 gpsd_report(LOG_WARN, "=> GPS: %s FAILED\n", buf);
673 #ifdef ALLOW_RECONFIGURE
674 static bool tnt_speed(struct gps_device_t *session,
675 speed_t speed, char parity, int stopbits)
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
682 unsigned int val = speed / 2400u; /* 2400->1, 4800->2, 9600->4, 19200->8... */
685 /* fast way to compute log2(val) */
686 while ((val >> i) > 1)
688 return tnt_send(session, "@B6=%d", i + 1)
689 && tnt_send(session, "@F28.6=1");
691 #endif /* ALLOW_RECONFIGURE */
693 static void tnt_event_hook(struct gps_device_t *session, event_t event)
694 /* TNT lifetime event hook */
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 */
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 */
724 #endif /* NTPSHM_ ENABLE */
729 #ifdef OCEANSERVER_ENABLE
730 /**************************************************************************
731 * OceanServer - Digital Compass, OS5000 Series
733 * More info: http://www.ocean-server.com/download/OS5000_Compass_Manual.pdf
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.
741 **************************************************************************/
743 static int oceanserver_send(int fd, const char *fmt, ...)
750 (void)vsnprintf(buf, sizeof(buf) - 5, fmt, ap);
752 (void)strlcat(buf, "
\e", BUFSIZ);
753 status = (int)write(fd, buf, strlen(buf));
755 if (status == (int)strlen(buf)) {
756 gpsd_report(LOG_IO, "=> GPS: %s\n", buf);
759 gpsd_report(LOG_WARN, "=> GPS: %s FAILED\n", buf);
764 static void oceanserver_event_hook(struct gps_device_t *session,
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");
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 */
797 #endif /* NTPSHM_ ENABLE */
802 #ifdef RTCM104V2_ENABLE
803 /**************************************************************************
805 * RTCM-104 (v2), used for broadcasting DGPS corrections and by DGPS radios
807 **************************************************************************/
809 static gps_mask_t rtcm104v2_analyze(struct gps_device_t *session)
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));
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 */
843 #endif /* NTPSHM_ ENABLE */
846 #endif /* RTCM104V2_ENABLE */
847 #ifdef RTCM104V3_ENABLE
848 /**************************************************************************
850 * RTCM-104 (v3), used for broadcasting DGPS corrections and by DGPS radios
852 **************************************************************************/
854 static gps_mask_t rtcm104v3_analyze(struct gps_device_t *session)
856 uint16_t length = getbeuw(session->packet.inbuffer, 1);
857 uint16_t type = getbeuw(session->packet.inbuffer, 3) >> 4;
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),
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 */
890 #endif /* NTPSHM_ ENABLE */
893 #endif /* RTCM104V3_ENABLE */
895 #ifdef GARMINTXT_ENABLE
896 /**************************************************************************
898 * Garmin Simple Text protocol
900 **************************************************************************/
902 static gps_mask_t garmintxt_parse_input(struct gps_device_t *session)
904 if (session->packet.type == COMMENT_PACKET) {
906 } else if (session->packet.type == GARMINTXT_PACKET) {
907 //gpsd_report(LOG_PROG, "Garmin Simple Text packet\n");
908 return garmintxt_parse(session);
910 const struct gps_type_t **dp;
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",
916 (void)gpsd_switch_driver(session, (*dp)->type_name);
917 return (*dp)->parse_packet(session);
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 */
946 #endif /* NTPSHM_ ENABLE */
949 #endif /* GARMINTXT_ENABLE */
951 #ifdef MTK3301_ENABLE
952 /**************************************************************************
956 **************************************************************************/
957 const char *mtk_reasons[4] =
958 { "Invalid", "Unsupported", "Valid but Failed", "Valid success" };
960 gps_mask_t processMTK3301(int c UNUSED, char *field[],
961 struct gps_device_t *session)
965 mask = 1; //ONLINE_IS;
967 switch (msg = atoi(&(field[0])[4])) {
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");
978 gpsd_report(LOG_WARN, "MTK NACK: %s, reason: %s\n", field[1],
979 mtk_reasons[reason]);
981 gpsd_report(LOG_WARN, "MTK ACK: %s\n", field[1]);
984 return 0; /* ignore */
989 static void mtk3301_event_hook(struct gps_device_t *session, event_t event)
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
1007 "$PMTK314,1,1,1,1,1,5,1,1,0,0,0,0,0,0,0,0,0,1,0"
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 */
1021 #ifdef ALLOW_RECONFIGURE
1022 static bool mtk3301_rate_switcher(struct gps_device_t *session, double rate)
1025 /*@i1@*/ unsigned int milliseconds = 1000 * rate;
1027 milliseconds = 1000;
1028 else if (rate < 0.2)
1031 (void)snprintf(buf, 78, "$PMTK300,%u,0,0,0,0", milliseconds);
1032 (void)nmea_send(session, buf); /* Fix interval */
1035 #endif /* ALLOW_RECONFIGURE */
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
1059 #endif /* NTPSHM_ ENABLE */
1062 #endif /* MTK3301_ENABLE */
1066 /**************************************************************************
1070 **************************************************************************/
1072 static gps_mask_t aivdm_analyze(struct gps_device_t *session)
1074 if (session->packet.type == AIVDM_PACKET) {
1076 ((char *)session->packet.outbuffer, session->packet.outbuflen,
1077 session->aivdm, &session->gpsdata.ais)) {
1078 return ONLINE_IS | AIS_IS;
1082 } else if (session->packet.type == NMEA_PACKET) {
1083 return nmea_parse((char *)session->packet.outbuffer, session);
1084 #endif /* NMEA_ENABLE */
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) */
1097 /* Number of satellite channels supported by the device */
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 */
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 */
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
1125 #endif /* NTPSHM_ ENABLE */
1128 #endif /* AIVDM_ENABLE */
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;
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[] = {
1140 #ifdef ASHTECH_ENABLE
1142 #endif /* ASHTECHV18_ENABLE */
1143 #ifdef TRIPMATE_ENABLE
1145 #endif /* TRIPMATE_ENABLE */
1146 #ifdef EARTHMATE_ENABLE
1148 #endif /* EARTHMATE_ENABLE */
1149 #ifdef GPSCLOCK_ENABLE
1151 #endif /* GPSCLOCK_ENABLE */
1152 #ifdef GARMIN_ENABLE
1154 #endif /* GARMIN_ENABLE */
1155 #ifdef MTK3301_ENABLE
1157 #endif /* MTK3301_ENABLE */
1158 #ifdef OCEANSERVER_ENABLE
1160 #endif /* OCEANSERVER_ENABLE */
1163 #endif /* FV18_ENABLE */
1166 #endif /* TNT_ENABLE */
1169 #endif /* AIVDM_ENABLE */
1170 #endif /* NMEA_ENABLE */
1173 #ifdef EVERMORE_ENABLE
1175 #endif /* EVERMORE_ENABLE */
1176 #ifdef GARMIN_ENABLE
1179 #endif /* GARMIN_ENABLE */
1182 #endif /* ITRAX_ENABLE */
1183 #ifdef ONCORE_ENABLE
1185 #endif /* ONCORE_ENABLE */
1186 #ifdef NAVCOM_ENABLE
1188 #endif /* NAVCOM_ENABLE */
1191 #endif /* SIRF_ENABLE */
1192 #ifdef SUPERSTAR2_ENABLE
1194 #endif /* SUPERSTAR2_ENABLE */
1197 #endif /* TSIP_ENABLE */
1200 #endif /* UBX_ENABLE */
1201 #ifdef ZODIAC_ENABLE
1203 #endif /* ZODIAC_ENABLE */
1205 #ifdef RTCM104V2_ENABLE
1207 #endif /* RTCM104V2_ENABLE */
1208 #ifdef RTCM104V3_ENABLE
1210 #endif /* RTCM104V3_ENABLE */
1211 #ifdef GARMINTXT_ENABLE
1213 #endif /* GARMINTXT_ENABLE */
1218 const struct gps_type_t **gpsd_drivers = &gpsd_driver_array[0];