17c881178SDavid du Colombier #include <u.h>
27c881178SDavid du Colombier #include <libc.h>
37c881178SDavid du Colombier #include <fcall.h>
47c881178SDavid du Colombier #include <thread.h>
57c881178SDavid du Colombier #include <ctype.h>
67c881178SDavid du Colombier #include <9p.h>
77c881178SDavid du Colombier #include "dat.h"
87c881178SDavid du Colombier
97c881178SDavid du Colombier enum
107c881178SDavid du Colombier {
117c881178SDavid du Colombier Numsize= 12,
127c881178SDavid du Colombier Vlnumsize= 22,
137c881178SDavid du Colombier Rawbuf= 0x10000,
147c881178SDavid du Colombier Rawmask= Rawbuf-1,
157c881178SDavid du Colombier };
167c881178SDavid du Colombier
177c881178SDavid du Colombier #define nsecperchar ((int)(1000000000.0 * 10.0 / baud))
187c881178SDavid du Colombier
197c881178SDavid du Colombier typedef struct Fix Fix;
207c881178SDavid du Colombier typedef struct Satellite Satellite;
217c881178SDavid du Colombier typedef struct GPSfile GPSfile;
227c881178SDavid du Colombier typedef struct Gpsmsg Gpsmsg;
237c881178SDavid du Colombier
247c881178SDavid du Colombier struct Satellite {
257c881178SDavid du Colombier int prn;
267c881178SDavid du Colombier int elevation;
277c881178SDavid du Colombier int azimuth;
287c881178SDavid du Colombier int snr;
297c881178SDavid du Colombier };
307c881178SDavid du Colombier
317c881178SDavid du Colombier struct Fix {
327c881178SDavid du Colombier int messages; /* bitmap of types seen */
337c881178SDavid du Colombier Place;
347c881178SDavid du Colombier /*
357c881178SDavid du Colombier * The following are in Plan 9 time format:
367c881178SDavid du Colombier * seconds or nanoseconds since the epoch.
377c881178SDavid du Colombier */
387c881178SDavid du Colombier vlong localtime; /* nsec() value when first byte was read */
397c881178SDavid du Colombier vlong gpstime; /* nsec() value from GPS */
407c881178SDavid du Colombier long time; /* time() value from GPS */
417c881178SDavid du Colombier
427c881178SDavid du Colombier double zulu;
437c881178SDavid du Colombier int date;
447c881178SDavid du Colombier char valid;
457c881178SDavid du Colombier uchar quality;
467c881178SDavid du Colombier ushort satellites;
477c881178SDavid du Colombier double pdop;
487c881178SDavid du Colombier double hdop;
497c881178SDavid du Colombier double vdop;
507c881178SDavid du Colombier double altitude;
517c881178SDavid du Colombier double sealevel;
527c881178SDavid du Colombier double groundspeed;
537c881178SDavid du Colombier double kmh;
547c881178SDavid du Colombier double course;
557c881178SDavid du Colombier double heading;
567c881178SDavid du Colombier double magvar;
577c881178SDavid du Colombier Satellite s[12];
587c881178SDavid du Colombier };
597c881178SDavid du Colombier
607c881178SDavid du Colombier struct GPSfile {
617c881178SDavid du Colombier char *name;
627c881178SDavid du Colombier char* (*rread)(Req*);
637c881178SDavid du Colombier int mode;
647c881178SDavid du Colombier vlong offset; /* for raw: rawout - read-offset */
657c881178SDavid du Colombier };
667c881178SDavid du Colombier
677c881178SDavid du Colombier enum {
687c881178SDavid du Colombier ASTRAL,
697c881178SDavid du Colombier GPGGA,
707c881178SDavid du Colombier GPGLL,
717c881178SDavid du Colombier GPGSA,
727c881178SDavid du Colombier GPGSV,
737c881178SDavid du Colombier GPRMC,
747c881178SDavid du Colombier GPVTG,
757c881178SDavid du Colombier PRWIRID,
767c881178SDavid du Colombier PRWIZCH
777c881178SDavid du Colombier };
787c881178SDavid du Colombier
797c881178SDavid du Colombier struct Gpsmsg {
807c881178SDavid du Colombier char *name;
817c881178SDavid du Colombier int tokens;
827c881178SDavid du Colombier ulong errors;
837c881178SDavid du Colombier };
847c881178SDavid du Colombier
857c881178SDavid du Colombier char raw[Rawbuf];
867c881178SDavid du Colombier vlong rawin;
877c881178SDavid du Colombier vlong rawout;
887c881178SDavid du Colombier
895e6bdc2cSDavid du Colombier ulong badlat, goodlat, suspectlat;
905e6bdc2cSDavid du Colombier ulong badlon, goodlon, suspectlon;
915e6bdc2cSDavid du Colombier ulong suspecttime, goodtime;
925e6bdc2cSDavid du Colombier
937c881178SDavid du Colombier ulong histo[32];
947c881178SDavid du Colombier
957c881178SDavid du Colombier char *serial = "/dev/eia0";
967c881178SDavid du Colombier
977c881178SDavid du Colombier Gpsmsg gpsmsg[] = {
987c881178SDavid du Colombier [ASTRAL] = { "ASTRAL", 0, 0},
997c881178SDavid du Colombier [GPGGA] = { "$GPGGA", 15, 0},
100*3b86f2f8SDavid du Colombier /* NMEA 2.3 permits optional 8th field, mode */
1017c881178SDavid du Colombier [GPGLL] = { "$GPGLL", 7, 0},
1027c881178SDavid du Colombier [GPGSA] = { "$GPGSA", 18, 0},
1037c881178SDavid du Colombier [GPGSV] = { "$GPGSV", 0, 0},
1047c881178SDavid du Colombier [GPRMC] = { "$GPRMC", 0, 0},
1057c881178SDavid du Colombier [GPVTG] = { "$GPVTG", 0, 0},
1067c881178SDavid du Colombier [PRWIRID] = { "$PRWIRID", 0, 0},
1077c881178SDavid du Colombier [PRWIZCH] = { "$PRWIZCH", 0, 0},
1087c881178SDavid du Colombier };
1097c881178SDavid du Colombier
1107c881178SDavid du Colombier int ttyfd, ctlfd, debug;
1117c881178SDavid du Colombier int setrtc;
1127c881178SDavid du Colombier int baud = Baud;
1135e6bdc2cSDavid du Colombier char *baudstr = "b%dd1r1pns1l8i9";
1147c881178SDavid du Colombier ulong seconds;
1157c881178SDavid du Colombier ulong starttime;
1167c881178SDavid du Colombier ulong checksumerrors;
1177c881178SDavid du Colombier int gpsplayback; /* If set, return times and positions with `invalid' marker set */
1187c881178SDavid du Colombier
1197c881178SDavid du Colombier Place where = {-(74.0 + 23.9191/60.0), 40.0 + 41.1346/60.0};
1207c881178SDavid du Colombier
1217c881178SDavid du Colombier Fix curfix;
1227c881178SDavid du Colombier Lock fixlock;
1237c881178SDavid du Colombier
1247c881178SDavid du Colombier int type(char*);
1257c881178SDavid du Colombier void setline(void);
1267c881178SDavid du Colombier int getonechar(vlong*);
1277c881178SDavid du Colombier void getline(char*, int, vlong*);
1287c881178SDavid du Colombier void putline(char*);
1295e6bdc2cSDavid du Colombier int gettime(Fix*);
1307c881178SDavid du Colombier int getzulu(char *, Fix*);
1317c881178SDavid du Colombier int getalt(char*, char*, Fix*);
1327c881178SDavid du Colombier int getsea(char*, char*, Fix*);
1337c881178SDavid du Colombier int getlat(char*, char*, Fix*);
1347c881178SDavid du Colombier int getlon(char*, char*, Fix*);
1357c881178SDavid du Colombier int getgs(char*, Fix *);
1367c881178SDavid du Colombier int getkmh(char*, Fix*);
1377c881178SDavid du Colombier int getcrs(char*, Fix*);
1387c881178SDavid du Colombier int gethdg(char*, Fix*);
1397c881178SDavid du Colombier int getdate(char*, Fix*);
1407c881178SDavid du Colombier int getmagvar(char*, char*, Fix*);
1417c881178SDavid du Colombier void printfix(int, Fix*);
1427c881178SDavid du Colombier void ropen(Req *r);
1437c881178SDavid du Colombier void rread(Req *r);
1447c881178SDavid du Colombier void rend(Srv *s);
1457c881178SDavid du Colombier void gpsinit(void);
1467c881178SDavid du Colombier char* readposn(Req*);
1477c881178SDavid du Colombier char* readtime(Req*);
1487c881178SDavid du Colombier char* readsats(Req*);
1497c881178SDavid du Colombier char* readstats(Req*);
1507c881178SDavid du Colombier char* readraw(Req*);
1517c881178SDavid du Colombier
1527c881178SDavid du Colombier GPSfile files[] = {
1537c881178SDavid du Colombier { "time", readtime, 0444, 0 },
1547c881178SDavid du Colombier { "position", readposn, 0444, 0 },
1557c881178SDavid du Colombier { "satellites", readsats, 0444, 0 },
1567c881178SDavid du Colombier { "stats", readstats, 0444, 0 },
1577c881178SDavid du Colombier { "raw", readraw, DMEXCL|0444, 0 },
1587c881178SDavid du Colombier };
1597c881178SDavid du Colombier
1607c881178SDavid du Colombier Srv s = {
1617c881178SDavid du Colombier .open = ropen,
1627c881178SDavid du Colombier .read = rread,
1637c881178SDavid du Colombier
1647c881178SDavid du Colombier .end = rend,
1657c881178SDavid du Colombier };
1667c881178SDavid du Colombier
1677c881178SDavid du Colombier File *root;
1687c881178SDavid du Colombier File *gpsdir;
1697c881178SDavid du Colombier
1707c881178SDavid du Colombier void
rend(Srv *)1717c881178SDavid du Colombier rend(Srv *)
1727c881178SDavid du Colombier {
1737c881178SDavid du Colombier sysfatal("gpsfs demised");
1747c881178SDavid du Colombier }
1757c881178SDavid du Colombier
1767c881178SDavid du Colombier void
ropen(Req * r)1777c881178SDavid du Colombier ropen(Req *r)
1787c881178SDavid du Colombier {
1797c881178SDavid du Colombier respond(r, nil);
1807c881178SDavid du Colombier }
1817c881178SDavid du Colombier
1827c881178SDavid du Colombier void
rread(Req * r)1837c881178SDavid du Colombier rread(Req *r)
1847c881178SDavid du Colombier {
1857c881178SDavid du Colombier GPSfile *f;
1867c881178SDavid du Colombier
1877c881178SDavid du Colombier r->ofcall.count = 0;
1887c881178SDavid du Colombier f = r->fid->file->aux;
1897c881178SDavid du Colombier respond(r, f->rread(r));
1907c881178SDavid du Colombier }
1917c881178SDavid du Colombier
1927c881178SDavid du Colombier void
fsinit(void)1937c881178SDavid du Colombier fsinit(void)
1947c881178SDavid du Colombier {
1957c881178SDavid du Colombier char* user;
1967c881178SDavid du Colombier int i;
1977c881178SDavid du Colombier
1987c881178SDavid du Colombier user = getuser();
1997c881178SDavid du Colombier s.tree = alloctree(user, user, 0555, nil);
2007c881178SDavid du Colombier if(s.tree == nil)
2017c881178SDavid du Colombier sysfatal("fsinit: alloctree: %r");
2027c881178SDavid du Colombier root = s.tree->root;
2037c881178SDavid du Colombier if((gpsdir = createfile(root, "gps", user, DMDIR|0555, nil)) == nil)
2047c881178SDavid du Colombier sysfatal("fsinit: createfile: gps: %r");
2057c881178SDavid du Colombier for(i = 0; i < nelem(files); i++)
2067c881178SDavid du Colombier if(createfile(gpsdir, files[i].name, user, files[i].mode, files + i) == nil)
2077c881178SDavid du Colombier sysfatal("fsinit: createfile: %s: %r", files[i].name);
2087c881178SDavid du Colombier }
2097c881178SDavid du Colombier
2107c881178SDavid du Colombier void
threadmain(int argc,char * argv[])2117c881178SDavid du Colombier threadmain(int argc, char*argv[])
2127c881178SDavid du Colombier {
2137c881178SDavid du Colombier char *srvname, *mntpt;
2147c881178SDavid du Colombier
2157c881178SDavid du Colombier srvname = "gps";
2167c881178SDavid du Colombier mntpt = "/mnt";
2177c881178SDavid du Colombier
2187c881178SDavid du Colombier ARGBEGIN {
2197c881178SDavid du Colombier default:
2207c881178SDavid du Colombier fprint(2, "usage: %s [-b baud] [-d device] [-l logfile] [-m mntpt] [-r] [-s postname]\n", argv0);
2217c881178SDavid du Colombier exits("usage");
2227c881178SDavid du Colombier case 'D':
2237c881178SDavid du Colombier debug++;
2247c881178SDavid du Colombier break;
2257c881178SDavid du Colombier case 'b':
2267c881178SDavid du Colombier baud = strtol(ARGF(), nil, 0);
2277c881178SDavid du Colombier break;
2287c881178SDavid du Colombier case 'd':
2297c881178SDavid du Colombier serial = ARGF();
2307c881178SDavid du Colombier break;
2317c881178SDavid du Colombier case 'r':
2327c881178SDavid du Colombier setrtc = 1;
2337c881178SDavid du Colombier break;
2347c881178SDavid du Colombier case 's':
2357c881178SDavid du Colombier srvname = ARGF();
2367c881178SDavid du Colombier break;
2377c881178SDavid du Colombier case 'm':
2387c881178SDavid du Colombier mntpt = ARGF();
2397c881178SDavid du Colombier break;
2407c881178SDavid du Colombier } ARGEND
2417c881178SDavid du Colombier
2427c881178SDavid du Colombier fmtinstall('L', placeconv);
2437c881178SDavid du Colombier
2447c881178SDavid du Colombier rfork(RFNOTEG);
2457c881178SDavid du Colombier
2467c881178SDavid du Colombier fsinit();
2477c881178SDavid du Colombier gpsinit();
2487c881178SDavid du Colombier threadpostmountsrv(&s, srvname, mntpt, MBEFORE);
2497c881178SDavid du Colombier threadexits(nil);
2507c881178SDavid du Colombier }
2517c881178SDavid du Colombier
2527c881178SDavid du Colombier static void
gpstrack(void *)2537c881178SDavid du Colombier gpstrack(void *)
2547c881178SDavid du Colombier {
2557c881178SDavid du Colombier Fix fix;
2567c881178SDavid du Colombier static char buf[256], *t[32];
2577c881178SDavid du Colombier int n, i, k, tp;
2587c881178SDavid du Colombier vlong localtime;
259843560e6SDavid du Colombier double d;
2607c881178SDavid du Colombier
2617c881178SDavid du Colombier setline();
2627c881178SDavid du Colombier fix.messages = 0;
2635e6bdc2cSDavid du Colombier fix.lon = 181.0;
2645e6bdc2cSDavid du Colombier fix.lat = 91.0;
2657c881178SDavid du Colombier fix.zulu = 0;
2667c881178SDavid du Colombier fix.date = 0;
2677c881178SDavid du Colombier fix.valid = 0;
2687c881178SDavid du Colombier fix.quality = 0;
2697c881178SDavid du Colombier fix.satellites = 0;
2707c881178SDavid du Colombier fix.pdop = 0.0;
2717c881178SDavid du Colombier fix.hdop = 0.0;
2727c881178SDavid du Colombier fix.vdop = 0.0;
2737c881178SDavid du Colombier fix.altitude = 0.0;
2747c881178SDavid du Colombier fix.sealevel = 0.0;
2757c881178SDavid du Colombier fix.groundspeed = 0.0;
2767c881178SDavid du Colombier fix.kmh = 0.0;
2777c881178SDavid du Colombier fix.course = 0.0;
2787c881178SDavid du Colombier fix.heading = 0.0;
2797c881178SDavid du Colombier fix.magvar = 0.0;
2807c881178SDavid du Colombier for(;;){
2817c881178SDavid du Colombier getline(buf, sizeof buf, &localtime);
2827c881178SDavid du Colombier n = getfields(buf, t, nelem(t), 0,",\r\n");
2837c881178SDavid du Colombier if(n == 0)
2847c881178SDavid du Colombier continue;
2857c881178SDavid du Colombier tp = type(t[0]);
286*3b86f2f8SDavid du Colombier if(tp >= 0 && tp < nelem(gpsmsg) && gpsmsg[tp].tokens &&
287*3b86f2f8SDavid du Colombier gpsmsg[tp].tokens > n){
2887c881178SDavid du Colombier gpsmsg[tp].errors++;
2897c881178SDavid du Colombier if(debug)
2907c881178SDavid du Colombier fprint(2, "%s: Expect %d tokens, got %d\n",
2917c881178SDavid du Colombier gpsmsg[tp].name, gpsmsg[tp].tokens, n);
2927c881178SDavid du Colombier continue;
2937c881178SDavid du Colombier }
2947c881178SDavid du Colombier switch(tp){
2957c881178SDavid du Colombier case ASTRAL:
2967c881178SDavid du Colombier putline("$IIGPQ,ASTRAL*73");
2977c881178SDavid du Colombier putline("$PRWIILOG,GGA,A,T,10,0");
2987c881178SDavid du Colombier putline("$PRWIILOG,RMC,A,T,10,0");
2997c881178SDavid du Colombier putline("$PRWIILOG,GSA,A,T,10,0");
3007c881178SDavid du Colombier putline("$PRWIILOG,GSV,V,,,");
3017c881178SDavid du Colombier fprint(2, "Reply: %s\n", "$IIGPQ,ASTRAL*73");
3027c881178SDavid du Colombier break;
3037c881178SDavid du Colombier case PRWIRID:
3047c881178SDavid du Colombier case PRWIZCH:
3057c881178SDavid du Colombier for(i = 0; i < n; i++) fprint(2, "%s,", t[i]);
3067c881178SDavid du Colombier fprint(2, "(%d tokens)\n", n);
3077c881178SDavid du Colombier break;
3087c881178SDavid du Colombier case GPGGA:
3095e6bdc2cSDavid du Colombier if(getlat(t[2], t[3], &fix))
3105e6bdc2cSDavid du Colombier break;
3115e6bdc2cSDavid du Colombier if(getlon(t[4], t[5], &fix))
3125e6bdc2cSDavid du Colombier break;
3137c881178SDavid du Colombier getzulu(t[1], &fix);
3145e6bdc2cSDavid du Colombier if(fix.date && gettime(&fix))
3155e6bdc2cSDavid du Colombier break;
3167c881178SDavid du Colombier if(isdigit(*t[7]))
3177c881178SDavid du Colombier fix.satellites = strtol(t[7], nil, 10);
318843560e6SDavid du Colombier if(isdigit(*t[8])){
319843560e6SDavid du Colombier d = strtod(t[8], nil);
320843560e6SDavid du Colombier if(!isNaN(d))
321843560e6SDavid du Colombier fix.hdop = d;
322843560e6SDavid du Colombier }
3237c881178SDavid du Colombier getalt(t[9], t[10], &fix);
3247c881178SDavid du Colombier getsea(t[11], t[12], &fix);
3255e6bdc2cSDavid du Colombier fix.localtime = localtime;
3265e6bdc2cSDavid du Colombier fix.quality = strtol(t[6], nil, 10);
3275e6bdc2cSDavid du Colombier fix.messages |= 1 << tp;
3287c881178SDavid du Colombier break;
3297c881178SDavid du Colombier case GPRMC:
3307c881178SDavid du Colombier fix.valid = *t[2];
3317c881178SDavid du Colombier getgs(t[7], &fix);
3327c881178SDavid du Colombier getcrs(t[8], &fix);
3337c881178SDavid du Colombier getdate(t[9], &fix);
3347c881178SDavid du Colombier getmagvar(t[10], t[11], &fix);
3357c881178SDavid du Colombier if((fix.messages & (1 << GPGGA)) == 0){
3365e6bdc2cSDavid du Colombier if(getlat(t[3], t[4], &fix))
3375e6bdc2cSDavid du Colombier break;
3385e6bdc2cSDavid du Colombier if(getlon(t[5], t[6], &fix))
3395e6bdc2cSDavid du Colombier break;
3407c881178SDavid du Colombier fix.localtime = localtime;
3417c881178SDavid du Colombier getzulu(t[1], &fix);
3427c881178SDavid du Colombier if(fix.date)
3437c881178SDavid du Colombier gettime(&fix);
3447c881178SDavid du Colombier }
3455e6bdc2cSDavid du Colombier fix.messages |= 1 << tp;
3467c881178SDavid du Colombier break;
3477c881178SDavid du Colombier case GPGSA:
348843560e6SDavid du Colombier if(*t[15]){
349843560e6SDavid du Colombier d = strtod(t[15], nil);
350843560e6SDavid du Colombier if(!isNaN(d))
351843560e6SDavid du Colombier fix.pdop = d;
352843560e6SDavid du Colombier }
353843560e6SDavid du Colombier if(*t[16]){
354843560e6SDavid du Colombier d = strtod(t[16], nil);
355843560e6SDavid du Colombier if(!isNaN(d))
356843560e6SDavid du Colombier fix.hdop = d;
357843560e6SDavid du Colombier }
358843560e6SDavid du Colombier if(*t[17]){
359843560e6SDavid du Colombier d = strtod(t[17], nil);
360843560e6SDavid du Colombier if(!isNaN(d))
361843560e6SDavid du Colombier fix.vdop = d;
362843560e6SDavid du Colombier }
3635e6bdc2cSDavid du Colombier fix.messages |= 1 << tp;
3647c881178SDavid du Colombier break;
3657c881178SDavid du Colombier case GPGLL:
3665e6bdc2cSDavid du Colombier if(getlat(t[1], t[2], &fix))
3675e6bdc2cSDavid du Colombier break;
3685e6bdc2cSDavid du Colombier if(getlon(t[3], t[4], &fix))
3695e6bdc2cSDavid du Colombier break;
3707c881178SDavid du Colombier getzulu(t[5], &fix);
3715e6bdc2cSDavid du Colombier fix.messages |= 1 << tp;
3727c881178SDavid du Colombier break;
3737c881178SDavid du Colombier case GPGSV:
3747c881178SDavid du Colombier if(n < 8){
3757c881178SDavid du Colombier gpsmsg[tp].errors++;
3767c881178SDavid du Colombier if(debug)
3777c881178SDavid du Colombier fprint(2, "%s: Expect at least 8 tokens, got %d\n",
3787c881178SDavid du Colombier gpsmsg[tp].name, n);
3797c881178SDavid du Colombier break;
3807c881178SDavid du Colombier }
3817c881178SDavid du Colombier i = 4*(strtol(t[2], nil, 10)-1); /* starting entry in satellite table */
3827c881178SDavid du Colombier fix.satellites = strtol(t[3], nil, 10);
3837c881178SDavid du Colombier k = 4;
3847c881178SDavid du Colombier while(i < nelem(fix.s) && k + 3 < n){
3857c881178SDavid du Colombier fix.s[i].prn = strtol(t[k++], nil, 10);
3867c881178SDavid du Colombier fix.s[i].elevation = strtol(t[k++], nil, 10);
3877c881178SDavid du Colombier fix.s[i].azimuth = strtol(t[k++], nil, 10);
3887c881178SDavid du Colombier fix.s[i].snr = strtol(t[k++], nil, 10);
3897c881178SDavid du Colombier k += 4;
3907c881178SDavid du Colombier i++;
3917c881178SDavid du Colombier }
3925e6bdc2cSDavid du Colombier fix.messages |= 1 << tp;
3935e6bdc2cSDavid du Colombier break;
3947c881178SDavid du Colombier case GPVTG:
3957c881178SDavid du Colombier if(n < 8){
3967c881178SDavid du Colombier gpsmsg[tp].errors++;
3977c881178SDavid du Colombier if(debug)
3987c881178SDavid du Colombier fprint(2, "%s: Expect at least 8 tokens, got %d\n",
3997c881178SDavid du Colombier gpsmsg[tp].name, n);
4007c881178SDavid du Colombier break;
4017c881178SDavid du Colombier }
4027c881178SDavid du Colombier getcrs(t[2], &fix);
4037c881178SDavid du Colombier gethdg(t[4], &fix);
4047c881178SDavid du Colombier getgs(t[6], &fix);
4057c881178SDavid du Colombier if(n > 8)
4067c881178SDavid du Colombier getkmh(t[8], &fix);
4075e6bdc2cSDavid du Colombier fix.messages |= 1 << tp;
4087c881178SDavid du Colombier break;
4097c881178SDavid du Colombier default:
4107c881178SDavid du Colombier if(debug && fix.date)
4117c881178SDavid du Colombier fprint(2, "Don't know %s\n", t[0]);
4127c881178SDavid du Colombier break;
4137c881178SDavid du Colombier }
4147c881178SDavid du Colombier if(fix.valid){
4157c881178SDavid du Colombier seconds++;
4167c881178SDavid du Colombier lock(&fixlock);
4177c881178SDavid du Colombier memmove(&curfix, &fix, sizeof fix);
4187c881178SDavid du Colombier unlock(&fixlock);
4197c881178SDavid du Colombier if(debug)
4207c881178SDavid du Colombier printfix(2, &fix);
4217c881178SDavid du Colombier fix.valid = 0;
4227c881178SDavid du Colombier fix.messages = 0;
4237c881178SDavid du Colombier for(i = 0; i < nelem(fix.s); i++)
4247c881178SDavid du Colombier fix.s[i].prn = 0;
4257c881178SDavid du Colombier if(gpsplayback)
4267c881178SDavid du Colombier sleep(100);
4277c881178SDavid du Colombier }
4287c881178SDavid du Colombier }
4297c881178SDavid du Colombier }
4307c881178SDavid du Colombier
4317c881178SDavid du Colombier void
gpsinit(void)4327c881178SDavid du Colombier gpsinit(void)
4337c881178SDavid du Colombier {
4347c881178SDavid du Colombier proccreate(gpstrack, nil, 4096);
4357c881178SDavid du Colombier }
4367c881178SDavid du Colombier
4377c881178SDavid du Colombier void
printfix(int f,Fix * fix)4387c881178SDavid du Colombier printfix(int f, Fix *fix){
4397c881178SDavid du Colombier int i;
4407c881178SDavid du Colombier
4417c881178SDavid du Colombier fprint(f, "%L, ", fix->Place);
4427c881178SDavid du Colombier fprint(f, "%g, ", fix->magvar);
4437c881178SDavid du Colombier fprint(f, "%gm - %gm = %gm, ", fix->altitude, fix->sealevel, fix->altitude - fix->sealevel);
4447c881178SDavid du Colombier fprint(f, "%06dZ(%g)-", (int)fix->zulu, fix->zulu);
4457c881178SDavid du Colombier fprint(f, "%06d\n", fix->date);
4467c881178SDavid du Colombier if(fix->lat >= 0)
4477c881178SDavid du Colombier fprint(f, "%11.8fN, ", fix->lat);
4487c881178SDavid du Colombier else
4497c881178SDavid du Colombier fprint(f, "%11.8fS, ", -fix->lat);
4507c881178SDavid du Colombier if(fix->lon >= 0)
4517c881178SDavid du Colombier fprint(f, "%12.8fE, ", fix->lon);
4527c881178SDavid du Colombier else
4537c881178SDavid du Colombier fprint(f, "%12.8fW, ", -fix->lon);
4547c881178SDavid du Colombier fprint(f, "%g@%g, ", fix->course, fix->groundspeed);
4557c881178SDavid du Colombier fprint(f, "(%c, %ds)\n", fix->valid, fix->satellites);
4567c881178SDavid du Colombier for(i = 0; i < nelem(fix->s); i++){
4577c881178SDavid du Colombier if(fix->s[i].prn == 0)
4587c881178SDavid du Colombier continue;
4597c881178SDavid du Colombier fprint(f, "[%d, %d°, %d°, %d]\n",
4607c881178SDavid du Colombier fix->s[i].prn, fix->s[i].elevation, fix->s[i].azimuth, fix->s[i].snr);
4617c881178SDavid du Colombier }
4627c881178SDavid du Colombier }
4637c881178SDavid du Colombier
4647c881178SDavid du Colombier char*
readposn(Req * r)4657c881178SDavid du Colombier readposn(Req *r)
4667c881178SDavid du Colombier {
4677c881178SDavid du Colombier Fix f;
4687c881178SDavid du Colombier char buf[256];
4697c881178SDavid du Colombier
4707c881178SDavid du Colombier lock(&fixlock);
4717c881178SDavid du Colombier memmove(&f, &curfix, sizeof f);
4727c881178SDavid du Colombier unlock(&fixlock);
4737c881178SDavid du Colombier snprint(buf, sizeof buf, "%x %06dZ %lud %g %g %g %g %g %g",
4747c881178SDavid du Colombier gpsplayback|f.quality, (int)f.zulu, f.time, f.lon, f.lat, f.altitude - f.sealevel,
4757c881178SDavid du Colombier f.course, f.groundspeed, f.magvar);
4767c881178SDavid du Colombier readstr(r, buf);
4777c881178SDavid du Colombier return nil;
4787c881178SDavid du Colombier }
4797c881178SDavid du Colombier
4807c881178SDavid du Colombier char*
readtime(Req * r)4817c881178SDavid du Colombier readtime(Req *r)
4827c881178SDavid du Colombier {
4837c881178SDavid du Colombier Fix f;
4847c881178SDavid du Colombier char buf[Numsize+Vlnumsize+Vlnumsize+8];
4857c881178SDavid du Colombier
4867c881178SDavid du Colombier lock(&fixlock);
4877c881178SDavid du Colombier memmove(&f, &curfix, sizeof f);
4887c881178SDavid du Colombier unlock(&fixlock);
4897c881178SDavid du Colombier seprint(buf, buf + sizeof buf, "%*.0lud %*.0llud %*.0llud %c",
4907c881178SDavid du Colombier Numsize-1, f.time,
4917c881178SDavid du Colombier Vlnumsize-1, f.gpstime,
4927c881178SDavid du Colombier Vlnumsize-1, f.localtime, f.valid + (gpsplayback?1:0));
4937c881178SDavid du Colombier readstr(r, buf);
4947c881178SDavid du Colombier return nil;
4957c881178SDavid du Colombier }
4967c881178SDavid du Colombier
4977c881178SDavid du Colombier char*
readstats(Req * r)4987c881178SDavid du Colombier readstats(Req *r)
4997c881178SDavid du Colombier {
5007c881178SDavid du Colombier int i;
5017c881178SDavid du Colombier char buf[1024], *p;
5027c881178SDavid du Colombier
5037c881178SDavid du Colombier p = buf;
5047c881178SDavid du Colombier p = seprint(p, buf + sizeof buf, "%lld bytes read, %ld samples processed in %ld seconds\n",
5057c881178SDavid du Colombier rawin, seconds, curfix.time - starttime);
5067c881178SDavid du Colombier p = seprint(p, buf + sizeof buf, "%lud checksum errors\n", checksumerrors);
5077c881178SDavid du Colombier p = seprint(p, buf + sizeof buf, "format errors:");
5087c881178SDavid du Colombier for(i = 0; i < nelem(gpsmsg); i++){
5097c881178SDavid du Colombier p = seprint(p, buf + sizeof buf, "[%s]: %ld, ",
5107c881178SDavid du Colombier gpsmsg[i].name, gpsmsg[i].errors);
5117c881178SDavid du Colombier }
5127c881178SDavid du Colombier p = seprint(p, buf + sizeof buf, "\nhistogram of # bytes received per buffer:\n");
5137c881178SDavid du Colombier for(i = 0; i < nelem(histo); i++){
5147c881178SDavid du Colombier p = seprint(p, buf + sizeof buf, "[%d]: %ld ",
5157c881178SDavid du Colombier i, histo[i]);
5167c881178SDavid du Colombier }
5175e6bdc2cSDavid du Colombier p = seprint(p, buf + sizeof buf, "\n");
5185e6bdc2cSDavid du Colombier p = seprint(p, buf + sizeof buf, "bad/good/suspect lat: %lud/%lud/%lud\n",
5195e6bdc2cSDavid du Colombier badlat, goodlat, suspectlat);
5205e6bdc2cSDavid du Colombier p = seprint(p, buf + sizeof buf, "bad/good/suspect lon: %lud/%lud/%lud\n",
5215e6bdc2cSDavid du Colombier badlon, goodlon, suspectlon);
5225e6bdc2cSDavid du Colombier p = seprint(p, buf + sizeof buf, "good/suspect time: %lud/%lud\n", goodtime, suspecttime);
5235e6bdc2cSDavid du Colombier USED(p);
5247c881178SDavid du Colombier readstr(r, buf);
5257c881178SDavid du Colombier return nil;
5267c881178SDavid du Colombier }
5277c881178SDavid du Colombier
5287c881178SDavid du Colombier char*
readsats(Req * r)5297c881178SDavid du Colombier readsats(Req *r)
5307c881178SDavid du Colombier {
5317c881178SDavid du Colombier Fix f;
5327c881178SDavid du Colombier int i;
5337c881178SDavid du Colombier char buf[1024], *p;
5347c881178SDavid du Colombier
5357c881178SDavid du Colombier lock(&fixlock);
5367c881178SDavid du Colombier memmove(&f, &curfix, sizeof f);
5377c881178SDavid du Colombier unlock(&fixlock);
5387c881178SDavid du Colombier p = seprint(buf, buf + sizeof buf, "%d %d\n", gpsplayback|f.quality, f.satellites);
5397c881178SDavid du Colombier for(i = 0; i < nelem(f.s); i++){
5407c881178SDavid du Colombier if(f.s[i].prn == 0)
5417c881178SDavid du Colombier continue;
5427c881178SDavid du Colombier p = seprint(p, buf + sizeof buf, "%d %d %d %d\n",
5437c881178SDavid du Colombier f.s[i].prn, f.s[i].elevation, f.s[i].azimuth, f.s[i].snr);
5447c881178SDavid du Colombier }
5457c881178SDavid du Colombier readstr(r, buf);
5467c881178SDavid du Colombier return nil;
5477c881178SDavid du Colombier }
5487c881178SDavid du Colombier
5497c881178SDavid du Colombier char*
readraw(Req * r)5507c881178SDavid du Colombier readraw(Req *r)
5517c881178SDavid du Colombier {
5527c881178SDavid du Colombier int n;
5537c881178SDavid du Colombier GPSfile *f;
5547c881178SDavid du Colombier
5557c881178SDavid du Colombier f = r->fid->file->aux;
5567c881178SDavid du Colombier if(rawin - rawout > Rawbuf){
5577c881178SDavid du Colombier rawout = rawin - Rawbuf;
5587c881178SDavid du Colombier f->offset = rawout - r->ifcall.offset;
5597c881178SDavid du Colombier }
5607c881178SDavid du Colombier n = Rawbuf - (rawout&Rawmask);
5617c881178SDavid du Colombier if(rawin - rawout < n)
5627c881178SDavid du Colombier n = rawin - rawout;
5637c881178SDavid du Colombier if(r->ifcall.count < n)
5647c881178SDavid du Colombier n = r->ifcall.count;
5657c881178SDavid du Colombier r->ofcall.count = n;
5667c881178SDavid du Colombier if(n > 0){
5677c881178SDavid du Colombier memmove(r->ofcall.data, raw + (rawout & Rawmask), n);
5687c881178SDavid du Colombier rawout += n;
5697c881178SDavid du Colombier }
5707c881178SDavid du Colombier return nil;
5717c881178SDavid du Colombier }
5727c881178SDavid du Colombier
5737c881178SDavid du Colombier void
rtcset(long t)5747c881178SDavid du Colombier rtcset(long t)
5757c881178SDavid du Colombier {
5767c881178SDavid du Colombier static int fd;
5777c881178SDavid du Colombier long r;
5787c881178SDavid du Colombier int n;
5797c881178SDavid du Colombier char buf[32];
5807c881178SDavid du Colombier
5817c881178SDavid du Colombier if(fd <= 0 && (fd = open("#r/rtc", ORDWR)) < 0){
5827c881178SDavid du Colombier fprint(2, "Can't open #r/rtc: %r\n");
5837c881178SDavid du Colombier return;
5847c881178SDavid du Colombier }
5857c881178SDavid du Colombier n = read(fd, buf, sizeof buf - 1);
5867c881178SDavid du Colombier if(n <= 0){
5877c881178SDavid du Colombier fprint(2, "Can't read #r/rtc: %r\n");
5887c881178SDavid du Colombier return;
5897c881178SDavid du Colombier }
5907c881178SDavid du Colombier buf[n] = '\0';
5917c881178SDavid du Colombier r = strtol(buf, nil, 0);
5927c881178SDavid du Colombier if(r <= 0){
5937c881178SDavid du Colombier fprint(2, "ridiculous #r/rtc: %ld\n", r);
5947c881178SDavid du Colombier return;
5957c881178SDavid du Colombier }
5967c881178SDavid du Colombier if(r - t > 1 || t - r > 0){
5977c881178SDavid du Colombier seek(fd, 0, 0);
5987c881178SDavid du Colombier fprint(fd, "%ld", t);
5997c881178SDavid du Colombier fprint(2, "correcting #r/rtc: %ld → %ld\n", r, t);
6007c881178SDavid du Colombier }
6017c881178SDavid du Colombier seek(fd, 0, 0);
6027c881178SDavid du Colombier }
6037c881178SDavid du Colombier
6045e6bdc2cSDavid du Colombier int
gettime(Fix * f)6057c881178SDavid du Colombier gettime(Fix *f){
6067c881178SDavid du Colombier /* Convert zulu time and date to Plan9 time(2) */
6077c881178SDavid du Colombier Tm tm;
6087c881178SDavid du Colombier int zulu;
6097c881178SDavid du Colombier double d;
6105e6bdc2cSDavid du Colombier long t;
6115e6bdc2cSDavid du Colombier static int count;
6127c881178SDavid du Colombier
6137c881178SDavid du Colombier zulu = f->zulu;
6147c881178SDavid du Colombier memset(&tm, 0, sizeof tm );
6157c881178SDavid du Colombier tm.sec = zulu % 100;
6167c881178SDavid du Colombier tm.min = (zulu/100) % 100;
6177c881178SDavid du Colombier tm.hour = zulu / 10000;
6187c881178SDavid du Colombier tm.year = f->date % 100 + 100; /* This'll only work until 2099 */
6197c881178SDavid du Colombier tm.mon = ((f->date/100) % 100) - 1;
6207c881178SDavid du Colombier tm.mday = f->date / 10000;
6217c881178SDavid du Colombier strcpy(tm.zone, "GMT");
6225e6bdc2cSDavid du Colombier t = tm2sec(&tm);
6235e6bdc2cSDavid du Colombier if(f->time && count < 3 && (t - f->time > 10 || t - f->time <= 0)){
6245e6bdc2cSDavid du Colombier count++;
6255e6bdc2cSDavid du Colombier suspecttime++;
6265e6bdc2cSDavid du Colombier return -1;
6275e6bdc2cSDavid du Colombier }
6285e6bdc2cSDavid du Colombier goodtime++;
6295e6bdc2cSDavid du Colombier f->time = t;
6305e6bdc2cSDavid du Colombier count = 0;
6315e6bdc2cSDavid du Colombier if(starttime == 0) starttime = t;
6325e6bdc2cSDavid du Colombier f->gpstime = 1000000000LL * t + 1000000 * (int)modf(f->zulu, &d);
6337c881178SDavid du Colombier if(setrtc){
6345e6bdc2cSDavid du Colombier if(setrtc == 1 || (t % 300) == 0){
6355e6bdc2cSDavid du Colombier rtcset(t);
6367c881178SDavid du Colombier setrtc++;
6377c881178SDavid du Colombier }
6387c881178SDavid du Colombier }
6395e6bdc2cSDavid du Colombier return 0;
6407c881178SDavid du Colombier }
6417c881178SDavid du Colombier
6427c881178SDavid du Colombier int
getzulu(char * s,Fix * f)6437c881178SDavid du Colombier getzulu(char *s, Fix *f){
644843560e6SDavid du Colombier double d;
645843560e6SDavid du Colombier
6467c881178SDavid du Colombier if(*s == '\0') return 0;
6477c881178SDavid du Colombier if(isdigit(*s)){
648843560e6SDavid du Colombier d = strtod(s, nil);
649843560e6SDavid du Colombier if(!isNaN(d))
650843560e6SDavid du Colombier f->zulu = d;
6517c881178SDavid du Colombier return 1;
6527c881178SDavid du Colombier }
6537c881178SDavid du Colombier return 0;
6547c881178SDavid du Colombier }
6557c881178SDavid du Colombier
6567c881178SDavid du Colombier int
getdate(char * s,Fix * f)6577c881178SDavid du Colombier getdate(char *s, Fix *f){
6587c881178SDavid du Colombier if(*s == 0) return 0;
6597c881178SDavid du Colombier if(isdigit(*s)){
6607c881178SDavid du Colombier f->date = strtol(s, nil, 10);
6617c881178SDavid du Colombier return 1;
6627c881178SDavid du Colombier }
6637c881178SDavid du Colombier return 0;
6647c881178SDavid du Colombier }
6657c881178SDavid du Colombier
6667c881178SDavid du Colombier int
getgs(char * s,Fix * f)667843560e6SDavid du Colombier getgs(char *s, Fix *f){
668843560e6SDavid du Colombier double d;
6697c881178SDavid du Colombier
670843560e6SDavid du Colombier if(*s == 0) return 0;
671843560e6SDavid du Colombier if(isdigit(*s)){
672843560e6SDavid du Colombier d = strtod(s, nil);
673843560e6SDavid du Colombier if(!isNaN(d))
674843560e6SDavid du Colombier f->groundspeed = d;
6757c881178SDavid du Colombier return 1;
6767c881178SDavid du Colombier }
6777c881178SDavid du Colombier return 0;
6787c881178SDavid du Colombier }
6797c881178SDavid du Colombier
6807c881178SDavid du Colombier int
getkmh(char * s,Fix * f)681843560e6SDavid du Colombier getkmh(char *s, Fix *f){
682843560e6SDavid du Colombier double d;
6837c881178SDavid du Colombier
684843560e6SDavid du Colombier if(*s == 0) return 0;
685843560e6SDavid du Colombier if(isdigit(*s)){
686843560e6SDavid du Colombier d = strtod(s, nil);
687843560e6SDavid du Colombier if(!isNaN(d))
688843560e6SDavid du Colombier f->kmh = d;
6897c881178SDavid du Colombier return 1;
6907c881178SDavid du Colombier }
6917c881178SDavid du Colombier return 0;
6927c881178SDavid du Colombier }
6937c881178SDavid du Colombier
6947c881178SDavid du Colombier int
getcrs(char * s1,Fix * f)6957c881178SDavid du Colombier getcrs(char *s1, Fix *f){
696843560e6SDavid du Colombier double d;
6977c881178SDavid du Colombier
6987c881178SDavid du Colombier if(*s1 == 0) return 0;
6997c881178SDavid du Colombier if(isdigit(*s1)){
700843560e6SDavid du Colombier d = strtod(s1, nil);
701843560e6SDavid du Colombier if(!isNaN(d))
702843560e6SDavid du Colombier f->course = d;
7037c881178SDavid du Colombier return 1;
7047c881178SDavid du Colombier }
7057c881178SDavid du Colombier return 0;
7067c881178SDavid du Colombier }
7077c881178SDavid du Colombier
7087c881178SDavid du Colombier int
gethdg(char * s1,Fix * f)7097c881178SDavid du Colombier gethdg(char *s1, Fix *f){
710843560e6SDavid du Colombier double d;
7117c881178SDavid du Colombier
7127c881178SDavid du Colombier if(*s1 == 0) return 0;
7137c881178SDavid du Colombier if(isdigit(*s1)){
714843560e6SDavid du Colombier d = strtod(s1, nil);
715843560e6SDavid du Colombier if(!isNaN(d))
716843560e6SDavid du Colombier f->heading = d;
7177c881178SDavid du Colombier return 1;
7187c881178SDavid du Colombier }
7197c881178SDavid du Colombier return 0;
7207c881178SDavid du Colombier }
7217c881178SDavid du Colombier
7227c881178SDavid du Colombier int
getalt(char * s1,char * s2,Fix * f)7237c881178SDavid du Colombier getalt(char *s1, char *s2, Fix *f){
7247c881178SDavid du Colombier double alt;
7257c881178SDavid du Colombier
7267c881178SDavid du Colombier if(*s1 == 0) return 0;
7277c881178SDavid du Colombier if(isdigit(*s1)){
7287c881178SDavid du Colombier alt = strtod(s1, nil);
729843560e6SDavid du Colombier if(*s2 == 'M' && !isNaN(alt)){
7307c881178SDavid du Colombier f->altitude = alt;
7317c881178SDavid du Colombier return 1;
7327c881178SDavid du Colombier }
7337c881178SDavid du Colombier return 0;
7347c881178SDavid du Colombier }
7357c881178SDavid du Colombier return 0;
7367c881178SDavid du Colombier }
7377c881178SDavid du Colombier
7387c881178SDavid du Colombier int
getsea(char * s1,char * s2,Fix * f)7397c881178SDavid du Colombier getsea(char *s1, char *s2, Fix *f){
7407c881178SDavid du Colombier double alt;
7417c881178SDavid du Colombier
7427c881178SDavid du Colombier if(*s1 == 0) return 0;
7437c881178SDavid du Colombier if(isdigit(*s1)){
7447c881178SDavid du Colombier alt = strtod(s1, nil);
7457c881178SDavid du Colombier if(*s2 == 'M'){
7467c881178SDavid du Colombier f->sealevel = alt;
7477c881178SDavid du Colombier return 1;
7487c881178SDavid du Colombier }
7497c881178SDavid du Colombier return 0;
7507c881178SDavid du Colombier }
7517c881178SDavid du Colombier return 0;
7527c881178SDavid du Colombier }
7537c881178SDavid du Colombier
7547c881178SDavid du Colombier int
getlat(char * s1,char * s2,Fix * f)7557c881178SDavid du Colombier getlat(char *s1, char *s2, Fix *f){
7567c881178SDavid du Colombier double lat;
7575e6bdc2cSDavid du Colombier static count;
7587c881178SDavid du Colombier
7595e6bdc2cSDavid du Colombier if(*s1 == 0 || !isdigit(*s1) || strlen(s1) <= 5){
7605e6bdc2cSDavid du Colombier badlat++;
7615e6bdc2cSDavid du Colombier return -1;
7625e6bdc2cSDavid du Colombier }
7637c881178SDavid du Colombier lat = strtod(s1+2, nil);
764843560e6SDavid du Colombier if(isNaN(lat)){
765843560e6SDavid du Colombier badlat++;
766843560e6SDavid du Colombier return -1;
767843560e6SDavid du Colombier }
7687c881178SDavid du Colombier lat /= 60.0;
7697c881178SDavid du Colombier lat += 10*(s1[0] - '0') + s1[1] - '0';
7705e6bdc2cSDavid du Colombier if(lat < 0 || lat > 90.0){
7715e6bdc2cSDavid du Colombier badlat++;
7725e6bdc2cSDavid du Colombier return -1;
7737c881178SDavid du Colombier }
7745e6bdc2cSDavid du Colombier switch(*s2){
7755e6bdc2cSDavid du Colombier default:
7765e6bdc2cSDavid du Colombier badlat++;
7775e6bdc2cSDavid du Colombier return -1;
7785e6bdc2cSDavid du Colombier case 'S':
7795e6bdc2cSDavid du Colombier lat = -lat;
7805e6bdc2cSDavid du Colombier case 'N':
7815e6bdc2cSDavid du Colombier break;
7825e6bdc2cSDavid du Colombier }
7835e6bdc2cSDavid du Colombier if(f->lat <= 90.0 && count < 3 && fabs(f->lat - lat) > 10.0){
7845e6bdc2cSDavid du Colombier count++;
7855e6bdc2cSDavid du Colombier suspectlat++;
7865e6bdc2cSDavid du Colombier return -1;
7875e6bdc2cSDavid du Colombier }
7887c881178SDavid du Colombier f->lat = lat;
7895e6bdc2cSDavid du Colombier count = 0;
7905e6bdc2cSDavid du Colombier goodlat++;
7917c881178SDavid du Colombier return 0;
7927c881178SDavid du Colombier }
7937c881178SDavid du Colombier
7947c881178SDavid du Colombier int
getlon(char * s1,char * s2,Fix * f)7957c881178SDavid du Colombier getlon(char *s1, char *s2, Fix *f){
7967c881178SDavid du Colombier double lon;
7975e6bdc2cSDavid du Colombier static count;
7987c881178SDavid du Colombier
7995e6bdc2cSDavid du Colombier if(*s1 == 0 || ! isdigit(*s1) || strlen(s1) <= 5){
8005e6bdc2cSDavid du Colombier badlon++;
8015e6bdc2cSDavid du Colombier return -1;
8025e6bdc2cSDavid du Colombier }
803843560e6SDavid du Colombier lon = strtod(s1+3, nil);
804843560e6SDavid du Colombier if(isNaN(lon)){
805843560e6SDavid du Colombier badlon++;
806843560e6SDavid du Colombier return -1;
807843560e6SDavid du Colombier }
808843560e6SDavid du Colombier lon /= 60.0;
809843560e6SDavid du Colombier lon += 100*(s1[0] - '0') + 10*(s1[1] - '0') + s1[2] - '0';
8105e6bdc2cSDavid du Colombier if(lon < 0 || lon > 180.0){
8115e6bdc2cSDavid du Colombier badlon++;
8125e6bdc2cSDavid du Colombier return -1;
8137c881178SDavid du Colombier }
8145e6bdc2cSDavid du Colombier switch(*s2){
8155e6bdc2cSDavid du Colombier default:
8165e6bdc2cSDavid du Colombier badlon++;
8175e6bdc2cSDavid du Colombier return -1;
8185e6bdc2cSDavid du Colombier case 'W':
8195e6bdc2cSDavid du Colombier lon = -lon;
8205e6bdc2cSDavid du Colombier case 'E':
8215e6bdc2cSDavid du Colombier break;
8225e6bdc2cSDavid du Colombier }
8235e6bdc2cSDavid du Colombier if(f->lon <= 180.0 && count < 3 && fabs(f->lon - lon) > 10.0){
8245e6bdc2cSDavid du Colombier count++;
8255e6bdc2cSDavid du Colombier suspectlon++;
8265e6bdc2cSDavid du Colombier return -1;
8275e6bdc2cSDavid du Colombier }
8287c881178SDavid du Colombier f->lon = lon;
8295e6bdc2cSDavid du Colombier goodlon++;
8305e6bdc2cSDavid du Colombier count = 0;
8317c881178SDavid du Colombier return 0;
8327c881178SDavid du Colombier }
8337c881178SDavid du Colombier
8347c881178SDavid du Colombier int
getmagvar(char * s1,char * s2,Fix * f)8357c881178SDavid du Colombier getmagvar(char *s1, char *s2, Fix *f){
8367c881178SDavid du Colombier double magvar;
8377c881178SDavid du Colombier
8387c881178SDavid du Colombier if(*s1 == 0) return 0;
8397c881178SDavid du Colombier if(isdigit(*s1) && strlen(s1) > 5){
840843560e6SDavid du Colombier magvar = strtod(s1+3, nil);
841843560e6SDavid du Colombier if(isNaN(magvar))
842843560e6SDavid du Colombier return 0;
843843560e6SDavid du Colombier magvar /= 60.0;
844843560e6SDavid du Colombier magvar += 100*(s1[0] - '0') + 10*(s1[1] - '0') + s1[2] - '0';
8457c881178SDavid du Colombier if(*s2 == 'W'){
8467c881178SDavid du Colombier f->magvar = -magvar;
8477c881178SDavid du Colombier return 1;
8487c881178SDavid du Colombier }
8497c881178SDavid du Colombier if(*s2 == 'E'){
8507c881178SDavid du Colombier f->magvar = magvar;
8517c881178SDavid du Colombier return 1;
8527c881178SDavid du Colombier }
8537c881178SDavid du Colombier return 0;
8547c881178SDavid du Colombier }
8557c881178SDavid du Colombier return 0;
8567c881178SDavid du Colombier }
8577c881178SDavid du Colombier
8587c881178SDavid du Colombier void
putline(char * s)8597c881178SDavid du Colombier putline(char *s){
8607c881178SDavid du Colombier write(ttyfd, s, strlen(s));
8617c881178SDavid du Colombier write(ttyfd, "\r\n", 2);
8627c881178SDavid du Colombier }
8637c881178SDavid du Colombier
8647c881178SDavid du Colombier int
type(char * s)8657c881178SDavid du Colombier type(char *s){
8667c881178SDavid du Colombier int i;
8677c881178SDavid du Colombier
8687c881178SDavid du Colombier for(i = 0; i < nelem(gpsmsg); i++){
8697c881178SDavid du Colombier if(strcmp(s, gpsmsg[i].name) == 0) return i;
8707c881178SDavid du Colombier }
8717c881178SDavid du Colombier return -1;
8727c881178SDavid du Colombier }
8737c881178SDavid du Colombier
8747c881178SDavid du Colombier void
setline(void)8757c881178SDavid du Colombier setline(void){
8767c881178SDavid du Colombier char *serialctl;
8777c881178SDavid du Colombier
8787c881178SDavid du Colombier serialctl = smprint("%sctl", serial);
8797c881178SDavid du Colombier if((ttyfd = open(serial, ORDWR)) < 0)
8807c881178SDavid du Colombier sysfatal("%s: %r", serial);
8817c881178SDavid du Colombier if((ctlfd = open(serialctl, OWRITE)) >= 0){
8827c881178SDavid du Colombier if(fprint(ctlfd, baudstr, baud) < 0)
8837c881178SDavid du Colombier sysfatal("%s: %r", serialctl);
8847c881178SDavid du Colombier }else
8857c881178SDavid du Colombier gpsplayback = 0x8;
8867c881178SDavid du Colombier free(serialctl);
8877c881178SDavid du Colombier }
8887c881178SDavid du Colombier
getonechar(vlong * t)8897c881178SDavid du Colombier int getonechar(vlong *t){
8907c881178SDavid du Colombier static char buf[32], *p;
8917c881178SDavid du Colombier static int n;
8927c881178SDavid du Colombier
8937c881178SDavid du Colombier if(n == 0){
8947c881178SDavid du Colombier n = read(ttyfd, buf, sizeof(buf));
8957c881178SDavid du Colombier if(t) *t = nsec();
8967c881178SDavid du Colombier if(n < 0)
8977c881178SDavid du Colombier sysfatal("%s: %r", serial);
8987c881178SDavid du Colombier if(n == 0)
8997c881178SDavid du Colombier threadexits(nil);
9007c881178SDavid du Colombier /*
9017c881178SDavid du Colombier * We received n characters, so the first must have been there
9027c881178SDavid du Colombier * at least n/(10*baud) seconds (10 is 1 start
9037c881178SDavid du Colombier * bit, one stop bit and 8 data bits per character)
9047c881178SDavid du Colombier */
9057c881178SDavid du Colombier if(t) {
9067c881178SDavid du Colombier *t -= n * nsecperchar;
9077c881178SDavid du Colombier histo[n]++;
9087c881178SDavid du Colombier }
9097c881178SDavid du Colombier p = buf;
9107c881178SDavid du Colombier }
9117c881178SDavid du Colombier n--;
9127c881178SDavid du Colombier return *p++;
9137c881178SDavid du Colombier }
9147c881178SDavid du Colombier
9157c881178SDavid du Colombier void
getline(char * s,int size,vlong * t)9167c881178SDavid du Colombier getline(char *s, int size, vlong *t){
9177c881178SDavid du Colombier uchar c;
9187c881178SDavid du Colombier char *p;
9197c881178SDavid du Colombier int n, cs;
9207c881178SDavid du Colombier
9215e6bdc2cSDavid du Colombier tryagain:
9227c881178SDavid du Colombier for(;;){
9237c881178SDavid du Colombier p = s;
9247c881178SDavid du Colombier n = 0;
9257c881178SDavid du Colombier while((c = getonechar(t)) != '\n' && n < size){
9267c881178SDavid du Colombier t = nil;
9277c881178SDavid du Colombier if(c != '\r'){
9287c881178SDavid du Colombier *p++ = c;
9297c881178SDavid du Colombier n++;
9307c881178SDavid du Colombier }
9317c881178SDavid du Colombier }
9327c881178SDavid du Colombier if(n < size)
9337c881178SDavid du Colombier break;
9347c881178SDavid du Colombier while(getonechar(t) != '\n' && n < 4096)
9357c881178SDavid du Colombier n++;
9367c881178SDavid du Colombier if(n == 4096)
9377c881178SDavid du Colombier sysfatal("preposterous gps line, wrong baud rate?");
9387c881178SDavid du Colombier fprint(2, "ridiculous gps line: %d bytes\n", n);
9397c881178SDavid du Colombier }
9407c881178SDavid du Colombier *p = 0;
9417c881178SDavid du Colombier for(p = s; isdigit(*p); p++)
9427c881178SDavid du Colombier ;
9437c881178SDavid du Colombier if(*p++ == ' ')
9447c881178SDavid du Colombier memmove(s, p, strlen(p)+1);
9457c881178SDavid du Colombier if(s[0] == '$'){
9467c881178SDavid du Colombier if(n > 4 && s[n-3] == '*'){
9477c881178SDavid du Colombier s[n-3] = 0;
9487c881178SDavid du Colombier p = s+1;
9497c881178SDavid du Colombier cs = 0;
9507c881178SDavid du Colombier while(*p) cs ^= *p++;
9517c881178SDavid du Colombier n = strtol(&s[n-2], nil, 16);
9527c881178SDavid du Colombier if(n != cs){
9537c881178SDavid du Colombier if(debug)
9547c881178SDavid du Colombier fprint(2, "Checksum error %s, 0x%x, 0x%x\n",
9557c881178SDavid du Colombier s, n, cs);
9567c881178SDavid du Colombier checksumerrors++;
9575e6bdc2cSDavid du Colombier goto tryagain;
9587c881178SDavid du Colombier }
9597c881178SDavid du Colombier }
9607c881178SDavid du Colombier }
9617c881178SDavid du Colombier for(p = s; *p; rawin++)
9627c881178SDavid du Colombier raw[rawin & Rawmask] = *p++;
9637c881178SDavid du Colombier raw[rawin & Rawmask] = '\n';
9647c881178SDavid du Colombier rawin++;
9657c881178SDavid du Colombier }
966