gpsfs.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <fcall.h>
  4. #include <thread.h>
  5. #include <ctype.h>
  6. #include <9p.h>
  7. #include "dat.h"
  8. enum
  9. {
  10. Numsize= 12,
  11. Vlnumsize= 22,
  12. Rawbuf= 0x10000,
  13. Rawmask= Rawbuf-1,
  14. };
  15. #define nsecperchar ((int)(1000000000.0 * 10.0 / baud))
  16. typedef struct Fix Fix;
  17. typedef struct Satellite Satellite;
  18. typedef struct GPSfile GPSfile;
  19. typedef struct Gpsmsg Gpsmsg;
  20. struct Satellite {
  21. int prn;
  22. int elevation;
  23. int azimuth;
  24. int snr;
  25. };
  26. struct Fix {
  27. int messages; /* bitmap of types seen */
  28. Place;
  29. /*
  30. * The following are in Plan 9 time format:
  31. * seconds or nanoseconds since the epoch.
  32. */
  33. vlong localtime; /* nsec() value when first byte was read */
  34. vlong gpstime; /* nsec() value from GPS */
  35. long time; /* time() value from GPS */
  36. double zulu;
  37. int date;
  38. char valid;
  39. uchar quality;
  40. ushort satellites;
  41. double pdop;
  42. double hdop;
  43. double vdop;
  44. double altitude;
  45. double sealevel;
  46. double groundspeed;
  47. double kmh;
  48. double course;
  49. double heading;
  50. double magvar;
  51. Satellite s[12];
  52. };
  53. struct GPSfile {
  54. char *name;
  55. char* (*rread)(Req*);
  56. int mode;
  57. vlong offset; /* for raw: rawout - read-offset */
  58. };
  59. enum {
  60. ASTRAL,
  61. GPGGA,
  62. GPGLL,
  63. GPGSA,
  64. GPGSV,
  65. GPRMC,
  66. GPVTG,
  67. PRWIRID,
  68. PRWIZCH
  69. };
  70. struct Gpsmsg {
  71. char *name;
  72. int tokens;
  73. ulong errors;
  74. };
  75. char raw[Rawbuf];
  76. vlong rawin;
  77. vlong rawout;
  78. ulong histo[32];
  79. char *serial = "/dev/eia0";
  80. Gpsmsg gpsmsg[] = {
  81. [ASTRAL] = { "ASTRAL", 0, 0},
  82. [GPGGA] = { "$GPGGA", 15, 0},
  83. [GPGLL] = { "$GPGLL", 7, 0},
  84. [GPGSA] = { "$GPGSA", 18, 0},
  85. [GPGSV] = { "$GPGSV", 0, 0},
  86. [GPRMC] = { "$GPRMC", 0, 0},
  87. [GPVTG] = { "$GPVTG", 0, 0},
  88. [PRWIRID] = { "$PRWIRID", 0, 0},
  89. [PRWIZCH] = { "$PRWIZCH", 0, 0},
  90. };
  91. int ttyfd, ctlfd, debug;
  92. int setrtc;
  93. int baud = Baud;
  94. char *baudstr = "b%dd1r1pns1l8i9w5";
  95. ulong seconds;
  96. ulong starttime;
  97. ulong checksumerrors;
  98. int gpsplayback; /* If set, return times and positions with `invalid' marker set */
  99. Place where = {-(74.0 + 23.9191/60.0), 40.0 + 41.1346/60.0};
  100. Fix curfix;
  101. Lock fixlock;
  102. int type(char*);
  103. void setline(void);
  104. int getonechar(vlong*);
  105. void getline(char*, int, vlong*);
  106. void putline(char*);
  107. void gettime(Fix*);
  108. int getzulu(char *, Fix*);
  109. int getalt(char*, char*, Fix*);
  110. int getsea(char*, char*, Fix*);
  111. int getlat(char*, char*, Fix*);
  112. int getlon(char*, char*, Fix*);
  113. int getgs(char*, Fix *);
  114. int getkmh(char*, Fix*);
  115. int getcrs(char*, Fix*);
  116. int gethdg(char*, Fix*);
  117. int getdate(char*, Fix*);
  118. int getmagvar(char*, char*, Fix*);
  119. void printfix(int, Fix*);
  120. void ropen(Req *r);
  121. void rread(Req *r);
  122. void rend(Srv *s);
  123. void gpsinit(void);
  124. char* readposn(Req*);
  125. char* readtime(Req*);
  126. char* readsats(Req*);
  127. char* readstats(Req*);
  128. char* readraw(Req*);
  129. GPSfile files[] = {
  130. { "time", readtime, 0444, 0 },
  131. { "position", readposn, 0444, 0 },
  132. { "satellites", readsats, 0444, 0 },
  133. { "stats", readstats, 0444, 0 },
  134. { "raw", readraw, DMEXCL|0444, 0 },
  135. };
  136. Srv s = {
  137. .open = ropen,
  138. .read = rread,
  139. .end = rend,
  140. };
  141. File *root;
  142. File *gpsdir;
  143. void
  144. rend(Srv *)
  145. {
  146. sysfatal("gpsfs demised");
  147. }
  148. void
  149. ropen(Req *r)
  150. {
  151. respond(r, nil);
  152. }
  153. void
  154. rread(Req *r)
  155. {
  156. GPSfile *f;
  157. r->ofcall.count = 0;
  158. f = r->fid->file->aux;
  159. respond(r, f->rread(r));
  160. }
  161. void
  162. fsinit(void)
  163. {
  164. char* user;
  165. int i;
  166. user = getuser();
  167. s.tree = alloctree(user, user, 0555, nil);
  168. if(s.tree == nil)
  169. sysfatal("fsinit: alloctree: %r");
  170. root = s.tree->root;
  171. if((gpsdir = createfile(root, "gps", user, DMDIR|0555, nil)) == nil)
  172. sysfatal("fsinit: createfile: gps: %r");
  173. for(i = 0; i < nelem(files); i++)
  174. if(createfile(gpsdir, files[i].name, user, files[i].mode, files + i) == nil)
  175. sysfatal("fsinit: createfile: %s: %r", files[i].name);
  176. }
  177. void
  178. threadmain(int argc, char*argv[])
  179. {
  180. char *srvname, *mntpt;
  181. srvname = "gps";
  182. mntpt = "/mnt";
  183. ARGBEGIN {
  184. default:
  185. fprint(2, "usage: %s [-b baud] [-d device] [-l logfile] [-m mntpt] [-r] [-s postname]\n", argv0);
  186. exits("usage");
  187. case 'D':
  188. debug++;
  189. break;
  190. case 'b':
  191. baud = strtol(ARGF(), nil, 0);
  192. break;
  193. case 'd':
  194. serial = ARGF();
  195. break;
  196. case 'r':
  197. setrtc = 1;
  198. break;
  199. case 's':
  200. srvname = ARGF();
  201. break;
  202. case 'm':
  203. mntpt = ARGF();
  204. break;
  205. } ARGEND
  206. fmtinstall('L', placeconv);
  207. rfork(RFNOTEG);
  208. fsinit();
  209. gpsinit();
  210. threadpostmountsrv(&s, srvname, mntpt, MBEFORE);
  211. threadexits(nil);
  212. }
  213. static void
  214. gpstrack(void *)
  215. {
  216. Fix fix;
  217. static char buf[256], *t[32];
  218. int n, i, k, tp;
  219. vlong localtime;
  220. setline();
  221. fix.messages = 0;
  222. fix.lon = 0;
  223. fix.lat = 0;
  224. fix.zulu = 0;
  225. fix.date = 0;
  226. fix.valid = 0;
  227. fix.quality = 0;
  228. fix.satellites = 0;
  229. fix.pdop = 0.0;
  230. fix.hdop = 0.0;
  231. fix.vdop = 0.0;
  232. fix.altitude = 0.0;
  233. fix.sealevel = 0.0;
  234. fix.groundspeed = 0.0;
  235. fix.kmh = 0.0;
  236. fix.course = 0.0;
  237. fix.heading = 0.0;
  238. fix.magvar = 0.0;
  239. for(;;){
  240. getline(buf, sizeof buf, &localtime);
  241. n = getfields(buf, t, nelem(t), 0,",\r\n");
  242. if(n == 0)
  243. continue;
  244. tp = type(t[0]);
  245. fix.messages |= 1 << tp;
  246. if(tp >= 0 && tp < nelem(gpsmsg) && gpsmsg[tp].tokens && gpsmsg[tp].tokens != n){
  247. gpsmsg[tp].errors++;
  248. if(debug)
  249. fprint(2, "%s: Expect %d tokens, got %d\n",
  250. gpsmsg[tp].name, gpsmsg[tp].tokens, n);
  251. continue;
  252. }
  253. switch(tp){
  254. case ASTRAL:
  255. putline("$IIGPQ,ASTRAL*73");
  256. putline("$PRWIILOG,GGA,A,T,10,0");
  257. putline("$PRWIILOG,RMC,A,T,10,0");
  258. putline("$PRWIILOG,GSA,A,T,10,0");
  259. putline("$PRWIILOG,GSV,V,,,");
  260. fprint(2, "Reply: %s\n", "$IIGPQ,ASTRAL*73");
  261. break;
  262. case PRWIRID:
  263. case PRWIZCH:
  264. for(i = 0; i < n; i++) fprint(2, "%s,", t[i]);
  265. fprint(2, "(%d tokens)\n", n);
  266. break;
  267. case GPGGA:
  268. fix.localtime = localtime;
  269. fix.quality = strtol(t[6], nil, 10);
  270. getzulu(t[1], &fix);
  271. getlat(t[2], t[3], &fix);
  272. getlon(t[4], t[5], &fix);
  273. if(isdigit(*t[7]))
  274. fix.satellites = strtol(t[7], nil, 10);
  275. if(isdigit(*t[8]))
  276. fix.hdop = strtod(t[8], nil);
  277. getalt(t[9], t[10], &fix);
  278. getsea(t[11], t[12], &fix);
  279. if(fix.date)
  280. gettime(&fix);
  281. break;
  282. case GPRMC:
  283. fix.valid = *t[2];
  284. getgs(t[7], &fix);
  285. getcrs(t[8], &fix);
  286. getdate(t[9], &fix);
  287. getmagvar(t[10], t[11], &fix);
  288. if((fix.messages & (1 << GPGGA)) == 0){
  289. fix.localtime = localtime;
  290. getzulu(t[1], &fix);
  291. getlat(t[3], t[4], &fix);
  292. getlon(t[5], t[6], &fix);
  293. if(fix.date)
  294. gettime(&fix);
  295. }
  296. break;
  297. case GPGSA:
  298. if(*t[15]) fix.pdop = strtod(t[15], nil);
  299. if(*t[16]) fix.hdop = strtod(t[16], nil);
  300. if(*t[17]) fix.vdop = strtod(t[17], nil);
  301. break;
  302. case GPGLL:
  303. getlat(t[1], t[2], &fix);
  304. getlon(t[3], t[4], &fix);
  305. getzulu(t[5], &fix);
  306. break;
  307. case GPGSV:
  308. if(n < 8){
  309. gpsmsg[tp].errors++;
  310. if(debug)
  311. fprint(2, "%s: Expect at least 8 tokens, got %d\n",
  312. gpsmsg[tp].name, n);
  313. break;
  314. }
  315. i = 4*(strtol(t[2], nil, 10)-1); /* starting entry in satellite table */
  316. fix.satellites = strtol(t[3], nil, 10);
  317. k = 4;
  318. while(i < nelem(fix.s) && k + 3 < n){
  319. fix.s[i].prn = strtol(t[k++], nil, 10);
  320. fix.s[i].elevation = strtol(t[k++], nil, 10);
  321. fix.s[i].azimuth = strtol(t[k++], nil, 10);
  322. fix.s[i].snr = strtol(t[k++], nil, 10);
  323. k += 4;
  324. i++;
  325. }
  326. case GPVTG:
  327. if(n < 8){
  328. gpsmsg[tp].errors++;
  329. if(debug)
  330. fprint(2, "%s: Expect at least 8 tokens, got %d\n",
  331. gpsmsg[tp].name, n);
  332. break;
  333. }
  334. getcrs(t[2], &fix);
  335. gethdg(t[4], &fix);
  336. getgs(t[6], &fix);
  337. if(n > 8)
  338. getkmh(t[8], &fix);
  339. break;
  340. default:
  341. if(debug && fix.date)
  342. fprint(2, "Don't know %s\n", t[0]);
  343. break;
  344. }
  345. if(fix.valid){
  346. seconds++;
  347. lock(&fixlock);
  348. memmove(&curfix, &fix, sizeof fix);
  349. unlock(&fixlock);
  350. if(debug)
  351. printfix(2, &fix);
  352. fix.valid = 0;
  353. fix.messages = 0;
  354. for(i = 0; i < nelem(fix.s); i++)
  355. fix.s[i].prn = 0;
  356. if(gpsplayback)
  357. sleep(100);
  358. }
  359. }
  360. }
  361. void
  362. gpsinit(void)
  363. {
  364. proccreate(gpstrack, nil, 4096);
  365. }
  366. void
  367. printfix(int f, Fix *fix){
  368. int i;
  369. fprint(f, "%L, ", fix->Place);
  370. fprint(f, "%g, ", fix->magvar);
  371. fprint(f, "%gm - %gm = %gm, ", fix->altitude, fix->sealevel, fix->altitude - fix->sealevel);
  372. fprint(f, "%06dZ(%g)-", (int)fix->zulu, fix->zulu);
  373. fprint(f, "%06d\n", fix->date);
  374. if(fix->lat >= 0)
  375. fprint(f, "%11.8fN, ", fix->lat);
  376. else
  377. fprint(f, "%11.8fS, ", -fix->lat);
  378. if(fix->lon >= 0)
  379. fprint(f, "%12.8fE, ", fix->lon);
  380. else
  381. fprint(f, "%12.8fW, ", -fix->lon);
  382. fprint(f, "%g@%g, ", fix->course, fix->groundspeed);
  383. fprint(f, "(%c, %ds)\n", fix->valid, fix->satellites);
  384. for(i = 0; i < nelem(fix->s); i++){
  385. if(fix->s[i].prn == 0)
  386. continue;
  387. fprint(f, "[%d, %d°, %d°, %d]\n",
  388. fix->s[i].prn, fix->s[i].elevation, fix->s[i].azimuth, fix->s[i].snr);
  389. }
  390. }
  391. char*
  392. readposn(Req *r)
  393. {
  394. Fix f;
  395. char buf[256];
  396. lock(&fixlock);
  397. memmove(&f, &curfix, sizeof f);
  398. unlock(&fixlock);
  399. snprint(buf, sizeof buf, "%x %06dZ %lud %g %g %g %g %g %g",
  400. gpsplayback|f.quality, (int)f.zulu, f.time, f.lon, f.lat, f.altitude - f.sealevel,
  401. f.course, f.groundspeed, f.magvar);
  402. readstr(r, buf);
  403. return nil;
  404. }
  405. char*
  406. readtime(Req *r)
  407. {
  408. Fix f;
  409. char buf[Numsize+Vlnumsize+Vlnumsize+8];
  410. lock(&fixlock);
  411. memmove(&f, &curfix, sizeof f);
  412. unlock(&fixlock);
  413. seprint(buf, buf + sizeof buf, "%*.0lud %*.0llud %*.0llud %c",
  414. Numsize-1, f.time,
  415. Vlnumsize-1, f.gpstime,
  416. Vlnumsize-1, f.localtime, f.valid + (gpsplayback?1:0));
  417. readstr(r, buf);
  418. return nil;
  419. }
  420. char*
  421. readstats(Req *r)
  422. {
  423. int i;
  424. char buf[1024], *p;
  425. p = buf;
  426. p = seprint(p, buf + sizeof buf, "%lld bytes read, %ld samples processed in %ld seconds\n",
  427. rawin, seconds, curfix.time - starttime);
  428. p = seprint(p, buf + sizeof buf, "%lud checksum errors\n", checksumerrors);
  429. p = seprint(p, buf + sizeof buf, "format errors:");
  430. for(i = 0; i < nelem(gpsmsg); i++){
  431. p = seprint(p, buf + sizeof buf, "[%s]: %ld, ",
  432. gpsmsg[i].name, gpsmsg[i].errors);
  433. }
  434. p = seprint(p, buf + sizeof buf, "\nhistogram of # bytes received per buffer:\n");
  435. for(i = 0; i < nelem(histo); i++){
  436. p = seprint(p, buf + sizeof buf, "[%d]: %ld ",
  437. i, histo[i]);
  438. }
  439. seprint(p, buf + sizeof buf, "\n");
  440. readstr(r, buf);
  441. return nil;
  442. }
  443. char*
  444. readsats(Req *r)
  445. {
  446. Fix f;
  447. int i;
  448. char buf[1024], *p;
  449. lock(&fixlock);
  450. memmove(&f, &curfix, sizeof f);
  451. unlock(&fixlock);
  452. p = seprint(buf, buf + sizeof buf, "%d %d\n", gpsplayback|f.quality, f.satellites);
  453. for(i = 0; i < nelem(f.s); i++){
  454. if(f.s[i].prn == 0)
  455. continue;
  456. p = seprint(p, buf + sizeof buf, "%d %d %d %d\n",
  457. f.s[i].prn, f.s[i].elevation, f.s[i].azimuth, f.s[i].snr);
  458. }
  459. readstr(r, buf);
  460. return nil;
  461. }
  462. char*
  463. readraw(Req *r)
  464. {
  465. int n;
  466. GPSfile *f;
  467. f = r->fid->file->aux;
  468. if(rawin - rawout > Rawbuf){
  469. rawout = rawin - Rawbuf;
  470. f->offset = rawout - r->ifcall.offset;
  471. }
  472. n = Rawbuf - (rawout&Rawmask);
  473. if(rawin - rawout < n)
  474. n = rawin - rawout;
  475. if(r->ifcall.count < n)
  476. n = r->ifcall.count;
  477. r->ofcall.count = n;
  478. if(n > 0){
  479. memmove(r->ofcall.data, raw + (rawout & Rawmask), n);
  480. rawout += n;
  481. }
  482. return nil;
  483. }
  484. void
  485. rtcset(long t)
  486. {
  487. static int fd;
  488. long r;
  489. int n;
  490. char buf[32];
  491. if(fd <= 0 && (fd = open("#r/rtc", ORDWR)) < 0){
  492. fprint(2, "Can't open #r/rtc: %r\n");
  493. return;
  494. }
  495. n = read(fd, buf, sizeof buf - 1);
  496. if(n <= 0){
  497. fprint(2, "Can't read #r/rtc: %r\n");
  498. return;
  499. }
  500. buf[n] = '\0';
  501. r = strtol(buf, nil, 0);
  502. if(r <= 0){
  503. fprint(2, "ridiculous #r/rtc: %ld\n", r);
  504. return;
  505. }
  506. if(r - t > 1 || t - r > 0){
  507. seek(fd, 0, 0);
  508. fprint(fd, "%ld", t);
  509. fprint(2, "correcting #r/rtc: %ld → %ld\n", r, t);
  510. }
  511. seek(fd, 0, 0);
  512. }
  513. void
  514. gettime(Fix *f){
  515. /* Convert zulu time and date to Plan9 time(2) */
  516. Tm tm;
  517. int zulu;
  518. double d;
  519. zulu = f->zulu;
  520. memset(&tm, 0, sizeof tm );
  521. tm.sec = zulu % 100;
  522. tm.min = (zulu/100) % 100;
  523. tm.hour = zulu / 10000;
  524. tm.year = f->date % 100 + 100; /* This'll only work until 2099 */
  525. tm.mon = ((f->date/100) % 100) - 1;
  526. tm.mday = f->date / 10000;
  527. strcpy(tm.zone, "GMT");
  528. f->time = tm2sec(&tm);
  529. if(starttime == 0) starttime = f->time;
  530. f->gpstime = 1000000000LL * f->time + 1000000 * (int)modf(f->zulu, &d);
  531. if(setrtc){
  532. if(setrtc == 1 || (f->time % 300) == 0){
  533. rtcset(f->time);
  534. setrtc++;
  535. }
  536. }
  537. }
  538. int
  539. getzulu(char *s, Fix *f){
  540. if(*s == '\0') return 0;
  541. if(isdigit(*s)){
  542. f->zulu = strtod(s, nil);
  543. return 1;
  544. }
  545. return 0;
  546. }
  547. int
  548. getdate(char *s, Fix *f){
  549. if(*s == 0) return 0;
  550. if(isdigit(*s)){
  551. f->date = strtol(s, nil, 10);
  552. return 1;
  553. }
  554. return 0;
  555. }
  556. int
  557. getgs(char *s1, Fix *f){
  558. if(*s1 == 0) return 0;
  559. if(isdigit(*s1)){
  560. f->groundspeed = strtod(s1, nil);
  561. return 1;
  562. }
  563. return 0;
  564. }
  565. int
  566. getkmh(char *s1, Fix *f){
  567. if(*s1 == 0) return 0;
  568. if(isdigit(*s1)){
  569. f->kmh = strtod(s1, nil);
  570. return 1;
  571. }
  572. return 0;
  573. }
  574. int
  575. getcrs(char *s1, Fix *f){
  576. if(*s1 == 0) return 0;
  577. if(isdigit(*s1)){
  578. f->course = strtod(s1, nil);
  579. return 1;
  580. }
  581. return 0;
  582. }
  583. int
  584. gethdg(char *s1, Fix *f){
  585. if(*s1 == 0) return 0;
  586. if(isdigit(*s1)){
  587. f->heading = strtod(s1, nil);
  588. return 1;
  589. }
  590. return 0;
  591. }
  592. int
  593. getalt(char *s1, char *s2, Fix *f){
  594. double alt;
  595. if(*s1 == 0) return 0;
  596. if(isdigit(*s1)){
  597. alt = strtod(s1, nil);
  598. if(*s2 == 'M'){
  599. f->altitude = alt;
  600. return 1;
  601. }
  602. return 0;
  603. }
  604. return 0;
  605. }
  606. int
  607. getsea(char *s1, char *s2, Fix *f){
  608. double alt;
  609. if(*s1 == 0) return 0;
  610. if(isdigit(*s1)){
  611. alt = strtod(s1, nil);
  612. if(*s2 == 'M'){
  613. f->sealevel = alt;
  614. return 1;
  615. }
  616. return 0;
  617. }
  618. return 0;
  619. }
  620. int
  621. getlat(char *s1, char *s2, Fix *f){
  622. double lat;
  623. if(*s1 == 0) return 0;
  624. if(isdigit(*s1) && strlen(s1) > 5){
  625. lat = strtod(s1+2, nil);
  626. lat /= 60.0;
  627. lat += 10*(s1[0] - '0') + s1[1] - '0';
  628. if(*s2 == 'S'){
  629. f->lat = -lat;
  630. return 1;
  631. }
  632. if(*s2 == 'N'){
  633. f->lat = lat;
  634. return 1;
  635. }
  636. return 0;
  637. }
  638. return 0;
  639. }
  640. int
  641. getlon(char *s1, char *s2, Fix *f){
  642. double lon;
  643. if(*s1 == 0) return 0;
  644. if(isdigit(*s1) && strlen(s1) > 5){
  645. lon = 100*(s1[0] - '0') + 10*(s1[1] - '0') + s1[2] - '0' +
  646. strtod(s1+3, nil)/60.0;
  647. if(*s2 == 'W'){
  648. f->lon = -lon;
  649. return 1;
  650. }
  651. if(*s2 == 'E'){
  652. f->lon = lon;
  653. return 1;
  654. }
  655. return 0;
  656. }
  657. return 0;
  658. }
  659. int
  660. getmagvar(char *s1, char *s2, Fix *f){
  661. double magvar;
  662. if(*s1 == 0) return 0;
  663. if(isdigit(*s1) && strlen(s1) > 5){
  664. magvar = 100*(s1[0] - '0') + 10*(s1[1] - '0') + s1[2] - '0' +
  665. strtod(s1+3, nil)/60.0;
  666. if(*s2 == 'W'){
  667. f->magvar = -magvar;
  668. return 1;
  669. }
  670. if(*s2 == 'E'){
  671. f->magvar = magvar;
  672. return 1;
  673. }
  674. return 0;
  675. }
  676. return 0;
  677. }
  678. void
  679. putline(char *s){
  680. write(ttyfd, s, strlen(s));
  681. write(ttyfd, "\r\n", 2);
  682. }
  683. int
  684. type(char *s){
  685. int i;
  686. for(i = 0; i < nelem(gpsmsg); i++){
  687. if(strcmp(s, gpsmsg[i].name) == 0) return i;
  688. }
  689. return -1;
  690. }
  691. void
  692. setline(void){
  693. char *serialctl;
  694. serialctl = smprint("%sctl", serial);
  695. if((ttyfd = open(serial, ORDWR)) < 0)
  696. sysfatal("%s: %r", serial);
  697. if((ctlfd = open(serialctl, OWRITE)) >= 0){
  698. if(fprint(ctlfd, baudstr, baud) < 0)
  699. sysfatal("%s: %r", serialctl);
  700. }else
  701. gpsplayback = 0x8;
  702. free(serialctl);
  703. }
  704. int getonechar(vlong *t){
  705. static char buf[32], *p;
  706. static int n;
  707. if(n == 0){
  708. n = read(ttyfd, buf, sizeof(buf));
  709. if(t) *t = nsec();
  710. if(n < 0)
  711. sysfatal("%s: %r", serial);
  712. if(n == 0)
  713. threadexits(nil);
  714. /*
  715. * We received n characters, so the first must have been there
  716. * at least n/(10*baud) seconds (10 is 1 start
  717. * bit, one stop bit and 8 data bits per character)
  718. */
  719. if(t) {
  720. *t -= n * nsecperchar;
  721. histo[n]++;
  722. }
  723. p = buf;
  724. }
  725. n--;
  726. return *p++;
  727. }
  728. void
  729. getline(char *s, int size, vlong *t){
  730. uchar c;
  731. char *p;
  732. int n, cs;
  733. for(;;){
  734. p = s;
  735. n = 0;
  736. while((c = getonechar(t)) != '\n' && n < size){
  737. t = nil;
  738. if(c != '\r'){
  739. *p++ = c;
  740. n++;
  741. }
  742. }
  743. if(n < size)
  744. break;
  745. while(getonechar(t) != '\n' && n < 4096)
  746. n++;
  747. if(n == 4096)
  748. sysfatal("preposterous gps line, wrong baud rate?");
  749. fprint(2, "ridiculous gps line: %d bytes\n", n);
  750. }
  751. *p = 0;
  752. for(p = s; isdigit(*p); p++)
  753. ;
  754. if(*p++ == ' ')
  755. memmove(s, p, strlen(p)+1);
  756. if(s[0] == '$'){
  757. if(n > 4 && s[n-3] == '*'){
  758. s[n-3] = 0;
  759. p = s+1;
  760. cs = 0;
  761. while(*p) cs ^= *p++;
  762. n = strtol(&s[n-2], nil, 16);
  763. if(n != cs){
  764. if(debug)
  765. fprint(2, "Checksum error %s, 0x%x, 0x%x\n",
  766. s, n, cs);
  767. checksumerrors++;
  768. }
  769. }
  770. }
  771. for(p = s; *p; rawin++)
  772. raw[rawin & Rawmask] = *p++;
  773. raw[rawin & Rawmask] = '\n';
  774. rawin++;
  775. }