libgps.c

来自「gpsd, a popular GPS daemon.」· C语言 代码 · 共 712 行 · 第 1/2 页

C
712
字号
/* $Id: libgps.c 4377 2007-06-02 14:52:38Z esr $ *//* libgps.c -- client interface library for the gpsd daemon */#include <sys/time.h>#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <stdarg.h>#ifndef S_SPLINT_S#include <pthread.h>	/* pacifies OpenBSD's compiler */#endif#include <math.h>#include "gpsd_config.h"#include "gpsd.h"#ifdef HAVE_SETLOCALE#include <locale.h>#endif#ifdef S_SPLINT_Sextern char *strtok_r(char *, const char *, char **);#endif /* S_SPLINT_S *//* convert double degrees to a static string and return a pointer to it * * deg_str_type: *   	deg_dd     : return DD.dddddd *      deg_ddmm   : return DD MM.mmmm' *      deg_ddmmss : return DD MM' SS.sss" * *//*@observer@*/char *deg_to_str( enum deg_str_type type,  double f) {    static char str[40];    int dsec, sec, deg, min;    long frac_deg;    double fdsec, fsec, fdeg, fmin;    if ( f < 0 || f > 360 ) {	(void)strlcpy( str, "nan", 40);	return str;    }    fmin = modf( f, &fdeg);    deg = (int)fdeg;    frac_deg = (long)(fmin * 1000000);    if ( deg_dd == type ) {	/* DD.dddddd */	(void)snprintf(str, sizeof(str), "%3d.%06ld", deg,frac_deg);	return str;    }    fsec = modf( fmin * 60, &fmin);    min = (int)fmin;    sec = (int)(fsec * 10000.0);    if ( deg_ddmm == type ) {	/* DD MM.mmmm */	(void)snprintf(str,sizeof(str), "%3d %02d.%04d'", deg,min,sec);	return str;    }    /* else DD MM SS.sss */    fdsec = modf( fsec * 60, &fsec);    sec = (int)fsec;    dsec = (int)(fdsec * 1000.0);    (void)snprintf(str,sizeof(str), "%3d %02d' %02d.%03d\"", deg,min,sec,dsec);    return str;}/*  * check the environment to determine proper GPS units * * clients should only call this if no user preference is specified on  * the command line or via X resources. * * return imperial    - Use miles/feet *        nautical    - Use knots/feet *        metric      - Use km/meters *        unspecified - use compiled default *  * In order check these environment vars: *    GPSD_UNITS one of:  *            	imperial   = miles/feet *              nautical   = knots/feet *              metric     = km/meters *    LC_MEASUREMENT *		en_US      = miles/feet *              C          = miles/feet *              POSIX      = miles/feet *              [other]    = km/meters *    LANG *		en_US      = miles/feet *              C          = miles/feet *              POSIX      = miles/feet *              [other]    = km/meters * * if none found then return compiled in default */enum unit gpsd_units(void){	char *envu = NULL;#ifdef HAVE_SETLOCALE	(void)setlocale(LC_NUMERIC, "C");#endif  	if ((envu = getenv("GPSD_UNITS")) != NULL && *envu != '\0') {		if (0 == strcasecmp(envu, "imperial")) {			return imperial;		}		if (0 == strcasecmp(envu, "nautical")) {			return nautical;		}		if (0 == strcasecmp(envu, "metric")) {			return metric;		}		/* unrecognized, ignore it */	} 	if (((envu = getenv("LC_MEASUREMENT")) != NULL && *envu != '\0')  	    || ((envu = getenv("LANG")) != NULL && *envu != '\0')) {		if (strcasecmp(envu, "en_US")==0 		    || strcasecmp(envu, "C")==0		    || strcasecmp(envu, "POSIX")==0) {			return imperial;		}		/* Other, must be metric */		return metric;	}	/* TODO: allow a compile time default here */	return unspecified;}struct gps_data_t *gps_open(const char *host, const char *port)/* open a connection to a gpsd daemon */{    struct gps_data_t *gpsdata = (struct gps_data_t *)calloc(sizeof(struct gps_data_t), 1);    /*@ -branchstate @*/    if (!gpsdata)	return NULL;    if (!host)	host = "127.0.0.1";    if (!port)	port = DEFAULT_GPSD_PORT;    if ((gpsdata->gps_fd = netlib_connectsock(host, port, "tcp")) < 0) {	errno = gpsdata->gps_fd;	(void)free(gpsdata);	return NULL;    }    gpsdata->status = STATUS_NO_FIX;    gps_clear_fix(&gpsdata->fix);    return gpsdata;    /*@ +branchstate @*/}int gps_close(struct gps_data_t *gpsdata)/* close a gpsd connection */{    int retval = close(gpsdata->gps_fd);    if (gpsdata->gps_id) {	(void)free(gpsdata->gps_id);	gpsdata->gps_id = NULL;    }    gpsdata->gps_device[0] = '\0';    if (gpsdata->devicelist) {	int i;	for (i = 0; i < gpsdata->ndevices; i++)	    /*@i1@*/(void)free(gpsdata->devicelist[i]);	(void)free(gpsdata->devicelist);	gpsdata->devicelist = NULL;	gpsdata->ndevices = -1;    }        /*@i@*/(void)free(gpsdata);    return retval;}void gps_set_raw_hook(struct gps_data_t *gpsdata, 		      void (*hook)(struct gps_data_t *, char *, size_t len, int level)){    gpsdata->raw_hook = hook;}/*@ -branchstate -usereleased @*/static void gps_unpack(char *buf, struct gps_data_t *gpsdata)/* unpack a daemon response into a status structure */{    char *ns, *sp, *tp;    int i;    for (ns = buf; ns; ns = strstr(ns+1, "GPSD")) {	if (/*@i1@*/strncmp(ns, "GPSD", 4) == 0) {	    /* the following should execute each time we have a good next sp */	    for (sp = ns + 5; *sp != '\0'; sp = tp+1) {		tp = sp + strcspn(sp, ",\r\n");		if (*tp == '\0') tp--;		else *tp = '\0';		switch (*sp) {		case 'A':		    if (sp[2] == '?') {			    gpsdata->fix.altitude = NAN;		    } else {		        (void)sscanf(sp, "A=%lf", &gpsdata->fix.altitude);		        gpsdata->set |= ALTITUDE_SET;		    }		    break;		case 'B':		    if (sp[2] == '?') {			gpsdata->baudrate = gpsdata->stopbits = 0;		    } else			(void)sscanf(sp, "B=%u %*d %*s %u", 			       &gpsdata->baudrate, &gpsdata->stopbits);		    break;		case 'C':		    if (sp[2] == '?')			gpsdata->mincycle = gpsdata->cycle = 0;		    else {			if (sscanf(sp, "C=%lf %lf", 				     &gpsdata->cycle,				   &gpsdata->mincycle) < 2)			    gpsdata->mincycle = gpsdata->cycle;		    }		    break;		case 'D':		    if (sp[2] == '?') 			gpsdata->fix.time = NAN;		    else {			gpsdata->fix.time = iso8601_to_unix(sp+2);			gpsdata->set |= TIME_SET;		    }		    break;		case 'E':		    gpsdata->epe = gpsdata->fix.eph = gpsdata->fix.epv = NAN;		    /* epe should always be present if eph or epv is */		    if (sp[2] != '?') {			char epe[20], eph[20], epv[20];		        (void)sscanf(sp, "E=%s %s %s", epe, eph, epv);#define DEFAULT(val) (val[0] == '?') ? NAN : atof(val)			    /*@ +floatdouble @*/			    gpsdata->epe = DEFAULT(epe);			    gpsdata->fix.eph = DEFAULT(eph);			    gpsdata->fix.epv = DEFAULT(epv);			    /*@ -floatdouble @*/#undef DEFAULT		    }		    break;		case 'F':		    /*@ -mustfreeonly */		    if (sp[2] == '?') 			gpsdata->gps_device[0] = '\0';		    else {			/*@ -mayaliasunique @*/			strncpy(gpsdata->gps_device, sp+2, PATH_MAX);			/*@ +mayaliasunique @*/			gpsdata->set |= DEVICE_SET;		    }		    /*@ +mustfreeonly */		    break;		case 'I':		    /*@ -mustfreeonly */		    if (gpsdata->gps_id)			free(gpsdata->gps_id);		    if (sp[2] == '?')			gpsdata->gps_id = NULL;		    else {			gpsdata->gps_id = strdup(sp+2);			gpsdata->set |= DEVICEID_SET;		    }		    /*@ +mustfreeonly */		    break;		case 'K':		    if (gpsdata->devicelist) {			for (i = 0; i < gpsdata->ndevices; i++)			    /*@i1@*/(void)free(gpsdata->devicelist[i]);			(void)free(gpsdata->devicelist);			gpsdata->devicelist = NULL;			gpsdata->ndevices = -1;			gpsdata->set |= DEVICELIST_SET;		    }    		    if (sp[2] != '?') {			/*@ -nullderef @*/			gpsdata->ndevices = (int)strtol(sp+2, &sp, 10);			gpsdata->devicelist = (char **)calloc(			    (size_t)gpsdata->ndevices,			    sizeof(char **));			/*@ -nullstate -mustfreefresh @*/			gpsdata->devicelist[i=0] = strdup(strtok_r(sp+1, " \r\n", &ns));			while ((sp = strtok_r(NULL, " \r\n",  &ns)))			    gpsdata->devicelist[++i] = strdup(sp);			/*@ +nullstate +mustfreefresh @*/			/*@ +nullderef @*/			gpsdata->set |= DEVICELIST_SET;		    }		    break;		case 'M':		    if (sp[2] == '?') {		        gpsdata->fix.mode = MODE_NOT_SEEN;		    } else {		        gpsdata->fix.mode = atoi(sp+2);		        gpsdata->set |= MODE_SET;		    }		    break;		case 'N':		    if (sp[2] == '?') 			gpsdata->driver_mode = 0;		    else			gpsdata->driver_mode = (unsigned)atoi(sp+2);		    break;		case 'O':		    if (sp[2] == '?') {			gpsdata->set = MODE_SET | STATUS_SET;			gpsdata->status = STATUS_NO_FIX;			gps_clear_fix(&gpsdata->fix);		    } else {			struct gps_fix_t nf;			char tag[MAXTAGLEN+1], alt[20];			char eph[20], epv[20], track[20],speed[20], climb[20];			char epd[20], eps[20], epc[20], mode[2];			char timestr[20], ept[20], lat[20], lon[20];			int st = sscanf(sp+2, 			       "%8s %19s %19s %19s %19s %19s %19s %19s %19s %19s %19s %19s %19s %19s %1s",				tag, timestr, ept, lat, lon,			        alt, eph, epv, track, speed, climb,			        epd, eps, epc, mode);			if (st >= 14) {#define DEFAULT(val) (val[0] == '?') ? NAN : atof(val)			    /*@ +floatdouble @*/			    nf.time = DEFAULT(timestr);			    nf.latitude = DEFAULT(lat);			    nf.longitude = DEFAULT(lon);			    nf.ept = DEFAULT(ept);			    nf.altitude = DEFAULT(alt);			    nf.eph = DEFAULT(eph);			    nf.epv = DEFAULT(epv);			    nf.track = DEFAULT(track);			    nf.speed = DEFAULT(speed);			    nf.climb = DEFAULT(climb);			    nf.epd = DEFAULT(epd);			    nf.eps = DEFAULT(eps);			    nf.epc = DEFAULT(epc);			    /*@ -floatdouble @*/#undef DEFAULT			    if (st >= 15)				nf.mode = (mode[0] == '?') ? MODE_NOT_SEEN : atoi(mode);			    else				nf.mode = (alt[0] == '?') ? MODE_2D : MODE_3D;			    if (alt[0] != '?')				gpsdata->set |= ALTITUDE_SET | CLIMB_SET;			    if (isnan(nf.eph)==0)				gpsdata->set |= HERR_SET;			    if (isnan(nf.epv)==0)				gpsdata->set |= VERR_SET;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?