gps/ 775 0 0 0 10453407457 113305ustar00rminnichrminnichgps/dat.h 664 0 0 437 10402266255 12226ustar00rminnichrminnichtypedef struct Place Place; struct Place { double lon; double lat; }; #pragma varargck type "L" Place enum { Undef = 0x80000000, Baud= 4800, }; extern Place nowhere; extern int debug; int placeconv(Fmt*); Place strtopos(char*, char**); int strtolatlon(char*, char**, Place*); gps/gpsevermore.c 664 0 0 10625 10402266256 14050ustar00rminnichrminnich#include #include #include "dat.h" char *serial = "/dev/eia0"; int ttyfd, ctlfd, debug; int baud = Baud; char *baudstr = "b%dd1r1pns1l8i1w5"; Place where = {-(74.0 + 23.9191/60.0), 40.0 + 41.1346/60.0}; void setline(void); void evermore80(Place, int); void evermore89(int); void evermore8e(void); void setline(void){ char *serialctl; serialctl = smprint("%sctl", serial); if((ttyfd = open(serial, ORDWR)) < 0) sysfatal("%s: %r", serial); if((ctlfd = open(serialctl, OWRITE)) >= 0){ if(fprint(ctlfd, baudstr, baud) < 0) sysfatal("%s: %r", serialctl); } free(serialctl); } enum { GGAon = 0x01, GLLon = 0x02, GSAon = 0x04, GSVon = 0x08, RMCon = 0x10, VTGon = 0x20, CRCon = 0x40, EMTon = 0x80 }; char* putbyte(char *s, int v) { *s++ = v; if((v & 0xff) == 0x10) *s++ = v; return s; } char* putshort(char *s, int v) { s = putbyte(s, v); s = putbyte(s, v >> 8); return s; } char* putlong(char *s, long v) { s = putbyte(s, v); s = putbyte(s, v >> 8); s = putbyte(s, v >> 16); s = putbyte(s, v >> 24); return s; } void evermoresend(char *body, int l) { char buf[8], *s; int crc, i; s = buf; *s++ = 0x10; /* DCE */ *s++ = 0x02; /* STX */ s = putbyte(s, l); /* length */ write(ttyfd, buf, s-buf); /* write header */ write(ttyfd, body, l); /* write body */ crc = 0; for(i = 0; i < l; i++) crc += body[i]; /* calculate crc */ s = buf; s = putbyte(s, crc); /* checksum */ *s++ = 0x10; /* DCE */ *s++ = 0x03; /* ETX */ write(ttyfd, buf, s-buf); /* write trailer */ } void evermore80(Place pl, int baud) { char buf[32], *s; long now, seconds, week; fprint(2, "Evermore80"); time(&now); seconds = now - 315964800; week = (seconds / (7*24*3600)); seconds = seconds % (7*24*3600); s = buf; s = putbyte(s, 0x80); /* message ID */ s = putshort(s, week); /* week number */ s = putlong(s, seconds*100); /* seconds */ s = putshort(s, pl.lat*10.0); /* latitude tenths degree */ s = putshort(s, pl.lon*10.0); /* longitude tenths degree */ s = putshort(s, 100); /* altitude meters */ s = putshort(s, 0); /* datumn ID */ s = putbyte(s, 2); /* warm start */ s = putbyte(s, GGAon|GSAon|GSVon|RMCon|CRCon); switch(baud){ case 4800: s = putbyte(s, 0); break; case 9600: s = putbyte(s, 1); break; case 19200: s = putbyte(s, 2); break; case 38400: s = putbyte(s, 3); break; default: sysfatal("Illegal baud rate"); } evermoresend(buf, s - buf); fprint(2, "\n"); } void evermore89(int baud) { char buf[32], *s; fprint(2, "Evermore89"); s = buf; s = putbyte(s, 0x89); /* message ID */ s = putbyte(s, 0x01); /* set main serial port */ switch(baud){ case 4800: s = putbyte(s, 0x00); break; case 9600: s = putbyte(s, 0x01); break; case 19200: s = putbyte(s, 0x02); break; case 38400: s = putbyte(s, 0x03); break; default: sysfatal("illegal baud rate %d\n", baud); } evermoresend(buf, s - buf); fprint(2, "\n"); } void evermore8e(void) { char buf[32], *s; fprint(2, "Evermore8e"); s = buf; s = putbyte(s, 0x8e); /* message ID */ s = putbyte(s, GGAon|GSAon|GSVon|RMCon); /* all messages except GLL and VTG */ s = putbyte(s, 0x01); /* checksum on */ s = putbyte(s, 0x01); /* GGA update rate */ s = putbyte(s, 0x0b); /* GLL update rate */ s = putbyte(s, 0x0a); /* GSA update rate */ s = putbyte(s, 0x14); /* GSV update rate */ s = putbyte(s, 0x08); /* RMC update rate */ s = putbyte(s, 0x0d); /* VTG update rate */ evermoresend(buf, s - buf); fprint(2, "\n"); } void main(int argc, char*argv[]) { char *p; Place pl; int newbaud; newbaud = -1; pl = nowhere; ARGBEGIN { default: fprint(2, "usage: %s [-b baud] [-d device] [-l longitude latitude] [-n newbaud]\n", argv0); exits("usage"); case 'D': debug++; break; case 'b': baud = strtol(ARGF(), nil, 0); break; case 'd': serial = ARGF(); break; case 'l': p = ARGF(); if(strtolatlon(p, &p, &pl) < 0) sysfatal("bad position"); while(*p == ' ' || *p == '\t' || *p == '\n') p++; if(*p == '\0') p = ARGF(); if (strtolatlon(p, &p, &pl) < 0) sysfatal("bad position"); while(*p == ' ' || *p == '\t' || *p == '\n') p++; if(*p != '\0') sysfatal("trailing gunk in position"); where = pl; break; case 'n': newbaud = strtol(ARGF(), nil, 0); break; } ARGEND if(newbaud < 0) newbaud = baud; fmtinstall('L', placeconv); print("Initializing GPS to %d baud, at %L, time %s\n", newbaud, where, ctime(time(nil))); setline(); evermore80(where, newbaud); } gps/gpsfs.c 664 0 0 44754 10416235534 12646ustar00rminnichrminnich#include #include #include #include #include #include <9p.h> #include "dat.h" enum { Numsize= 12, Vlnumsize= 22, Rawbuf= 0x10000, Rawmask= Rawbuf-1, }; #define nsecperchar ((int)(1000000000.0 * 10.0 / baud)) typedef struct Fix Fix; typedef struct Satellite Satellite; typedef struct GPSfile GPSfile; typedef struct Gpsmsg Gpsmsg; struct Satellite { int prn; int elevation; int azimuth; int snr; }; struct Fix { int messages; /* bitmap of types seen */ Place; /* * The following are in Plan 9 time format: * seconds or nanoseconds since the epoch. */ vlong localtime; /* nsec() value when first byte was read */ vlong gpstime; /* nsec() value from GPS */ long time; /* time() value from GPS */ double zulu; int date; char valid; uchar quality; ushort satellites; double pdop; double hdop; double vdop; double altitude; double sealevel; double groundspeed; double kmh; double course; double heading; double magvar; Satellite s[12]; }; struct GPSfile { char *name; char* (*rread)(Req*); int mode; vlong offset; /* for raw: rawout - read-offset */ }; enum { ASTRAL, GPGGA, GPGLL, GPGSA, GPGSV, GPRMC, GPVTG, PRWIRID, PRWIZCH }; struct Gpsmsg { char *name; int tokens; ulong errors; }; char raw[Rawbuf]; vlong rawin; vlong rawout; ulong badlat, goodlat, suspectlat; ulong badlon, goodlon, suspectlon; ulong suspecttime, goodtime; ulong histo[32]; char *serial = "/dev/eia0"; Gpsmsg gpsmsg[] = { [ASTRAL] = { "ASTRAL", 0, 0}, [GPGGA] = { "$GPGGA", 15, 0}, [GPGLL] = { "$GPGLL", 7, 0}, [GPGSA] = { "$GPGSA", 18, 0}, [GPGSV] = { "$GPGSV", 0, 0}, [GPRMC] = { "$GPRMC", 0, 0}, [GPVTG] = { "$GPVTG", 0, 0}, [PRWIRID] = { "$PRWIRID", 0, 0}, [PRWIZCH] = { "$PRWIZCH", 0, 0}, }; int ttyfd, ctlfd, debug; int setrtc; int baud = Baud; char *baudstr = "b%dd1r1pns1l8i9"; ulong seconds; ulong starttime; ulong checksumerrors; int gpsplayback; /* If set, return times and positions with `invalid' marker set */ Place where = {-(74.0 + 23.9191/60.0), 40.0 + 41.1346/60.0}; Fix curfix; Lock fixlock; int type(char*); void setline(void); int getonechar(vlong*); void getline(char*, int, vlong*); void putline(char*); int gettime(Fix*); int getzulu(char *, Fix*); int getalt(char*, char*, Fix*); int getsea(char*, char*, Fix*); int getlat(char*, char*, Fix*); int getlon(char*, char*, Fix*); int getgs(char*, Fix *); int getkmh(char*, Fix*); int getcrs(char*, Fix*); int gethdg(char*, Fix*); int getdate(char*, Fix*); int getmagvar(char*, char*, Fix*); void printfix(int, Fix*); void ropen(Req *r); void rread(Req *r); void rend(Srv *s); void gpsinit(void); char* readposn(Req*); char* readtime(Req*); char* readsats(Req*); char* readstats(Req*); char* readraw(Req*); char* readxml(Req*); GPSfile files[] = { { "time", readtime, 0444, 0 }, { "position", readposn, 0444, 0 }, { "satellites", readsats, 0444, 0 }, { "stats", readstats, 0444, 0 }, { "raw", readraw, DMEXCL|0444, 0 }, { "gps.xml", readxml, 0444, 0 }, { "gps.html", readxml, 0444, 0 },}; Srv s = { .open = ropen, .read = rread, .end = rend, }; File *root; File *gpsdir; char *idname = "NO sysname"; void rend(Srv *) { sysfatal("gpsfs demised"); } void ropen(Req *r) { respond(r, nil); } void rread(Req *r) { GPSfile *f; r->ofcall.count = 0; f = r->fid->file->aux; respond(r, f->rread(r)); } File *xmlfile = nil; void fsinit(void) { int formatxml(void); char* user; File *f; int i; user = getuser(); s.tree = alloctree(user, user, 0555, nil); if(s.tree == nil) sysfatal("fsinit: alloctree: %r"); root = s.tree->root; if((gpsdir = createfile(root, "gps", user, DMDIR|0555, nil)) == nil) sysfatal("fsinit: createfile: gps: %r"); for(i = 0; i < nelem(files); i++){ f = createfile(gpsdir, files[i].name, user, files[i].mode, files + i); if(f == nil) sysfatal("fsinit: createfile: %s: %r", files[i].name); if (i > 4) f->length = formatxml(); if (i == 5) xmlfile = f; } } void threadmain(int argc, char*argv[]) { char *srvname, *mntpt; srvname = "gps"; mntpt = "/mnt"; ARGBEGIN { default: fprint(2, "usage: %s [-b baud] [-d device] [-l logfile] [-m mntpt] [-r] [-s postname]\n", argv0); exits("usage"); case 'D': debug++; break; case 'b': baud = strtol(ARGF(), nil, 0); break; case 'd': serial = ARGF(); break; case 'r': setrtc = 1; break; case 's': srvname = ARGF(); break; case 'm': mntpt = ARGF(); break; } ARGEND fmtinstall('L', placeconv); idname = sysname(); rfork(RFNOTEG); fsinit(); gpsinit(); threadpostmountsrv(&s, srvname, mntpt, MBEFORE); threadexits(nil); } static void gpstrack(void *) { Fix fix; static char buf[256], *t[32]; int n, i, k, tp; vlong localtime; double d; setline(); fix.messages = 0; fix.lon = 181.0; fix.lat = 91.0; fix.zulu = 0; fix.date = 0; fix.valid = 0; fix.quality = 0; fix.satellites = 0; fix.pdop = 0.0; fix.hdop = 0.0; fix.vdop = 0.0; fix.altitude = 0.0; fix.sealevel = 0.0; fix.groundspeed = 0.0; fix.kmh = 0.0; fix.course = 0.0; fix.heading = 0.0; fix.magvar = 0.0; for(;;){ getline(buf, sizeof buf, &localtime); n = getfields(buf, t, nelem(t), 0,",\r\n"); if(n == 0) continue; tp = type(t[0]); if(tp >= 0 && tp < nelem(gpsmsg) && gpsmsg[tp].tokens && gpsmsg[tp].tokens != n){ gpsmsg[tp].errors++; if(debug) fprint(2, "%s: Expect %d tokens, got %d\n", gpsmsg[tp].name, gpsmsg[tp].tokens, n); continue; } switch(tp){ case ASTRAL: putline("$IIGPQ,ASTRAL*73"); putline("$PRWIILOG,GGA,A,T,10,0"); putline("$PRWIILOG,RMC,A,T,10,0"); putline("$PRWIILOG,GSA,A,T,10,0"); putline("$PRWIILOG,GSV,V,,,"); fprint(2, "Reply: %s\n", "$IIGPQ,ASTRAL*73"); break; case PRWIRID: case PRWIZCH: for(i = 0; i < n; i++) fprint(2, "%s,", t[i]); fprint(2, "(%d tokens)\n", n); break; case GPGGA: if(getlat(t[2], t[3], &fix)) break; if(getlon(t[4], t[5], &fix)) break; getzulu(t[1], &fix); if(fix.date && gettime(&fix)) break; if(isdigit(*t[7])) fix.satellites = strtol(t[7], nil, 10); if(isdigit(*t[8])){ d = strtod(t[8], nil); if(!isNaN(d)) fix.hdop = d; } getalt(t[9], t[10], &fix); getsea(t[11], t[12], &fix); fix.localtime = localtime; fix.quality = strtol(t[6], nil, 10); fix.messages |= 1 << tp; break; case GPRMC: fix.valid = *t[2]; getgs(t[7], &fix); getcrs(t[8], &fix); getdate(t[9], &fix); getmagvar(t[10], t[11], &fix); if((fix.messages & (1 << GPGGA)) == 0){ if(getlat(t[3], t[4], &fix)) break; if(getlon(t[5], t[6], &fix)) break; fix.localtime = localtime; getzulu(t[1], &fix); if(fix.date) gettime(&fix); } fix.messages |= 1 << tp; break; case GPGSA: if(*t[15]){ d = strtod(t[15], nil); if(!isNaN(d)) fix.pdop = d; } if(*t[16]){ d = strtod(t[16], nil); if(!isNaN(d)) fix.hdop = d; } if(*t[17]){ d = strtod(t[17], nil); if(!isNaN(d)) fix.vdop = d; } fix.messages |= 1 << tp; break; case GPGLL: if(getlat(t[1], t[2], &fix)) break; if(getlon(t[3], t[4], &fix)) break; getzulu(t[5], &fix); fix.messages |= 1 << tp; break; case GPGSV: if(n < 8){ gpsmsg[tp].errors++; if(debug) fprint(2, "%s: Expect at least 8 tokens, got %d\n", gpsmsg[tp].name, n); break; } i = 4*(strtol(t[2], nil, 10)-1); /* starting entry in satellite table */ fix.satellites = strtol(t[3], nil, 10); k = 4; while(i < nelem(fix.s) && k + 3 < n){ fix.s[i].prn = strtol(t[k++], nil, 10); fix.s[i].elevation = strtol(t[k++], nil, 10); fix.s[i].azimuth = strtol(t[k++], nil, 10); fix.s[i].snr = strtol(t[k++], nil, 10); k += 4; i++; } fix.messages |= 1 << tp; break; case GPVTG: if(n < 8){ gpsmsg[tp].errors++; if(debug) fprint(2, "%s: Expect at least 8 tokens, got %d\n", gpsmsg[tp].name, n); break; } getcrs(t[2], &fix); gethdg(t[4], &fix); getgs(t[6], &fix); if(n > 8) getkmh(t[8], &fix); fix.messages |= 1 << tp; break; default: if(debug && fix.date) fprint(2, "Don't know %s\n", t[0]); break; } if(fix.valid){ seconds++; lock(&fixlock); memmove(&curfix, &fix, sizeof fix); unlock(&fixlock); if(debug) printfix(2, &fix); fix.valid = 0; fix.messages = 0; for(i = 0; i < nelem(fix.s); i++) fix.s[i].prn = 0; if(gpsplayback) sleep(100); } } } void gpsinit(void) { proccreate(gpstrack, nil, 4096); } void printfix(int f, Fix *fix){ int i; fprint(f, "%L, ", fix->Place); fprint(f, "%g, ", fix->magvar); fprint(f, "%gm - %gm = %gm, ", fix->altitude, fix->sealevel, fix->altitude - fix->sealevel); fprint(f, "%06dZ(%g)-", (int)fix->zulu, fix->zulu); fprint(f, "%06d\n", fix->date); if(fix->lat >= 0) fprint(f, "%11.8fN, ", fix->lat); else fprint(f, "%11.8fS, ", -fix->lat); if(fix->lon >= 0) fprint(f, "%12.8fE, ", fix->lon); else fprint(f, "%12.8fW, ", -fix->lon); fprint(f, "%g@%g, ", fix->course, fix->groundspeed); fprint(f, "(%c, %ds)\n", fix->valid, fix->satellites); for(i = 0; i < nelem(fix->s); i++){ if(fix->s[i].prn == 0) continue; fprint(f, "[%d, %d°, %d°, %d]\n", fix->s[i].prn, fix->s[i].elevation, fix->s[i].azimuth, fix->s[i].snr); } } char* readposn(Req *r) { Fix f; char buf[256]; lock(&fixlock); memmove(&f, &curfix, sizeof f); unlock(&fixlock); snprint(buf, sizeof buf, "%x %06dZ %lud %g %g %g %g %g %g", gpsplayback|f.quality, (int)f.zulu, f.time, f.lon, f.lat, f.altitude - f.sealevel, f.course, f.groundspeed, f.magvar); readstr(r, buf); return nil; } char* readtime(Req *r) { Fix f; char buf[Numsize+Vlnumsize+Vlnumsize+8]; lock(&fixlock); memmove(&f, &curfix, sizeof f); unlock(&fixlock); seprint(buf, buf + sizeof buf, "%*.0lud %*.0llud %*.0llud %c", Numsize-1, f.time, Vlnumsize-1, f.gpstime, Vlnumsize-1, f.localtime, f.valid + (gpsplayback?1:0)); readstr(r, buf); return nil; } char* readstats(Req *r) { int i; char buf[1024], *p; p = buf; p = seprint(p, buf + sizeof buf, "%lld bytes read, %ld samples processed in %ld seconds\n", rawin, seconds, curfix.time - starttime); p = seprint(p, buf + sizeof buf, "%lud checksum errors\n", checksumerrors); p = seprint(p, buf + sizeof buf, "format errors:"); for(i = 0; i < nelem(gpsmsg); i++){ p = seprint(p, buf + sizeof buf, "[%s]: %ld, ", gpsmsg[i].name, gpsmsg[i].errors); } p = seprint(p, buf + sizeof buf, "\nhistogram of # bytes received per buffer:\n"); for(i = 0; i < nelem(histo); i++){ p = seprint(p, buf + sizeof buf, "[%d]: %ld ", i, histo[i]); } p = seprint(p, buf + sizeof buf, "\n"); p = seprint(p, buf + sizeof buf, "bad/good/suspect lat: %lud/%lud/%lud\n", badlat, goodlat, suspectlat); p = seprint(p, buf + sizeof buf, "bad/good/suspect lon: %lud/%lud/%lud\n", badlon, goodlon, suspectlon); p = seprint(p, buf + sizeof buf, "good/suspect time: %lud/%lud\n", goodtime, suspecttime); USED(p); readstr(r, buf); return nil; } char xmlbuf[1024]; int formatxml(void) { Fix f; char *p; lock(&fixlock); memmove(&f, &curfix, sizeof f); unlock(&fixlock); p = xmlbuf; p = seprint(p, xmlbuf+sizeof xmlbuf, ""); p = seprint(p, xmlbuf + sizeof xmlbuf, "", (int)f.zulu, f.lon, f.lat, f.course, f.groundspeed); p = seprint(p,xmlbuf+sizeof xmlbuf,""); return strlen(xmlbuf); } char * readxml(Req *r) { xmlfile->length = formatxml(); xmlfile->mtime = time(0); readstr(r, xmlbuf); return nil; } char* readsats(Req *r) { Fix f; int i; char buf[1024], *p; lock(&fixlock); memmove(&f, &curfix, sizeof f); unlock(&fixlock); p = seprint(buf, buf + sizeof buf, "%d %d\n", gpsplayback|f.quality, f.satellites); for(i = 0; i < nelem(f.s); i++){ if(f.s[i].prn == 0) continue; p = seprint(p, buf + sizeof buf, "%d %d %d %d\n", f.s[i].prn, f.s[i].elevation, f.s[i].azimuth, f.s[i].snr); } readstr(r, buf); return nil; } char* readraw(Req *r) { int n; GPSfile *f; f = r->fid->file->aux; if(rawin - rawout > Rawbuf){ rawout = rawin - Rawbuf; f->offset = rawout - r->ifcall.offset; } n = Rawbuf - (rawout&Rawmask); if(rawin - rawout < n) n = rawin - rawout; if(r->ifcall.count < n) n = r->ifcall.count; r->ofcall.count = n; if(n > 0){ memmove(r->ofcall.data, raw + (rawout & Rawmask), n); rawout += n; } return nil; } void rtcset(long t) { static int fd; long r; int n; char buf[32]; if(fd <= 0 && (fd = open("#r/rtc", ORDWR)) < 0){ fprint(2, "Can't open #r/rtc: %r\n"); return; } n = read(fd, buf, sizeof buf - 1); if(n <= 0){ fprint(2, "Can't read #r/rtc: %r\n"); return; } buf[n] = '\0'; r = strtol(buf, nil, 0); if(r <= 0){ fprint(2, "ridiculous #r/rtc: %ld\n", r); return; } if(r - t > 1 || t - r > 0){ seek(fd, 0, 0); fprint(fd, "%ld", t); fprint(2, "correcting #r/rtc: %ld → %ld\n", r, t); } seek(fd, 0, 0); } int gettime(Fix *f){ /* Convert zulu time and date to Plan9 time(2) */ Tm tm; int zulu; double d; long t; static int count; zulu = f->zulu; memset(&tm, 0, sizeof tm ); tm.sec = zulu % 100; tm.min = (zulu/100) % 100; tm.hour = zulu / 10000; tm.year = f->date % 100 + 100; /* This'll only work until 2099 */ tm.mon = ((f->date/100) % 100) - 1; tm.mday = f->date / 10000; strcpy(tm.zone, "GMT"); t = tm2sec(&tm); if(f->time && count < 3 && (t - f->time > 10 || t - f->time <= 0)){ count++; suspecttime++; return -1; } goodtime++; f->time = t; count = 0; if(starttime == 0) starttime = t; f->gpstime = 1000000000LL * t + 1000000 * (int)modf(f->zulu, &d); if(setrtc){ if(setrtc == 1 || (t % 300) == 0){ rtcset(t); setrtc++; } } return 0; } int getzulu(char *s, Fix *f){ double d; if(*s == '\0') return 0; if(isdigit(*s)){ d = strtod(s, nil); if(!isNaN(d)) f->zulu = d; return 1; } return 0; } int getdate(char *s, Fix *f){ if(*s == 0) return 0; if(isdigit(*s)){ f->date = strtol(s, nil, 10); return 1; } return 0; } int getgs(char *s, Fix *f){ double d; if(*s == 0) return 0; if(isdigit(*s)){ d = strtod(s, nil); if(!isNaN(d)) f->groundspeed = d; return 1; } return 0; } int getkmh(char *s, Fix *f){ double d; if(*s == 0) return 0; if(isdigit(*s)){ d = strtod(s, nil); if(!isNaN(d)) f->kmh = d; return 1; } return 0; } int getcrs(char *s1, Fix *f){ double d; if(*s1 == 0) return 0; if(isdigit(*s1)){ d = strtod(s1, nil); if(!isNaN(d)) f->course = d; return 1; } return 0; } int gethdg(char *s1, Fix *f){ double d; if(*s1 == 0) return 0; if(isdigit(*s1)){ d = strtod(s1, nil); if(!isNaN(d)) f->heading = d; return 1; } return 0; } int getalt(char *s1, char *s2, Fix *f){ double alt; if(*s1 == 0) return 0; if(isdigit(*s1)){ alt = strtod(s1, nil); if(*s2 == 'M' && !isNaN(alt)){ f->altitude = alt; return 1; } return 0; } return 0; } int getsea(char *s1, char *s2, Fix *f){ double alt; if(*s1 == 0) return 0; if(isdigit(*s1)){ alt = strtod(s1, nil); if(*s2 == 'M'){ f->sealevel = alt; return 1; } return 0; } return 0; } int getlat(char *s1, char *s2, Fix *f){ double lat; static count; if(*s1 == 0 || !isdigit(*s1) || strlen(s1) <= 5){ badlat++; return -1; } lat = strtod(s1+2, nil); if(isNaN(lat)){ badlat++; return -1; } lat /= 60.0; lat += 10*(s1[0] - '0') + s1[1] - '0'; if(lat < 0 || lat > 90.0){ badlat++; return -1; } switch(*s2){ default: badlat++; return -1; case 'S': lat = -lat; case 'N': break; } if(f->lat <= 90.0 && count < 3 && fabs(f->lat - lat) > 10.0){ count++; suspectlat++; return -1; } f->lat = lat; count = 0; goodlat++; return 0; } int getlon(char *s1, char *s2, Fix *f){ double lon; static count; if(*s1 == 0 || ! isdigit(*s1) || strlen(s1) <= 5){ badlon++; return -1; } lon = strtod(s1+3, nil); if(isNaN(lon)){ badlon++; return -1; } lon /= 60.0; lon += 100*(s1[0] - '0') + 10*(s1[1] - '0') + s1[2] - '0'; if(lon < 0 || lon > 180.0){ badlon++; return -1; } switch(*s2){ default: badlon++; return -1; case 'W': lon = -lon; case 'E': break; } if(f->lon <= 180.0 && count < 3 && fabs(f->lon - lon) > 10.0){ count++; suspectlon++; return -1; } f->lon = lon; goodlon++; count = 0; return 0; } int getmagvar(char *s1, char *s2, Fix *f){ double magvar; if(*s1 == 0) return 0; if(isdigit(*s1) && strlen(s1) > 5){ magvar = strtod(s1+3, nil); if(isNaN(magvar)) return 0; magvar /= 60.0; magvar += 100*(s1[0] - '0') + 10*(s1[1] - '0') + s1[2] - '0'; if(*s2 == 'W'){ f->magvar = -magvar; return 1; } if(*s2 == 'E'){ f->magvar = magvar; return 1; } return 0; } return 0; } void putline(char *s){ write(ttyfd, s, strlen(s)); write(ttyfd, "\r\n", 2); } int type(char *s){ int i; for(i = 0; i < nelem(gpsmsg); i++){ if(strcmp(s, gpsmsg[i].name) == 0) return i; } return -1; } void setline(void){ char *serialctl; serialctl = smprint("%sctl", serial); if((ttyfd = open(serial, ORDWR)) < 0) sysfatal("%s: %r", serial); if((ctlfd = open(serialctl, OWRITE)) >= 0){ if(fprint(ctlfd, baudstr, baud) < 0) sysfatal("%s: %r", serialctl); }else gpsplayback = 0x8; free(serialctl); } int getonechar(vlong *t){ static char buf[32], *p; static int n; if(n == 0){ n = read(ttyfd, buf, sizeof(buf)); if(t) *t = nsec(); if(n < 0) sysfatal("%s: %r", serial); if(n == 0) threadexits(nil); /* * We received n characters, so the first must have been there * at least n/(10*baud) seconds (10 is 1 start * bit, one stop bit and 8 data bits per character) */ if(t) { *t -= n * nsecperchar; histo[n]++; } p = buf; } n--; return *p++; } void getline(char *s, int size, vlong *t){ uchar c; char *p; int n, cs; tryagain: for(;;){ p = s; n = 0; while((c = getonechar(t)) != '\n' && n < size){ t = nil; if(c != '\r'){ *p++ = c; n++; } } if(n < size) break; while(getonechar(t) != '\n' && n < 4096) n++; if(n == 4096) sysfatal("preposterous gps line, wrong baud rate?"); fprint(2, "ridiculous gps line: %d bytes\n", n); } *p = 0; for(p = s; isdigit(*p); p++) ; if(*p++ == ' ') memmove(s, p, strlen(p)+1); if(s[0] == '$'){ if(n > 4 && s[n-3] == '*'){ s[n-3] = 0; p = s+1; cs = 0; while(*p) cs ^= *p++; n = strtol(&s[n-2], nil, 16); if(n != cs){ if(debug) fprint(2, "Checksum error %s, 0x%x, 0x%x\n", s, n, cs); checksumerrors++; goto tryagain; } } } for(p = s; *p; rawin++) raw[rawin & Rawmask] = *p++; raw[rawin & Rawmask] = '\n'; rawin++; } , "%g, ", fix->magvagps/mkfile 664 0 0 333 10402266256 12473ustar00rminnichrminnich #include #include "dat.h" Place nowhere = { Undef, Undef }; static void setlat(Place *p, double lat) { p->lat = lat; } static void setlon(Place *p, double lon) { p->lon = lon; } static int printlatlon(char *p, int n, double lat, char po, char ne) { char c; double d; int deg, min, sec; if(lat > 0) c = po; else if(lat < 0){ c = ne; lat = -lat; } else c = ' '; sec = 3600 * modf(lat, &d); deg = d; min = sec/60; sec = sec % 60; return snprint(p, n, "%#3.3d°%#2.2d′%#2.2d″%c", deg, min, sec, c); } int placeconv(Fmt *fp) { char str[256]; int n; Place pl; pl = va_arg(fp->args, Place); n = 0; n += printlatlon(str+n, sizeof(str)-n, pl.lat, 'N', 'S'); n += snprint(str+n, sizeof(str)-n, ", "); printlatlon(str+n, sizeof(str)-n, pl.lon, 'E', 'W'); return fmtstrcpy(fp, str); } int strtolatlon(char *p, char **ep, Place *pl) { double latlon; int neg = 0; while(*p == '0') p++; latlon = strtod(p, &p); if(latlon < 0){ latlon = -latlon; neg = 1; } if(*p == ':'){ p++; while(*p == '0') p++; latlon += strtod(p, &p)/60.0; if(*p == ':'){ p++; while(*p == '0') p++; latlon += strtod(p, &p)/3600.0; } } switch (*p++){ case 'N': case 'n': if(neg) latlon = -latlon; if(pl->lat != Undef) return -1; setlat(pl, latlon); break; case 'S': case 's': if(!neg) latlon = -latlon; if(pl->lat != Undef) return -1; setlat(pl, latlon); break; case 'E': case 'e': if(neg) latlon = -latlon; if(pl->lon != Undef) return -1; setlon(pl, latlon); break; case 'W': case 'w': if(!neg) latlon = -latlon; if(pl->lon != Undef) return -1; setlon(pl, latlon); break; case '\0': case ' ': case '\t': case '\n': p--; if(neg) latlon = -latlon; if(pl->lat == Undef){ setlat(pl, latlon); } else if(pl->lon == Undef){ latlon = -latlon; setlon(pl, latlon); } else return -1; break; default: return -1; } if(ep) *ep = p; return 0; } Place strtopos(char *p, char **ep) { Place pl = nowhere; if(strtolatlon(p, &p, &pl) < 0) return nowhere; while(*p == ' ' || *p == '\t' || *p == '\n') p++; if(strtolatlon(p, &p, &pl) < 0) return nowhere; if(ep) *ep = p; return pl; } static void rtcset(long t) /* We may use this some day */ { static int fd; long r; int n; char buf[32]; if(fd <= 0 && (fd = open("#r/rtc", ORDWR)) < 0){ fprint(2, "Can't open #r/rtc: %r\n"); return; } n = read(fd, buf, sizeof buf - 1); if(n <= 0){ fprint(2, "Can't read #r/rtc: %r\n"); return; } buf[n] = '\0'; r = strtol(buf, nil, 0); if(r <= 0){ fprint(2, "ridiculous #r/rtc: %ld\n", r); return; } if(r - t > 1 || t - r > 0){ seek(fd, 0, 0); fprint(fd, "%ld", t); fprint(2, "correcting #r/rtc: %ld → %ld\n", r, t); } seek(fd, 0, 0); } ld\n", r); return; } if(r - t > 1 || t - r > 0){ seek(fd, 0, 0); fprint(fd, "%ld", t); fprint(2, "correcting #r/rtc: %ld → %ld\n", r, t); } seek(fd, 0, 0); } int gettime(Fix *f){ /* Convert zulu time and date to Plan9 time(2) */ Tm tm; int zulu; double d; l