This source file includes following definitions.
- nmeaattach
- nmeaopen
- nmeaclose
- nmeainput
- nmea_scan
- nmea_gprmc
- nmea_date_to_nano
- nmea_time_to_nano
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 #include <sys/param.h>
22 #include <sys/systm.h>
23 #include <sys/queue.h>
24 #include <sys/proc.h>
25 #include <sys/malloc.h>
26 #include <sys/sensors.h>
27 #include <sys/tty.h>
28 #include <sys/conf.h>
29 #include <sys/time.h>
30
31 #ifdef NMEA_DEBUG
32 #define DPRINTFN(n, x) do { if (nmeadebug > (n)) printf x; } while (0)
33 int nmeadebug = 0;
34 #else
35 #define DPRINTFN(n, x)
36 #endif
37 #define DPRINTF(x) DPRINTFN(0, x)
38
39 int nmeaopen(dev_t, struct tty *);
40 int nmeaclose(struct tty *, int);
41 int nmeainput(int, struct tty *);
42 void nmeaattach(int);
43
44 #define NMEAMAX 82
45 #define MAXFLDS 32
46
47 int nmea_count;
48
49 struct nmea {
50 char cbuf[NMEAMAX];
51 struct ksensor time;
52 struct ksensordev timedev;
53 struct timespec ts;
54 struct timespec lts;
55 int64_t gap;
56 #ifdef NMEA_DEBUG
57 int gapno;
58 #endif
59 int64_t last;
60 int sync;
61 int pos;
62 int no_pps;
63 char mode;
64 };
65
66
67 void nmea_scan(struct nmea *, struct tty *);
68 void nmea_gprmc(struct nmea *, struct tty *, char *fld[], int fldcnt);
69
70
71 int nmea_date_to_nano(char *s, int64_t *nano);
72 int nmea_time_to_nano(char *s, int64_t *nano);
73
74 void
75 nmeaattach(int dummy)
76 {
77 }
78
79 int
80 nmeaopen(dev_t dev, struct tty *tp)
81 {
82 struct proc *p = curproc;
83 struct nmea *np;
84 int error;
85
86 if (tp->t_line == NMEADISC)
87 return ENODEV;
88 if ((error = suser(p, 0)) != 0)
89 return error;
90 np = malloc(sizeof(struct nmea), M_DEVBUF, M_WAITOK);
91 bzero(np, sizeof(*np));
92 snprintf(np->timedev.xname, sizeof(np->timedev.xname), "nmea%d",
93 nmea_count++);
94 np->time.status = SENSOR_S_UNKNOWN;
95 np->time.type = SENSOR_TIMEDELTA;
96 np->time.flags = SENSOR_FINVALID;
97 sensor_attach(&np->timedev, &np->time);
98 np->sync = 1;
99 tp->t_sc = (caddr_t)np;
100
101 error = linesw[TTYDISC].l_open(dev, tp);
102 if (error) {
103 free(np, M_DEVBUF);
104 tp->t_sc = NULL;
105 } else
106 sensordev_install(&np->timedev);
107 return error;
108 }
109
110 int
111 nmeaclose(struct tty *tp, int flags)
112 {
113 struct nmea *np = (struct nmea *)tp->t_sc;
114
115 tp->t_line = TTYDISC;
116 sensordev_deinstall(&np->timedev);
117 free(np, M_DEVBUF);
118 tp->t_sc = NULL;
119 nmea_count--;
120 return linesw[TTYDISC].l_close(tp, flags);
121 }
122
123
124 int
125 nmeainput(int c, struct tty *tp)
126 {
127 struct nmea *np = (struct nmea *)tp->t_sc;
128 struct timespec ts;
129 int64_t gap;
130 long tmin, tmax;
131
132 switch (c) {
133 case '$':
134 nanotime(&ts);
135 np->pos = np->sync = 0;
136 gap = (ts.tv_sec * 1000000000LL + ts.tv_nsec) -
137 (np->lts.tv_sec * 1000000000LL + np->lts.tv_nsec);
138
139 np->lts.tv_sec = ts.tv_sec;
140 np->lts.tv_nsec = ts.tv_nsec;
141
142 if (gap <= np->gap)
143 break;
144
145 np->ts.tv_sec = ts.tv_sec;
146 np->ts.tv_nsec = ts.tv_nsec;
147
148 #ifdef NMEA_DEBUG
149 if (nmeadebug > 0) {
150 linesw[TTYDISC].l_rint('[', tp);
151 linesw[TTYDISC].l_rint('0' + np->gapno++, tp);
152 linesw[TTYDISC].l_rint(']', tp);
153 }
154 #endif
155 np->gap = gap;
156
157
158
159
160
161
162
163
164
165 if (tp->t_flags & (TS_TSTAMPDCDSET | TS_TSTAMPDCDCLR |
166 TS_TSTAMPCTSSET | TS_TSTAMPCTSCLR)) {
167 tmax = lmax(np->ts.tv_sec, tp->t_tv.tv_sec);
168 tmin = lmin(np->ts.tv_sec, tp->t_tv.tv_sec);
169 if (tmax - tmin > 1)
170 np->no_pps = 1;
171 else {
172 np->ts.tv_sec = tp->t_tv.tv_sec;
173 np->ts.tv_nsec = tp->t_tv.tv_usec *
174 1000L;
175 np->no_pps = 0;
176 }
177 }
178 break;
179 case '\r':
180 case '\n':
181 if (!np->sync) {
182 np->cbuf[np->pos] = '\0';
183 nmea_scan(np, tp);
184 np->sync = 1;
185 }
186 break;
187 default:
188 if (!np->sync && np->pos < (NMEAMAX - 1))
189 np->cbuf[np->pos++] = c;
190 break;
191 }
192
193 return linesw[TTYDISC].l_rint(c, tp);
194 }
195
196
197 void
198 nmea_scan(struct nmea *np, struct tty *tp)
199 {
200 int fldcnt = 0, cksum = 0, msgcksum, n;
201 char *fld[MAXFLDS], *cs;
202
203
204 fld[fldcnt++] = &np->cbuf[0];
205 for (cs = NULL, n = 0; n < np->pos && cs == NULL; n++) {
206 switch (np->cbuf[n]) {
207 case '*':
208 np->cbuf[n] = '\0';
209 cs = &np->cbuf[n + 1];
210 break;
211 case ',':
212 if (fldcnt < MAXFLDS) {
213 cksum ^= np->cbuf[n];
214 np->cbuf[n] = '\0';
215 fld[fldcnt++] = &np->cbuf[n + 1];
216 } else {
217 DPRINTF(("nr of fields in %s sentence exceeds "
218 "maximum of %d\n", fld[0], MAXFLDS));
219 return;
220 }
221 break;
222 default:
223 cksum ^= np->cbuf[n];
224 }
225 }
226
227
228 if (cs != NULL) {
229 msgcksum = 0;
230 while (*cs) {
231 if ((*cs >= '0' && *cs <= '9') ||
232 (*cs >= 'A' && *cs <= 'F')) {
233 if (msgcksum)
234 msgcksum <<= 4;
235 if (*cs >= '0' && *cs<= '9')
236 msgcksum += *cs - '0';
237 else if (*cs >= 'A' && *cs <= 'F')
238 msgcksum += 10 + *cs - 'A';
239 cs++;
240 } else {
241 DPRINTF(("bad char %c in checksum\n", *cs));
242 return;
243 }
244 }
245 if (msgcksum != cksum) {
246 DPRINTF(("checksum mismatch\n"));
247 return;
248 }
249 }
250
251
252 if (!strcmp(fld[0], "GPRMC"))
253 nmea_gprmc(np, tp, fld, fldcnt);
254 }
255
256
257 void
258 nmea_gprmc(struct nmea *np, struct tty *tp, char *fld[], int fldcnt)
259 {
260 int64_t date_nano, time_nano, nmea_now;
261
262 if (fldcnt != 12 && fldcnt != 13) {
263 DPRINTF(("gprmc: field count mismatch, %d\n", fldcnt));
264 return;
265 }
266 if (nmea_time_to_nano(fld[1], &time_nano)) {
267 DPRINTF(("gprmc: illegal time, %s\n", fld[1]));
268 return;
269 }
270 if (nmea_date_to_nano(fld[9], &date_nano)) {
271 DPRINTF(("gprmc: illegal date, %s\n", fld[9]));
272 return;
273 }
274 nmea_now = date_nano + time_nano;
275 if (nmea_now <= np->last) {
276 DPRINTF(("gprmc: time not monotonically increasing\n"));
277 return;
278 }
279 np->last = nmea_now;
280 np->gap = 0LL;
281 #ifdef NMEA_DEBUG
282 np->gapno = 0;
283 if (nmeadebug > 0) {
284 linesw[TTYDISC].l_rint('[', tp);
285 linesw[TTYDISC].l_rint('C', tp);
286 linesw[TTYDISC].l_rint(']', tp);
287 }
288 #endif
289
290 np->time.value = np->ts.tv_sec * 1000000000LL +
291 np->ts.tv_nsec - nmea_now;
292 np->time.tv.tv_sec = np->ts.tv_sec;
293 np->time.tv.tv_usec = np->ts.tv_nsec / 1000L;
294 if (np->time.status == SENSOR_S_UNKNOWN) {
295 np->time.status = SENSOR_S_OK;
296 np->time.flags &= ~SENSOR_FINVALID;
297 if (fldcnt != 13)
298 strlcpy(np->time.desc, "GPS", sizeof(np->time.desc));
299 }
300 if (fldcnt == 13 && *fld[12] != np->mode) {
301 np->mode = *fld[12];
302 switch (np->mode) {
303 case 'S':
304 strlcpy(np->time.desc, "GPS simulated",
305 sizeof(np->time.desc));
306 break;
307 case 'E':
308 strlcpy(np->time.desc, "GPS estimated",
309 sizeof(np->time.desc));
310 break;
311 case 'A':
312 strlcpy(np->time.desc, "GPS autonomous",
313 sizeof(np->time.desc));
314 break;
315 case 'D':
316 strlcpy(np->time.desc, "GPS differential",
317 sizeof(np->time.desc));
318 break;
319 case 'N':
320 strlcpy(np->time.desc, "GPS not valid",
321 sizeof(np->time.desc));
322 break;
323 default:
324 strlcpy(np->time.desc, "GPS unknown",
325 sizeof(np->time.desc));
326 DPRINTF(("gprmc: unknown mode '%c'\n", np->mode));
327 }
328 }
329 switch (*fld[2]) {
330 case 'A':
331 np->time.status = SENSOR_S_OK;
332 break;
333 case 'V':
334 np->time.status = SENSOR_S_WARN;
335 break;
336 default:
337 DPRINTF(("gprmc: unknown warning indication\n"));
338 }
339
340
341
342
343
344 if (np->no_pps)
345 np->time.status = SENSOR_S_CRIT;
346 }
347
348
349
350
351
352
353 int
354 nmea_date_to_nano(char *s, int64_t *nano)
355 {
356 struct clock_ymdhms ymd;
357 time_t secs;
358 char *p;
359 int n;
360
361
362 for (n = 0, p = s; n < 6 && *p && *p >= '0' && *p <= '9'; n++, p++)
363 ;
364 if (n != 6 || (*p != '\0'))
365 return -1;
366
367 ymd.dt_year = 2000 + (s[4] - '0') * 10 + (s[5] - '0');
368 ymd.dt_mon = (s[2] - '0') * 10 + (s[3] - '0');
369 ymd.dt_day = (s[0] - '0') * 10 + (s[1] - '0');
370 ymd.dt_hour = ymd.dt_min = ymd.dt_sec = 0;
371
372 secs = clock_ymdhms_to_secs(&ymd);
373 *nano = secs * 1000000000LL;
374 return 0;
375 }
376
377
378
379
380
381
382 int
383 nmea_time_to_nano(char *s, int64_t *nano)
384 {
385 long fac = 36000L, div = 6L, secs = 0L, frac = 0L;
386 char ul = '2';
387 int n;
388
389 for (n = 0, secs = 0; fac && *s && *s >= '0' && *s <= ul; s++, n++) {
390 secs += (*s - '0') * fac;
391 div = 16 - div;
392 fac /= div;
393 switch (n) {
394 case 0:
395 if (*s <= '1')
396 ul = '9';
397 else
398 ul = '3';
399 break;
400 case 1:
401 case 3:
402 ul = '5';
403 break;
404 case 2:
405 case 4:
406 ul = '9';
407 break;
408 }
409 }
410 if (fac)
411 return -1;
412
413
414 div = 1L;
415 if (*s == '.') {
416 for (++s; div < 1000000 && *s && *s >= '0' && *s <= '9'; s++) {
417 frac *= 10;
418 frac += (*s - '0');
419 div *= 10;
420 }
421 }
422
423 if (*s != '\0')
424 return -1;
425
426 *nano = secs * 1000000000LL + (int64_t)frac * (1000000000 / div);
427 return 0;
428 }