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 + -
显示快捷键?