📄 gpsfs.c
字号:
#include <u.h>#include <libc.h>#include <fcall.h>#include <thread.h>#include <ctype.h>#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*);GPSfile files[] = { { "time", readtime, 0444, 0 }, { "position", readposn, 0444, 0 }, { "satellites", readsats, 0444, 0 }, { "stats", readstats, 0444, 0 }, { "raw", readraw, DMEXCL|0444, 0 },};Srv s = { .open = ropen, .read = rread, .end = rend,};File *root;File *gpsdir;voidrend(Srv *){ sysfatal("gpsfs demised");}voidropen(Req *r){ respond(r, nil);}voidrread(Req *r){ GPSfile *f; r->ofcall.count = 0; f = r->fid->file->aux; respond(r, f->rread(r));}voidfsinit(void){ char* user; 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++) if(createfile(gpsdir, files[i].name, user, files[i].mode, files + i) == nil) sysfatal("fsinit: createfile: %s: %r", files[i].name);}voidthreadmain(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); rfork(RFNOTEG); fsinit(); gpsinit(); threadpostmountsrv(&s, srvname, mntpt, MBEFORE); threadexits(nil);}static voidgpstrack(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); } }}voidgpsinit(void){ proccreate(gpstrack, nil, 4096);}voidprintfix(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];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -