drivers.c
来自「gpsd, a popular GPS daemon.」· C语言 代码 · 共 927 行 · 第 1/3 页
C
927 行
/* $Id: drivers.c 4663 2008-01-20 23:35:32Z garyemiller $ */#include <sys/types.h>#include <sys/ioctl.h>#include <sys/time.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <errno.h>#include <stdio.h>#include <math.h>#include <stdarg.h>#include "gpsd_config.h"#include "gpsd.h"extern struct gps_type_t zodiac_binary;extern struct gps_type_t ubx_binary;ssize_t generic_get(struct gps_device_t *session){ return packet_get(session->gpsdata.gps_fd, &session->packet);}#if defined(NMEA_ENABLE) || defined(SIRF_ENABLE) || defined(EVERMORE_ENABLE) || defined(ITRAX_ENABLE) || defined(NAVCOM_ENABLE)ssize_t pass_rtcm(struct gps_device_t *session, char *buf, size_t rtcmbytes)/* most GPSes take their RTCM corrections straight up */{ return gpsd_write(session, buf, rtcmbytes);}#endif#ifdef NMEA_ENABLE/************************************************************************** * * Generic driver -- straight NMEA 0183 * **************************************************************************/gps_mask_t nmea_parse_input(struct gps_device_t *session){ if (session->packet.type == COMMENT_PACKET) { return 0; } else if (session->packet.type == SIRF_PACKET) { gpsd_report(LOG_WARN, "SiRF packet seen when NMEA expected.\n");#ifdef SIRF_ENABLE (void)gpsd_switch_driver(session, "SiRF binary"); return sirf_parse(session, session->packet.outbuffer, session->packet.outbuflen);#else return 0;#endif /* SIRF_ENABLE */ } else if (session->packet.type == EVERMORE_PACKET) { gpsd_report(LOG_WARN, "EverMore packet seen when NMEA expected.\n");#ifdef EVERMORE_ENABLE (void)gpsd_switch_driver(session, "EverMore binary"); return evermore_parse(session, session->packet.outbuffer, session->packet.outbuflen);#else return 0;#endif /* EVERMORE_ENABLE */ } else if (session->packet.type == NAVCOM_PACKET) { gpsd_report(LOG_WARN, "Navcom packet seen when NMEA expected.\n");#ifdef NAVCOM_ENABLE (void)gpsd_switch_driver(session, "Navcom binary"); return navcom_parse(session, session->packet.outbuffer, session->packet.outbuflen);#else return 0;#endif /* NAVCOM_ENABLE */} else if (session->packet.type == GARMIN_PACKET) { gpsd_report(LOG_WARN, "Garmin packet seen when NMEA expected.\n");#ifdef GARMIN_ENABLE /* we might never see a trigger, have this as a backstop */ (void)gpsd_switch_driver(session, "Garmin Serial binary"); return garmin_ser_parse(session);#else return 0;#endif /* GARMIN_ENABLE */ } else if (session->packet.type == NMEA_PACKET) { gps_mask_t st = 0;#ifdef GARMINTXT_ENABLE if (session->packet.outbuflen >= 56) { if ((char) *session->packet.outbuffer == '@') { /* Garmin Simple Text packet received; it starts with '@' is terminated with \r\n and has length 57 bytes */ (void)gpsd_switch_driver(session, "Garmin Simple Text"); return garmintxt_parse(session); } }#endif /* GARMINTXT_ENABLE */ gpsd_report(LOG_IO, "<= GPS: %s", session->packet.outbuffer); if ((st=nmea_parse((char *)session->packet.outbuffer, session))==0) {#ifdef NON_NMEA_ENABLE struct gps_type_t **dp; /* maybe this is a trigger string for a driver we know about? */ for (dp = gpsd_drivers; *dp; dp++) { char *trigger = (*dp)->trigger; if (trigger!=NULL && strncmp((char *)session->packet.outbuffer, trigger, strlen(trigger))==0 && isatty(session->gpsdata.gps_fd)!=0) { gpsd_report(LOG_PROG, "found %s.\n", trigger); (void)gpsd_switch_driver(session, (*dp)->type_name); return 1; } }#endif /* NON_NMEA_ENABLE */ gpsd_report(LOG_WARN, "unknown sentence: \"%s\"\n", session->packet.outbuffer); }#ifdef NMEADISC if (session->ldisc == 0) { uid_t old; int ldisc = NMEADISC;#ifdef TIOCSTSTAMP struct tstamps tstamps;#ifdef PPS_ON_CTS tstamps.ts_set |= TIOCM_CTS;#else /*!PPS_ON_CTS */ tstamps.ts_set |= TIOCM_CAR;#endif /* PPS_ON_CTS */ tstamps.ts_clr = 0; old = geteuid(); if (seteuid(0) == -1) gpsd_report(LOG_WARN, "can't seteuid(0) - %s", strerror(errno)); else gpsd_report(LOG_WARN, "seteuid(0) to enable timestamping\n"); if (ioctl(session->gpsdata.gps_fd, TIOCSTSTAMP, &tstamps) < 0) gpsd_report(LOG_WARN, "can't set kernel timestamping: %s\n", strerror(errno)); else gpsd_report(LOG_WARN, "activated kernel timestamping\n");#endif /* TIOCSTSTAMP */ if (ioctl(session->gpsdata.gps_fd, TIOCSETD, &ldisc) == -1) gpsd_report(LOG_WARN, "can't set nmea discipline: %s\n", strerror(errno)); else gpsd_report(LOG_WARN, "activated nmea discipline\n"); /* this is a flag that shows if we've tried the setup */ session->ldisc = NMEADISC; if (old){ gpsd_report(LOG_WARN, "giving up euid 0\n"); (void)seteuid(old); } gpsd_report(LOG_WARN, "running with effective user ID %d\n", geteuid()); }#endif /*NMEADISC */#ifdef NTPSHM_ENABLE /* this magic number is derived from observation */ if (session->context->enable_ntpshm && (st & TIME_SET) != 0 && (session->gpsdata.fix.time!=session->last_fixtime)) { (void)ntpshm_put(session, session->gpsdata.fix.time); session->last_fixtime = session->gpsdata.fix.time; }#endif /* NTPSHM_ENABLE */ return st; } else return 0;}static void nmea_probe_subtype(struct gps_device_t *session, unsigned int seq){ /* * The reason for splitting these probes up by packet sequence * number, interleaving them with the first few packet receives, * is because many generic-NMEA devices get confused if you send * too much at them in one go. * * A fast response to an early probe will change drivers so the * later ones won't be sent at all. Thus, for best overall * performance, order these to probe for the most popular types * soonest. * * Note: don't make the trigger strings identical to the probe, * because some NMEA devices (notably SiRFs) will just echo * unknown strings right back at you. A useful dodge is to append * a comma to the trigger, because that won't be in the response * unless there is actual following data. */ switch (seq) {#ifdef SIRF_ENABLE case 0: /* * We used to try to probe for SiRF by issuing "$PSRF105,1" * and expecting "$Ack Input105.". But it turns out this * only works for SiRF-IIs; SiRF-I and SiRF-III don't respond. * Thus the only reliable probe is to try to flip the SiRF into * binary mode, cluing in the library to revert it on close. */ (void)nmea_send(session->gpsdata.gps_fd, "$PSRF100,0,%d,%d,%d,0", session->gpsdata.baudrate, 9-session->gpsdata.stopbits, session->gpsdata.stopbits); session->back_to_nmea = true; break;#endif /* SIRF_ENABLE */#ifdef NMEA_ENABLE case 1: /* probe for Garmin serial GPS -- expect $PGRMC followed by data*/ (void)nmea_send(session->gpsdata.gps_fd, "$PGRMCE"); break; case 2: /* probe for the FV-18 -- expect $PFEC,GPint followed by data */ (void)nmea_send(session->gpsdata.gps_fd, "$PFEC,GPint"); break;#endif /* NMEA_ENABLE */#ifdef EVERMORE_ENABLE case 3: /* Enable checksum and GGA(1s), GLL(0s), GSA(1s), GSV(1s), RMC(1s), VTG(0s), PEMT101(1s) */ /* EverMore will reply with: \x10\x02\x04\x38\x8E\xC6\x10\x03 */ (void)gpsd_write(session, "\x10\x02\x12\x8E\x7F\x01\x01\x00\x01\x01\x01\x00\x01\x00\x00\x00\x00\x00\x00\x13\x10\x03", 22); break;#endif /* EVERMORE_ENABLE */#ifdef ITRAX_ENABLE case 4: /* probe for iTrax, looking for "$PFST,OK" */ (void)nmea_send(session->gpsdata.gps_fd, "$PFST"); break;#endif /* ITRAX_ENABLE */#ifdef GPSCLOCK_ENABLE case 5: /* probe for Furuno Electric GH-79L4-N (GPSClock) */ (void)nmea_send(session->gpsdata.gps_fd, "$PFEC,GPsrq"); break;#endif /* GPSCLOCK_ENABLE */#ifdef ASHTECH_ENABLE case 6: /* probe for Ashtech -- expect $PASHR */ (void)nmea_send(session->gpsdata.gps_fd, "$PASHQ,RID"); break;#endif /* ASHTECH_ENABLE */ default: break; }}static struct gps_type_t nmea = { .type_name = "Generic NMEA", /* full name of type */ .trigger = NULL, /* it's the default */ .channels = 12, /* consumer-grade GPS */ .probe_wakeup = NULL, /* no wakeup to be done before hunt */ .probe_detect = NULL, /* no probe */ .probe_subtype = nmea_probe_subtype, /* probe for special types */#ifdef ALLOW_RECONFIGURE .configurator = NULL, /* enable what we need */#endif /* ALLOW_RECONFIGURE */ .get_packet = generic_get, /* use generic packet getter */ .parse_packet = nmea_parse_input, /* how to interpret a packet */ .rtcm_writer = pass_rtcm, /* write RTCM data straight */ .speed_switcher = NULL, /* no speed switcher */ .mode_switcher = NULL, /* no mode switcher */ .rate_switcher = NULL, /* no sample-rate switcher */ .cycle_chars = -1, /* not relevant, no rate switch */#ifdef ALLOW_RECONFIGURE .revert = NULL, /* no setting-reversion method */#endif /* ALLOW_RECONFIGURE */ .wrapup = NULL, /* no wrapup */ .cycle = 1, /* updates every second */};#if defined(GARMIN_ENABLE) && defined(NMEA_ENABLE)/************************************************************************** * * Garmin NMEA * **************************************************************************/#ifdef ALLOW_RECONFIGUREstatic void garmin_nmea_configurator(struct gps_device_t *session, unsigned int seq){ /* * Receivers like the Garmin GPS-10 don't handle having having a lot of * probes shoved at them very well. */ switch (seq) { case 0: /* reset some config, AutoFix, WGS84, PPS * Set the PPS pulse length to 40ms which leaves the Garmin 18-5hz * with a 160ms low state. * NOTE: new PPS only takes effect after next power cycle */ (void)nmea_send(session->gpsdata.gps_fd, "$PGRMC,A,,100,,,,,,A,,1,2,1,30"); break; case 1: /* once a sec, no averaging, NMEA 2.3, WAAS */ (void)nmea_send(session->gpsdata.gps_fd, "$PGRMC1,1,1,1,,,,2,W,N"); break; case 2: /* get some more config info */ (void)nmea_send(session->gpsdata.gps_fd, "$PGRMC1E"); break; case 3: /* turn off all output except GGA */ (void)nmea_send(session->gpsdata.gps_fd, "$PGRMO,,2"); (void)nmea_send(session->gpsdata.gps_fd, "$PGRMO,GPGGA,1"); break; case 4: /* enable GPGGA, GPGSA, GPGSV, GPRMC on Garmin serial GPS */ (void)nmea_send(session->gpsdata.gps_fd, "$PGRMO,GPGSA,1"); break; case 5: (void)nmea_send(session->gpsdata.gps_fd, "$PGRMO,GPGSV,1"); break; case 6: (void)nmea_send(session->gpsdata.gps_fd, "$PGRMO,GPRMC,1"); break; case 7: (void)nmea_send(session->gpsdata.gps_fd, "$PGRMO,PGRME,1"); break;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?