1 /* 2 * refclock_nmea.c - clock driver for an NMEA GPS CLOCK 3 * Michael Petry Jun 20, 1994 4 * based on refclock_heathn.c 5 */ 6 #ifdef HAVE_CONFIG_H 7 #include <config.h> 8 #endif 9 10 #if defined(SYS_WINNT) 11 #undef close 12 #define close closesocket 13 #endif 14 15 #if defined(REFCLOCK) && defined(CLOCK_NMEA) 16 17 #include "ntpd.h" 18 #include "ntp_io.h" 19 #include "ntp_unixtime.h" 20 #include "ntp_refclock.h" 21 #include "ntp_stdlib.h" 22 23 #include <stdio.h> 24 #include <ctype.h> 25 26 #ifdef HAVE_PPSAPI 27 # ifdef HAVE_TIMEPPS_H 28 # include <timepps.h> 29 # else 30 # ifdef HAVE_SYS_TIMEPPS_H 31 # include <sys/timepps.h> 32 # endif 33 # endif 34 #endif /* HAVE_PPSAPI */ 35 36 /* 37 * This driver supports the NMEA GPS Receiver with 38 * 39 * Protype was refclock_trak.c, Thanks a lot. 40 * 41 * The receiver used spits out the NMEA sentences for boat navigation. 42 * And you thought it was an information superhighway. Try a raging river 43 * filled with rapids and whirlpools that rip away your data and warp time. 44 * 45 * If HAVE_PPSAPI is defined code to use the PPSAPI will be compiled in. 46 * On startup if initialization of the PPSAPI fails, it will fall back 47 * to the "normal" timestamps. 48 * 49 * The PPSAPI part of the driver understands fudge flag2 and flag3. If 50 * flag2 is set, it will use the clear edge of the pulse. If flag3 is 51 * set, kernel hardpps is enabled. 52 * 53 * GPS sentences other than RMC (the default) may be enabled by setting 54 * the relevent bits of 'mode' in the server configuration line 55 * server 127.127.20.x mode X 56 * 57 * bit 0 - enables RMC (1) 58 * bit 1 - enables GGA (2) 59 * bit 2 - enables GLL (4) 60 * multiple sentences may be selected 61 */ 62 63 /* 64 * Definitions 65 */ 66 #ifdef SYS_WINNT 67 # define DEVICE "COM%d:" /* COM 1 - 3 supported */ 68 #else 69 # define DEVICE "/dev/gps%d" /* name of radio device */ 70 #endif 71 #define SPEED232 B4800 /* uart speed (4800 bps) */ 72 #define PRECISION (-9) /* precision assumed (about 2 ms) */ 73 #define PPS_PRECISION (-20) /* precision assumed (about 1 us) */ 74 #define REFID "GPS\0" /* reference id */ 75 #define DESCRIPTION "NMEA GPS Clock" /* who we are */ 76 #define NANOSECOND 1000000000 /* one second (ns) */ 77 #define RANGEGATE 500000 /* range gate (ns) */ 78 79 #define LENNMEA 75 /* min timecode length */ 80 81 /* 82 * Tables to compute the ddd of year form icky dd/mm timecode. Viva la 83 * leap. 84 */ 85 static int day1tab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 86 static int day2tab[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 87 88 /* 89 * Unit control structure 90 */ 91 struct nmeaunit { 92 int pollcnt; /* poll message counter */ 93 int polled; /* Hand in a sample? */ 94 l_fp tstamp; /* timestamp of last poll */ 95 #ifdef HAVE_PPSAPI 96 struct timespec ts; /* last timestamp */ 97 pps_params_t pps_params; /* pps parameters */ 98 pps_info_t pps_info; /* last pps data */ 99 pps_handle_t handle; /* pps handlebars */ 100 #endif /* HAVE_PPSAPI */ 101 }; 102 103 /* 104 * Function prototypes 105 */ 106 static int nmea_start P((int, struct peer *)); 107 static void nmea_shutdown P((int, struct peer *)); 108 #ifdef HAVE_PPSAPI 109 static void nmea_control P((int, struct refclockstat *, struct 110 refclockstat *, struct peer *)); 111 static int nmea_ppsapi P((struct peer *, int, int)); 112 static int nmea_pps P((struct nmeaunit *, l_fp *)); 113 #endif /* HAVE_PPSAPI */ 114 static void nmea_receive P((struct recvbuf *)); 115 static void nmea_poll P((int, struct peer *)); 116 static void gps_send P((int, const char *, struct peer *)); 117 static char *field_parse P((char *, int)); 118 119 /* 120 * Transfer vector 121 */ 122 struct refclock refclock_nmea = { 123 nmea_start, /* start up driver */ 124 nmea_shutdown, /* shut down driver */ 125 nmea_poll, /* transmit poll message */ 126 #ifdef HAVE_PPSAPI 127 nmea_control, /* fudge control */ 128 #else 129 noentry, /* fudge control */ 130 #endif /* HAVE_PPSAPI */ 131 noentry, /* initialize driver */ 132 noentry, /* buginfo */ 133 NOFLAGS /* not used */ 134 }; 135 136 /* 137 * nmea_start - open the GPS devices and initialize data for processing 138 */ 139 static int 140 nmea_start( 141 int unit, 142 struct peer *peer 143 ) 144 { 145 register struct nmeaunit *up; 146 struct refclockproc *pp; 147 int fd; 148 char device[20]; 149 150 /* 151 * Open serial port. Use CLK line discipline, if available. 152 */ 153 (void)sprintf(device, DEVICE, unit); 154 155 fd = refclock_open(device, SPEED232, LDISC_CLK); 156 if (fd < 0) 157 return (0); 158 159 /* 160 * Allocate and initialize unit structure 161 */ 162 up = (struct nmeaunit *)emalloc(sizeof(struct nmeaunit)); 163 if (up == NULL) { 164 (void) close(fd); 165 return (0); 166 } 167 memset((char *)up, 0, sizeof(struct nmeaunit)); 168 pp = peer->procptr; 169 pp->io.clock_recv = nmea_receive; 170 pp->io.srcclock = (caddr_t)peer; 171 pp->io.datalen = 0; 172 pp->io.fd = fd; 173 if (!io_addclock(&pp->io)) { 174 (void) close(fd); 175 free(up); 176 return (0); 177 } 178 pp->unitptr = (caddr_t)up; 179 180 /* 181 * Initialize miscellaneous variables 182 */ 183 peer->precision = PRECISION; 184 pp->clockdesc = DESCRIPTION; 185 memcpy((char *)&pp->refid, REFID, 4); 186 up->pollcnt = 2; 187 gps_send(pp->io.fd,"$PMOTG,RMC,0000*1D\r\n", peer); 188 189 #ifdef HAVE_PPSAPI 190 /* 191 * Start the PPSAPI interface if it is there. Default to use 192 * the assert edge and do not enable the kernel hardpps. 193 */ 194 if (time_pps_create(fd, &up->handle) < 0) { 195 up->handle = 0; 196 msyslog(LOG_ERR, 197 "refclock_nmea: time_pps_create failed: %m"); 198 return (1); 199 } 200 return(nmea_ppsapi(peer, 0, 0)); 201 #else 202 return (1); 203 #endif /* HAVE_PPSAPI */ 204 } 205 206 /* 207 * nmea_shutdown - shut down a GPS clock 208 */ 209 static void 210 nmea_shutdown( 211 int unit, 212 struct peer *peer 213 ) 214 { 215 register struct nmeaunit *up; 216 struct refclockproc *pp; 217 218 pp = peer->procptr; 219 up = (struct nmeaunit *)pp->unitptr; 220 #ifdef HAVE_PPSAPI 221 if (up->handle != 0) 222 time_pps_destroy(up->handle); 223 #endif /* HAVE_PPSAPI */ 224 io_closeclock(&pp->io); 225 free(up); 226 } 227 228 #ifdef HAVE_PPSAPI 229 /* 230 * nmea_control - fudge control 231 */ 232 static void 233 nmea_control( 234 int unit, /* unit (not used */ 235 struct refclockstat *in, /* input parameters (not uded) */ 236 struct refclockstat *out, /* output parameters (not used) */ 237 struct peer *peer /* peer structure pointer */ 238 ) 239 { 240 struct refclockproc *pp; 241 242 pp = peer->procptr; 243 nmea_ppsapi(peer, pp->sloppyclockflag & CLK_FLAG2, 244 pp->sloppyclockflag & CLK_FLAG3); 245 } 246 247 248 /* 249 * Initialize PPSAPI 250 */ 251 int 252 nmea_ppsapi( 253 struct peer *peer, /* peer structure pointer */ 254 int enb_clear, /* clear enable */ 255 int enb_hardpps /* hardpps enable */ 256 ) 257 { 258 struct refclockproc *pp; 259 struct nmeaunit *up; 260 int capability; 261 262 pp = peer->procptr; 263 up = (struct nmeaunit *)pp->unitptr; 264 if (time_pps_getcap(up->handle, &capability) < 0) { 265 msyslog(LOG_ERR, 266 "refclock_nmea: time_pps_getcap failed: %m"); 267 return (0); 268 } 269 memset(&up->pps_params, 0, sizeof(pps_params_t)); 270 if (enb_clear) 271 up->pps_params.mode = capability & PPS_CAPTURECLEAR; 272 else 273 up->pps_params.mode = capability & PPS_CAPTUREASSERT; 274 if (!up->pps_params.mode) { 275 msyslog(LOG_ERR, 276 "refclock_nmea: invalid capture edge %d", 277 !enb_clear); 278 return (0); 279 } 280 up->pps_params.mode |= PPS_TSFMT_TSPEC; 281 if (time_pps_setparams(up->handle, &up->pps_params) < 0) { 282 msyslog(LOG_ERR, 283 "refclock_nmea: time_pps_setparams failed: %m"); 284 return (0); 285 } 286 if (enb_hardpps) { 287 if (time_pps_kcbind(up->handle, PPS_KC_HARDPPS, 288 up->pps_params.mode & ~PPS_TSFMT_TSPEC, 289 PPS_TSFMT_TSPEC) < 0) { 290 msyslog(LOG_ERR, 291 "refclock_nmea: time_pps_kcbind failed: %m"); 292 return (0); 293 } 294 pps_enable = 1; 295 } 296 peer->precision = PPS_PRECISION; 297 298 #if DEBUG 299 if (debug) { 300 time_pps_getparams(up->handle, &up->pps_params); 301 printf( 302 "refclock_ppsapi: capability 0x%x version %d mode 0x%x kern %d\n", 303 capability, up->pps_params.api_version, 304 up->pps_params.mode, enb_hardpps); 305 } 306 #endif 307 308 return (1); 309 } 310 311 /* 312 * Get PPSAPI timestamps. 313 * 314 * Return 0 on failure and 1 on success. 315 */ 316 static int 317 nmea_pps( 318 struct nmeaunit *up, 319 l_fp *tsptr 320 ) 321 { 322 pps_info_t pps_info; 323 struct timespec timeout, ts; 324 double dtemp; 325 l_fp tstmp; 326 327 /* 328 * Convert the timespec nanoseconds field to ntp l_fp units. 329 */ 330 if (up->handle == 0) 331 return (0); 332 timeout.tv_sec = 0; 333 timeout.tv_nsec = 0; 334 memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t)); 335 if (time_pps_fetch(up->handle, PPS_TSFMT_TSPEC, &up->pps_info, 336 &timeout) < 0) 337 return (0); 338 if (up->pps_params.mode & PPS_CAPTUREASSERT) { 339 if (pps_info.assert_sequence == 340 up->pps_info.assert_sequence) 341 return (0); 342 ts = up->pps_info.assert_timestamp; 343 } else if (up->pps_params.mode & PPS_CAPTURECLEAR) { 344 if (pps_info.clear_sequence == 345 up->pps_info.clear_sequence) 346 return (0); 347 ts = up->pps_info.clear_timestamp; 348 } else { 349 return (0); 350 } 351 if ((up->ts.tv_sec == ts.tv_sec) && (up->ts.tv_nsec == ts.tv_nsec)) 352 return (0); 353 up->ts = ts; 354 355 tstmp.l_ui = ts.tv_sec + JAN_1970; 356 dtemp = ts.tv_nsec * FRAC / 1e9; 357 tstmp.l_uf = (u_int32)dtemp; 358 *tsptr = tstmp; 359 return (1); 360 } 361 #endif /* HAVE_PPSAPI */ 362 363 /* 364 * nmea_receive - receive data from the serial interface 365 */ 366 static void 367 nmea_receive( 368 struct recvbuf *rbufp 369 ) 370 { 371 register struct nmeaunit *up; 372 struct refclockproc *pp; 373 struct peer *peer; 374 int month, day; 375 int i; 376 char *cp, *dp; 377 int cmdtype; 378 /* Use these variables to hold data until we decide its worth keeping */ 379 char rd_lastcode[BMAX]; 380 l_fp rd_tmp; 381 u_short rd_lencode; 382 383 /* 384 * Initialize pointers and read the timecode and timestamp 385 */ 386 peer = (struct peer *)rbufp->recv_srcclock; 387 pp = peer->procptr; 388 up = (struct nmeaunit *)pp->unitptr; 389 rd_lencode = (u_short)refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp); 390 391 /* 392 * There is a case that a <CR><LF> gives back a "blank" line 393 */ 394 if (rd_lencode == 0) 395 return; 396 397 #ifdef DEBUG 398 if (debug) 399 printf("nmea: gpsread %d %s\n", rd_lencode, 400 rd_lastcode); 401 #endif 402 403 /* 404 * We check the timecode format and decode its contents. The 405 * we only care about a few of them. The most important being 406 * the $GPRMC format 407 * $GPRMC,hhmmss,a,fddmm.xx,n,dddmmm.xx,w,zz.z,yyy.,ddmmyy,dd,v*CC 408 * For Magellan (ColorTrak) GLL probably datum (order of sentences) 409 * also mode (0,1,2,3) select sentence ANY/ALL, RMC, GGA, GLL 410 * $GPGLL,3513.8385,S,14900.7851,E,232420.594,A*21 411 * $GPGGA,232420.59,3513.8385,S,14900.7851,E,1,05,3.4,00519,M,,,,*3F 412 * $GPRMB,... 413 * $GPRMC,232418.19,A,3513.8386,S,14900.7853,E,00.0,000.0,121199,12.,E*77 414 * $GPAPB,... 415 * $GPGSA,... 416 * $GPGSV,... 417 * $GPGSV,... 418 */ 419 #define GPXXX 0 420 #define GPRMC 1 421 #define GPGGA 2 422 #define GPGLL 4 423 cp = rd_lastcode; 424 cmdtype=0; 425 if(strncmp(cp,"$GPRMC",6)==0) { 426 cmdtype=GPRMC; 427 } 428 else if(strncmp(cp,"$GPGGA",6)==0) { 429 cmdtype=GPGGA; 430 } 431 else if(strncmp(cp,"$GPGLL",6)==0) { 432 cmdtype=GPGLL; 433 } 434 else if(strncmp(cp,"$GPXXX",6)==0) { 435 cmdtype=GPXXX; 436 } 437 else 438 return; 439 440 441 /* See if I want to process this message type */ 442 if ( ((peer->ttl == 0) && (cmdtype != GPRMC)) 443 || ((peer->ttl != 0) && !(cmdtype & peer->ttl)) ) 444 return; 445 446 pp->lencode = rd_lencode; 447 strcpy(pp->a_lastcode,rd_lastcode); 448 cp = pp->a_lastcode; 449 450 pp->lastrec = up->tstamp = rd_tmp; 451 up->pollcnt = 2; 452 453 #ifdef DEBUG 454 if (debug) 455 printf("nmea: timecode %d %s\n", pp->lencode, 456 pp->a_lastcode); 457 #endif 458 459 460 /* Grab field depending on clock string type */ 461 switch( cmdtype ) { 462 case GPRMC: 463 /* 464 * Test for synchronization. Check for quality byte. 465 */ 466 dp = field_parse(cp,2); 467 if( dp[0] != 'A') 468 pp->leap = LEAP_NOTINSYNC; 469 else 470 pp->leap = LEAP_NOWARNING; 471 472 /* Now point at the time field */ 473 dp = field_parse(cp,1); 474 break; 475 476 477 case GPGGA: 478 /* 479 * Test for synchronization. Check for quality byte. 480 */ 481 dp = field_parse(cp,6); 482 if( dp[0] == '0') 483 pp->leap = LEAP_NOTINSYNC; 484 else 485 pp->leap = LEAP_NOWARNING; 486 487 /* Now point at the time field */ 488 dp = field_parse(cp,1); 489 break; 490 491 492 case GPGLL: 493 /* 494 * Test for synchronization. Check for quality byte. 495 */ 496 dp = field_parse(cp,6); 497 if( dp[0] != 'A') 498 pp->leap = LEAP_NOTINSYNC; 499 else 500 pp->leap = LEAP_NOWARNING; 501 502 /* Now point at the time field */ 503 dp = field_parse(cp,5); 504 break; 505 506 507 case GPXXX: 508 return; 509 default: 510 return; 511 512 } 513 514 /* 515 * Check time code format of NMEA 516 */ 517 518 if( !isdigit((int)dp[0]) || 519 !isdigit((int)dp[1]) || 520 !isdigit((int)dp[2]) || 521 !isdigit((int)dp[3]) || 522 !isdigit((int)dp[4]) || 523 !isdigit((int)dp[5]) 524 ) { 525 refclock_report(peer, CEVNT_BADREPLY); 526 return; 527 } 528 529 530 /* 531 * Convert time and check values. 532 */ 533 pp->hour = ((dp[0] - '0') * 10) + dp[1] - '0'; 534 pp->minute = ((dp[2] - '0') * 10) + dp[3] - '0'; 535 pp->second = ((dp[4] - '0') * 10) + dp[5] - '0'; 536 /* Default to 0 milliseconds, if decimal convert milliseconds in 537 one, two or three digits 538 */ 539 pp->nsec = 0; 540 if (dp[6] == '.') { 541 if (isdigit((int)dp[7])) { 542 pp->nsec = (dp[7] - '0') * 100000000; 543 if (isdigit((int)dp[8])) { 544 pp->nsec += (dp[8] - '0') * 10000000; 545 if (isdigit((int)dp[9])) { 546 pp->nsec += (dp[9] - '0') * 1000000; 547 } 548 } 549 } 550 } 551 552 if (pp->hour > 23 || pp->minute > 59 || pp->second > 59 553 || pp->nsec > 1000000000) { 554 refclock_report(peer, CEVNT_BADTIME); 555 return; 556 } 557 558 559 /* 560 * Convert date and check values. 561 */ 562 if (cmdtype==GPRMC) { 563 dp = field_parse(cp,9); 564 day = dp[0] - '0'; 565 day = (day * 10) + dp[1] - '0'; 566 month = dp[2] - '0'; 567 month = (month * 10) + dp[3] - '0'; 568 pp->year = dp[4] - '0'; 569 pp->year = (pp->year * 10) + dp[5] - '0'; 570 } 571 else { 572 /* only time */ 573 time_t tt = time(NULL); 574 struct tm * t = gmtime(&tt); 575 day = t->tm_mday; 576 month = t->tm_mon + 1; 577 pp->year= t->tm_year; 578 } 579 580 if (month < 1 || month > 12 || day < 1) { 581 refclock_report(peer, CEVNT_BADTIME); 582 return; 583 } 584 585 /* Hmmmm this will be a nono for 2100,2200,2300 but I don't think I'll be here */ 586 /* good thing that 2000 is a leap year */ 587 /* pp->year will be 00-99 if read from GPS, 00-> (years since 1900) from tm_year */ 588 if (pp->year % 4) { 589 if (day > day1tab[month - 1]) { 590 refclock_report(peer, CEVNT_BADTIME); 591 return; 592 } 593 for (i = 0; i < month - 1; i++) 594 day += day1tab[i]; 595 } else { 596 if (day > day2tab[month - 1]) { 597 refclock_report(peer, CEVNT_BADTIME); 598 return; 599 } 600 for (i = 0; i < month - 1; i++) 601 day += day2tab[i]; 602 } 603 pp->day = day; 604 605 606 #ifdef HAVE_PPSAPI 607 /* 608 * If the PPSAPI is working, rather use its timestamps. 609 * assume that the PPS occurs on the second so blow any msec 610 */ 611 if (nmea_pps(up, &rd_tmp) == 1) { 612 pp->lastrec = up->tstamp = rd_tmp; 613 pp->nsec = 0; 614 } 615 #endif /* HAVE_PPSAPI */ 616 617 /* 618 * Process the new sample in the median filter and determine the 619 * reference clock offset and dispersion. We use lastrec as both 620 * the reference time and receive time, in order to avoid being 621 * cute, like setting the reference time later than the receive 622 * time, which may cause a paranoid protocol module to chuck out 623 * the data. 624 */ 625 626 if (!refclock_process(pp)) { 627 refclock_report(peer, CEVNT_BADTIME); 628 return; 629 } 630 631 632 633 /* 634 * Only go on if we had been polled. 635 */ 636 if (!up->polled) 637 return; 638 up->polled = 0; 639 pp->lastref = pp->lastrec; 640 refclock_receive(peer); 641 642 /* If we get here - what we got from the clock is OK, so say so */ 643 refclock_report(peer, CEVNT_NOMINAL); 644 645 record_clock_stats(&peer->srcadr, pp->a_lastcode); 646 647 } 648 649 /* 650 * nmea_poll - called by the transmit procedure 651 * 652 * We go to great pains to avoid changing state here, since there may be 653 * more than one eavesdropper receiving the same timecode. 654 */ 655 static void 656 nmea_poll( 657 int unit, 658 struct peer *peer 659 ) 660 { 661 register struct nmeaunit *up; 662 struct refclockproc *pp; 663 664 pp = peer->procptr; 665 up = (struct nmeaunit *)pp->unitptr; 666 if (up->pollcnt == 0) 667 refclock_report(peer, CEVNT_TIMEOUT); 668 else 669 up->pollcnt--; 670 pp->polls++; 671 up->polled = 1; 672 673 /* 674 * usually nmea_receive can get a timestamp every second 675 */ 676 677 gps_send(pp->io.fd,"$PMOTG,RMC,0000*1D\r\n", peer); 678 } 679 680 /* 681 * 682 * gps_send(fd,cmd, peer) Sends a command to the GPS receiver. 683 * as gps_send(fd,"rqts,u\r", peer); 684 * 685 * We don't currently send any data, but would like to send 686 * RTCM SC104 messages for differential positioning. It should 687 * also give us better time. Without a PPS output, we're 688 * Just fooling ourselves because of the serial code paths 689 * 690 */ 691 static void 692 gps_send( 693 int fd, 694 const char *cmd, 695 struct peer *peer 696 ) 697 { 698 699 if (write(fd, cmd, strlen(cmd)) == -1) { 700 refclock_report(peer, CEVNT_FAULT); 701 } 702 } 703 704 static char * 705 field_parse( 706 char *cp, 707 int fn 708 ) 709 { 710 char *tp; 711 int i = fn; 712 713 for (tp = cp; *tp != '\0'; tp++) { 714 if (*tp == ',') 715 i--; 716 if (i == 0) 717 break; 718 } 719 return (++tp); 720 } 721 #else 722 int refclock_nmea_bs; 723 #endif /* REFCLOCK */ 724