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 * Updated to add support for Accord GPS Clock 7 * Venu Gopal Dec 05, 2007 8 * neo.venu@gmail.com, venugopal_d@pgad.gov.in 9 * 10 * Updated to process 'time1' fudge factor 11 * Venu Gopal May 05, 2008 12 * 13 * Converted to common PPSAPI code, separate PPS fudge time1 14 * from serial timecode fudge time2. 15 * Dave Hart July 1, 2009 16 * hart@ntp.org, davehart@davehart.com 17 */ 18#ifdef HAVE_CONFIG_H 19#include <config.h> 20#endif 21 22#if defined(REFCLOCK) && defined(CLOCK_NMEA) 23 24#include <sys/stat.h> 25#include <stdio.h> 26#include <ctype.h> 27 28#include "ntpd.h" 29#include "ntp_io.h" 30#include "ntp_unixtime.h" 31#include "ntp_refclock.h" 32#include "ntp_stdlib.h" 33 34#ifdef HAVE_PPSAPI 35# include "ppsapi_timepps.h" 36#include "refclock_atom.h" 37#endif /* HAVE_PPSAPI */ 38 39#ifdef SYS_WINNT 40#undef write /* ports/winnt/include/config.h: #define write _write */ 41extern int async_write(int, const void *, unsigned int); 42#define write(fd, data, octets) async_write(fd, data, octets) 43#endif 44 45/* 46 * This driver supports NMEA-compatible GPS receivers 47 * 48 * Prototype was refclock_trak.c, Thanks a lot. 49 * 50 * The receiver used spits out the NMEA sentences for boat navigation. 51 * And you thought it was an information superhighway. Try a raging river 52 * filled with rapids and whirlpools that rip away your data and warp time. 53 * 54 * If HAVE_PPSAPI is defined code to use the PPSAPI will be compiled in. 55 * On startup if initialization of the PPSAPI fails, it will fall back 56 * to the "normal" timestamps. 57 * 58 * The PPSAPI part of the driver understands fudge flag2 and flag3. If 59 * flag2 is set, it will use the clear edge of the pulse. If flag3 is 60 * set, kernel hardpps is enabled. 61 * 62 * GPS sentences other than RMC (the default) may be enabled by setting 63 * the relevent bits of 'mode' in the server configuration line 64 * server 127.127.20.x mode X 65 * 66 * bit 0 - enables RMC (1) 67 * bit 1 - enables GGA (2) 68 * bit 2 - enables GLL (4) 69 * bit 3 - enables ZDA (8) - Standard Time & Date 70 * bit 3 - enables ZDG (8) - Accord GPS Clock's custom sentence with GPS time 71 * very close to standard ZDA 72 * 73 * Multiple sentences may be selected except when ZDG/ZDA is selected. 74 * 75 * bit 4/5/6 - selects the baudrate for serial port : 76 * 0 for 4800 (default) 77 * 1 for 9600 78 * 2 for 19200 79 * 3 for 38400 80 * 4 for 57600 81 * 5 for 115200 82 */ 83#define NMEA_MESSAGE_MASK_OLD 0x07 84#define NMEA_MESSAGE_MASK_SINGLE 0x08 85#define NMEA_MESSAGE_MASK (NMEA_MESSAGE_MASK_OLD | NMEA_MESSAGE_MASK_SINGLE) 86 87#define NMEA_BAUDRATE_MASK 0x70 88#define NMEA_BAUDRATE_SHIFT 4 89 90/* 91 * Definitions 92 */ 93#define DEVICE "/dev/gps%d" /* GPS serial device */ 94#define PPSDEV "/dev/gpspps%d" /* PPSAPI device override */ 95#define SPEED232 B4800 /* uart speed (4800 bps) */ 96#define PRECISION (-9) /* precision assumed (about 2 ms) */ 97#define PPS_PRECISION (-20) /* precision assumed (about 1 us) */ 98#define REFID "GPS\0" /* reference id */ 99#define DESCRIPTION "NMEA GPS Clock" /* who we are */ 100#define NANOSECOND 1000000000 /* one second (ns) */ 101#define RANGEGATE 500000 /* range gate (ns) */ 102#ifndef O_NOCTTY 103#define M_NOCTTY 0 104#else 105#define M_NOCTTY O_NOCTTY 106#endif 107#ifndef O_NONBLOCK 108#define M_NONBLOCK 0 109#else 110#define M_NONBLOCK O_NONBLOCK 111#endif 112#define PPSOPENMODE (O_RDWR | M_NOCTTY | M_NONBLOCK) 113 114/* 115 * Unit control structure 116 */ 117struct nmeaunit { 118#ifdef HAVE_PPSAPI 119 struct refclock_atom atom; /* PPSAPI structure */ 120 int ppsapi_tried; /* attempt PPSAPI once */ 121 int ppsapi_lit; /* time_pps_create() worked */ 122 int ppsapi_fd; /* fd used with PPSAPI */ 123 int tcount; /* timecode sample counter */ 124 int pcount; /* PPS sample counter */ 125#endif /* HAVE_PPSAPI */ 126 l_fp tstamp; /* timestamp of last poll */ 127 int gps_time; /* 0 UTC, 1 GPS time */ 128}; 129 130/* 131 * Function prototypes 132 */ 133static int nmea_start (int, struct peer *); 134static void nmea_shutdown (int, struct peer *); 135static void nmea_receive (struct recvbuf *); 136static void nmea_poll (int, struct peer *); 137#ifdef HAVE_PPSAPI 138static void nmea_control (int, struct refclockstat *, 139 struct refclockstat *, struct peer *); 140static void nmea_timer (int, struct peer *); 141#define NMEA_CONTROL nmea_control 142#define NMEA_TIMER nmea_timer 143#else 144#define NMEA_CONTROL noentry 145#define NMEA_TIMER noentry 146#endif /* HAVE_PPSAPI */ 147static void gps_send (int, const char *, struct peer *); 148static char * field_parse (char *, int); 149static int nmea_checksum_ok(const char *); 150 151/* 152 * Transfer vector 153 */ 154struct refclock refclock_nmea = { 155 nmea_start, /* start up driver */ 156 nmea_shutdown, /* shut down driver */ 157 nmea_poll, /* transmit poll message */ 158 NMEA_CONTROL, /* fudge control */ 159 noentry, /* initialize driver */ 160 noentry, /* buginfo */ 161 NMEA_TIMER /* called once per second */ 162}; 163 164/* 165 * nmea_start - open the GPS devices and initialize data for processing 166 */ 167static int 168nmea_start( 169 int unit, 170 struct peer *peer 171 ) 172{ 173 register struct nmeaunit *up; 174 struct refclockproc *pp; 175 int fd; 176 char device[20]; 177 int baudrate; 178 char *baudtext; 179 180 pp = peer->procptr; 181 182 /* 183 * Open serial port. Use CLK line discipline, if available. 184 */ 185 snprintf(device, sizeof(device), DEVICE, unit); 186 187 /* 188 * Opening the serial port with appropriate baudrate 189 * based on the value of bit 4/5/6 190 */ 191 switch ((peer->ttl & NMEA_BAUDRATE_MASK) >> NMEA_BAUDRATE_SHIFT) { 192 case 0: 193 case 6: 194 case 7: 195 default: 196 baudrate = SPEED232; 197 baudtext = "4800"; 198 break; 199 case 1: 200 baudrate = B9600; 201 baudtext = "9600"; 202 break; 203 case 2: 204 baudrate = B19200; 205 baudtext = "19200"; 206 break; 207 case 3: 208 baudrate = B38400; 209 baudtext = "38400"; 210 break; 211#ifdef B57600 212 case 4: 213 baudrate = B57600; 214 baudtext = "57600"; 215 break; 216#endif 217#ifdef B115200 218 case 5: 219 baudrate = B115200; 220 baudtext = "115200"; 221 break; 222#endif 223 } 224 225 fd = refclock_open(device, baudrate, LDISC_CLK); 226 227 if (fd <= 0) { 228#ifdef HAVE_READLINK 229 /* nmead support added by Jon Miner (cp_n18@yahoo.com) 230 * 231 * See http://home.hiwaay.net/~taylorc/gps/nmea-server/ 232 * for information about nmead 233 * 234 * To use this, you need to create a link from /dev/gpsX to 235 * the server:port where nmead is running. Something like this: 236 * 237 * ln -s server:port /dev/gps1 238 */ 239 char buffer[80]; 240 char *nmea_host, *nmea_tail; 241 int nmea_port; 242 int len; 243 struct hostent *he; 244 struct protoent *p; 245 struct sockaddr_in so_addr; 246 247 if ((len = readlink(device,buffer,sizeof(buffer))) == -1) 248 return(0); 249 buffer[len] = 0; 250 251 if ((nmea_host = strtok(buffer,":")) == NULL) 252 return(0); 253 if ((nmea_tail = strtok(NULL,":")) == NULL) 254 return(0); 255 256 nmea_port = atoi(nmea_tail); 257 258 if ((he = gethostbyname(nmea_host)) == NULL) 259 return(0); 260 if ((p = getprotobyname("ip")) == NULL) 261 return(0); 262 memset(&so_addr, 0, sizeof(so_addr)); 263 so_addr.sin_family = AF_INET; 264 so_addr.sin_port = htons(nmea_port); 265 so_addr.sin_addr = *((struct in_addr *) he->h_addr); 266 267 if ((fd = socket(PF_INET,SOCK_STREAM,p->p_proto)) == -1) 268 return(0); 269 if (connect(fd,(struct sockaddr *)&so_addr, sizeof(so_addr)) == -1) { 270 close(fd); 271 return (0); 272 } 273#else 274 pp->io.fd = -1; 275 return (0); 276#endif 277 } 278 279 msyslog(LOG_NOTICE, "%s serial %s open at %s bps", 280 refnumtoa(&peer->srcadr), device, baudtext); 281 282 /* 283 * Allocate and initialize unit structure 284 */ 285 up = emalloc(sizeof(*up)); 286 memset(up, 0, sizeof(*up)); 287 pp->io.clock_recv = nmea_receive; 288 pp->io.srcclock = (caddr_t)peer; 289 pp->io.datalen = 0; 290 pp->io.fd = fd; 291 if (!io_addclock(&pp->io)) { 292 pp->io.fd = -1; 293 close(fd); 294 free(up); 295 return (0); 296 } 297 pp->unitptr = (caddr_t)up; 298 299 /* 300 * Initialize miscellaneous variables 301 */ 302 peer->precision = PRECISION; 303 pp->clockdesc = DESCRIPTION; 304 memcpy(&pp->refid, REFID, 4); 305 306 gps_send(fd,"$PMOTG,RMC,0000*1D\r\n", peer); 307 308 return (1); 309} 310 311 312/* 313 * nmea_shutdown - shut down a GPS clock 314 * 315 * NOTE this routine is called after nmea_start() returns failure, 316 * as well as during a normal shutdown due to ntpq :config unpeer. 317 */ 318static void 319nmea_shutdown( 320 int unit, 321 struct peer *peer 322 ) 323{ 324 register struct nmeaunit *up; 325 struct refclockproc *pp; 326 327 UNUSED_ARG(unit); 328 329 pp = peer->procptr; 330 up = (struct nmeaunit *)pp->unitptr; 331 if (up != NULL) { 332#ifdef HAVE_PPSAPI 333 if (up->ppsapi_lit) { 334 time_pps_destroy(up->atom.handle); 335 if (up->ppsapi_fd != pp->io.fd) 336 close(up->ppsapi_fd); 337 } 338#endif 339 free(up); 340 } 341 if (-1 != pp->io.fd) 342 io_closeclock(&pp->io); 343} 344 345/* 346 * nmea_control - configure fudge params 347 */ 348#ifdef HAVE_PPSAPI 349static void 350nmea_control( 351 int unit, 352 struct refclockstat *in_st, 353 struct refclockstat *out_st, 354 struct peer *peer 355 ) 356{ 357 char device[32]; 358 register struct nmeaunit *up; 359 struct refclockproc *pp; 360 int pps_fd; 361 362 UNUSED_ARG(in_st); 363 UNUSED_ARG(out_st); 364 365 pp = peer->procptr; 366 up = (struct nmeaunit *)pp->unitptr; 367 368 if (!(CLK_FLAG1 & pp->sloppyclockflag)) { 369 if (!up->ppsapi_tried) 370 return; 371 up->ppsapi_tried = 0; 372 if (!up->ppsapi_lit) 373 return; 374 peer->flags &= ~FLAG_PPS; 375 peer->precision = PRECISION; 376 time_pps_destroy(up->atom.handle); 377 if (up->ppsapi_fd != pp->io.fd) 378 close(up->ppsapi_fd); 379 up->atom.handle = 0; 380 up->ppsapi_lit = 0; 381 up->ppsapi_fd = -1; 382 return; 383 } 384 385 if (up->ppsapi_tried) 386 return; 387 /* 388 * Light up the PPSAPI interface. 389 */ 390 up->ppsapi_tried = 1; 391 392 /* 393 * if /dev/gpspps$UNIT can be opened that will be used for 394 * PPSAPI. Otherwise, the GPS serial device /dev/gps$UNIT 395 * already opened is used for PPSAPI as well. 396 */ 397 snprintf(device, sizeof(device), PPSDEV, unit); 398 399 pps_fd = open(device, PPSOPENMODE, S_IRUSR | S_IWUSR); 400 401 if (-1 == pps_fd) 402 pps_fd = pp->io.fd; 403 404 if (refclock_ppsapi(pps_fd, &up->atom)) { 405 up->ppsapi_lit = 1; 406 up->ppsapi_fd = pps_fd; 407 return; 408 } 409 410 NLOG(NLOG_CLOCKINFO) 411 msyslog(LOG_WARNING, "%s flag1 1 but PPSAPI fails", 412 refnumtoa(&peer->srcadr)); 413} 414#endif /* HAVE_PPSAPI */ 415 416 417/* 418 * nmea_timer - called once per second, fetches PPS 419 * timestamp and stuffs in median filter. 420 */ 421#ifdef HAVE_PPSAPI 422static void 423nmea_timer( 424 int unit, 425 struct peer * peer 426 ) 427{ 428 struct nmeaunit *up; 429 struct refclockproc *pp; 430 431 UNUSED_ARG(unit); 432 433 pp = peer->procptr; 434 up = (struct nmeaunit *)pp->unitptr; 435 436 if (up->ppsapi_lit && 437 refclock_pps(peer, &up->atom, pp->sloppyclockflag) > 0) { 438 up->pcount++, 439 peer->flags |= FLAG_PPS; 440 peer->precision = PPS_PRECISION; 441 } 442} 443#endif /* HAVE_PPSAPI */ 444 445 446/* 447 * nmea_receive - receive data from the serial interface 448 */ 449static void 450nmea_receive( 451 struct recvbuf *rbufp 452 ) 453{ 454 register struct nmeaunit *up; 455 struct refclockproc *pp; 456 struct peer *peer; 457 int month, day; 458 char *cp, *dp, *msg; 459 int cmdtype; 460 int cmdtypezdg = 0; 461 /* Use these variables to hold data until we decide its worth keeping */ 462 char rd_lastcode[BMAX]; 463 l_fp rd_timestamp; 464 int rd_lencode; 465 466 /* 467 * Initialize pointers and read the timecode and timestamp 468 */ 469 peer = rbufp->recv_peer; 470 pp = peer->procptr; 471 up = (struct nmeaunit *)pp->unitptr; 472 473 rd_lencode = refclock_gtlin( 474 rbufp, 475 rd_lastcode, 476 sizeof(rd_lastcode), 477 &rd_timestamp); 478 479 /* 480 * There is a case that a <CR><LF> gives back a "blank" line 481 */ 482 if (rd_lencode == 0) 483 return; 484 485 DPRINTF(1, ("nmea: gpsread %d %s\n", rd_lencode, rd_lastcode)); 486 487 /* 488 * We check the timecode format and decode its contents. The 489 * we only care about a few of them. The most important being 490 * the $GPRMC format 491 * $GPRMC,hhmmss,a,fddmm.xx,n,dddmmm.xx,w,zz.z,yyy.,ddmmyy,dd,v*CC 492 * mode (0,1,2,3) selects sentence ANY/ALL, RMC, GGA, GLL, ZDA 493 * $GPGLL,3513.8385,S,14900.7851,E,232420.594,A*21 494 * $GPGGA,232420.59,3513.8385,S,14900.7851,E,1,05,3.4,00519,M,,,,*3F 495 * $GPRMC,232418.19,A,3513.8386,S,14900.7853,E,00.0,000.0,121199,12.,E*77 496 * 497 * Defining GPZDA to support Standard Time & Date 498 * sentence. The sentence has the following format 499 * 500 * $--ZDA,HHMMSS.SS,DD,MM,YYYY,TH,TM,*CS<CR><LF> 501 * 502 * Apart from the familiar fields, 503 * 'TH' Time zone Hours 504 * 'TM' Time zone Minutes 505 * 506 * Defining GPZDG to support Accord GPS Clock's custom NMEA 507 * sentence. The sentence has the following format 508 * 509 * $GPZDG,HHMMSS.S,DD,MM,YYYY,AA.BB,V*CS<CR><LF> 510 * 511 * It contains the GPS timestamp valid for next PPS pulse. 512 * Apart from the familiar fields, 513 * 'AA.BB' denotes the signal strength( should be < 05.00 ) 514 * 'V' denotes the GPS sync status : 515 * '0' indicates INVALID time, 516 * '1' indicates accuracy of +/-20 ms 517 * '2' indicates accuracy of +/-100 ns 518 */ 519#define GPXXX 0 /* any/all */ 520#define GPRMC 1 521#define GPGGA 2 522#define GPGLL 4 523#define GPZDG_ZDA 8 524 525 cp = rd_lastcode; 526 cmdtype=0; 527 if (cp[0] == '$') { 528 /* Allow for GLGGA and GPGGA etc. */ 529 msg = cp + 3; 530 531 if (strncmp(msg, "RMC", 3) == 0) 532 cmdtype = GPRMC; 533 else if (strncmp(msg, "GGA", 3) == 0) 534 cmdtype = GPGGA; 535 else if (strncmp(msg, "GLL", 3) == 0) 536 cmdtype = GPGLL; 537 else if (strncmp(msg, "ZD", 2) == 0) { 538 cmdtype = GPZDG_ZDA; 539 if ('G' == msg[2]) 540 cmdtypezdg = 1; 541 else if ('A' != msg[2]) 542 return; 543 } else 544 return; 545 } else 546 return; 547 548 /* See if I want to process this message type */ 549 if (peer->ttl && !(cmdtype & (peer->ttl & NMEA_MESSAGE_MASK))) 550 return; 551 552 /* 553 * $GPZDG provides GPS time not UTC, and the two mix poorly. 554 * Once have processed a $GPZDG, do not process any further 555 * UTC sentences (all but $GPZDG currently). 556 */ 557 if (up->gps_time && !cmdtypezdg) 558 return; 559 560 /* make sure it came in clean */ 561 if (!nmea_checksum_ok(rd_lastcode)) { 562 refclock_report(peer, CEVNT_BADREPLY); 563 return; 564 } 565 566 pp->lencode = (u_short) rd_lencode; 567 memcpy(pp->a_lastcode, rd_lastcode, pp->lencode + 1); 568 cp = pp->a_lastcode; 569 570 up->tstamp = rd_timestamp; 571 pp->lastrec = up->tstamp; 572 573 DPRINTF(1, ("nmea: timecode %d %s\n", pp->lencode, pp->a_lastcode)); 574 575 /* Grab field depending on clock string type */ 576 switch (cmdtype) { 577 578 case GPRMC: 579 /* 580 * Test for synchronization. Check for quality byte. 581 */ 582 dp = field_parse(cp, 2); 583 if (dp[0] != 'A') 584 pp->leap = LEAP_NOTINSYNC; 585 else 586 pp->leap = LEAP_NOWARNING; 587 588 /* Now point at the time field */ 589 dp = field_parse(cp, 1); 590 break; 591 592 case GPGGA: 593 /* 594 * Test for synchronization. Check for quality byte. 595 */ 596 dp = field_parse(cp, 6); 597 if (dp[0] == '0') 598 pp->leap = LEAP_NOTINSYNC; 599 else 600 pp->leap = LEAP_NOWARNING; 601 602 /* Now point at the time field */ 603 dp = field_parse(cp, 1); 604 break; 605 606 case GPGLL: 607 /* 608 * Test for synchronization. Check for quality byte. 609 */ 610 dp = field_parse(cp, 6); 611 if (dp[0] != 'A') 612 pp->leap = LEAP_NOTINSYNC; 613 else 614 pp->leap = LEAP_NOWARNING; 615 616 /* Now point at the time field */ 617 dp = field_parse(cp, 5); 618 break; 619 620 case GPZDG_ZDA: 621 /* 622 * Test for synchronization. For $GPZDG check for validity of GPS time. 623 */ 624 if (cmdtypezdg) { 625 dp = field_parse(cp, 6); 626 if (dp[0] == '0') 627 pp->leap = LEAP_NOTINSYNC; 628 else 629 pp->leap = LEAP_NOWARNING; 630 } else 631 pp->leap = LEAP_NOWARNING; 632 633 /* Now point at the time field */ 634 dp = field_parse(cp, 1); 635 break; 636 637 default: 638 return; 639 } 640 641 /* 642 * Check time code format of NMEA 643 */ 644 if (!isdigit((int)dp[0]) || 645 !isdigit((int)dp[1]) || 646 !isdigit((int)dp[2]) || 647 !isdigit((int)dp[3]) || 648 !isdigit((int)dp[4]) || 649 !isdigit((int)dp[5])) { 650 651 DPRINTF(1, ("NMEA time code %c%c%c%c%c%c non-numeric", 652 dp[0], dp[1], dp[2], dp[3], dp[4], dp[5])); 653 refclock_report(peer, CEVNT_BADTIME); 654 return; 655 } 656 657 /* 658 * Convert time and check values. 659 */ 660 pp->hour = ((dp[0] - '0') * 10) + dp[1] - '0'; 661 pp->minute = ((dp[2] - '0') * 10) + dp[3] - '0'; 662 pp->second = ((dp[4] - '0') * 10) + dp[5] - '0'; 663 /* 664 * Default to 0 milliseconds, if decimal convert milliseconds in 665 * one, two or three digits 666 */ 667 pp->nsec = 0; 668 if (dp[6] == '.') { 669 if (isdigit((int)dp[7])) { 670 pp->nsec = (dp[7] - '0') * 100000000; 671 if (isdigit((int)dp[8])) { 672 pp->nsec += (dp[8] - '0') * 10000000; 673 if (isdigit((int)dp[9])) { 674 pp->nsec += (dp[9] - '0') * 1000000; 675 } 676 } 677 } 678 } 679 680 /* 681 * Manipulating GPS timestamp in GPZDG as the seconds field 682 * is valid for next PPS tick. Just rolling back the second, 683 * minute and hour fields appopriately 684 */ 685 if (cmdtypezdg) { 686 if (pp->second == 0) { 687 pp->second = 59; 688 if (pp->minute == 0) { 689 pp->minute = 59; 690 if (pp->hour == 0) 691 pp->hour = 23; 692 } 693 } else 694 pp->second -= 1; 695 } 696 697 if (pp->hour > 23 || pp->minute > 59 || 698 pp->second > 59 || pp->nsec > 1000000000) { 699 700 DPRINTF(1, ("NMEA hour/min/sec/nsec range %02d:%02d:%02d.%09ld\n", 701 pp->hour, pp->minute, pp->second, pp->nsec)); 702 refclock_report(peer, CEVNT_BADTIME); 703 return; 704 } 705 706 /* 707 * Convert date and check values. 708 */ 709 if (GPRMC == cmdtype) { 710 711 dp = field_parse(cp,9); 712 day = dp[0] - '0'; 713 day = (day * 10) + dp[1] - '0'; 714 month = dp[2] - '0'; 715 month = (month * 10) + dp[3] - '0'; 716 pp->year = dp[4] - '0'; 717 pp->year = (pp->year * 10) + dp[5] - '0'; 718 719 } else if (GPZDG_ZDA == cmdtype) { 720 721 dp = field_parse(cp, 2); 722 day = 10 * (dp[0] - '0') + (dp[1] - '0'); 723 dp = field_parse(cp, 3); 724 month = 10 * (dp[0] - '0') + (dp[1] - '0'); 725 dp = field_parse(cp, 4); 726 pp->year = /* 1000 * (dp[0] - '0') + 100 * (dp[1] - '0') + */ 10 * (dp[2] - '0') + (dp[3] - '0'); 727 728 } else { 729 /* only time */ 730 time_t tt = time(NULL); 731 struct tm * t = gmtime(&tt); 732 day = t->tm_mday; 733 month = t->tm_mon + 1; 734 pp->year= t->tm_year + 1900; 735 } 736 737 if (month < 1 || month > 12 || day < 1) { 738 refclock_report(peer, CEVNT_BADDATE); 739 return; 740 } 741 742 /* pp->year will be 2 or 4 digits if read from GPS, 4 from gmtime */ 743 if (pp->year < 100) { 744 if (pp->year < 9) /* year of our line of code is 2009 */ 745 pp->year += 2100; 746 else 747 pp->year += 2000; 748 } 749 750 /* pp->year now 4 digits as ymd2yd requires */ 751 day = ymd2yd(pp->year, month, day); 752 if (-1 == day) { 753 refclock_report(peer, CEVNT_BADDATE); 754 return; 755 } 756 pp->day = day; 757 758 /* 759 * If "fudge 127.127.20.__ flag4 1" is configured in ntp.conf, 760 * remove the location and checksum from the NMEA sentence 761 * recorded as the last timecode and visible to remote users 762 * with: 763 * 764 * ntpq -c clockvar <server> 765 * 766 * Note that this also removes the location from the clockstats 767 * log (if it is enabled). Some NTP operators monitor their 768 * NMEA GPS using the change in location in clockstats over 769 * time as as a proxy for the quality of GPS reception and 770 * thereby time reported. 771 */ 772 if (CLK_FLAG4 & pp->sloppyclockflag) { 773 /* 774 * Start by pointing cp and dp at the fields with 775 * longitude and latitude in the last timecode. 776 */ 777 switch (cmdtype) { 778 779 case GPGLL: 780 cp = field_parse(pp->a_lastcode, 1); 781 dp = field_parse(cp, 2); 782 break; 783 784 case GPGGA: 785 cp = field_parse(pp->a_lastcode, 2); 786 dp = field_parse(cp, 2); 787 break; 788 789 case GPRMC: 790 cp = field_parse(pp->a_lastcode, 3); 791 dp = field_parse(cp, 2); 792 break; 793 794 case GPZDG_ZDA: 795 default: 796 cp = dp = NULL; 797 } 798 799 /* Blank the entire latitude & longitude. */ 800 while (cp) { 801 while (',' != *cp) { 802 if ('.' != *cp) 803 *cp = '_'; 804 cp++; 805 } 806 807 /* Longitude at cp then latitude at dp */ 808 if (cp < dp) 809 cp = dp; 810 else 811 cp = NULL; 812 } 813 814 /* Blank the checksum, the last two characters */ 815 if (dp) { 816 cp = pp->a_lastcode + pp->lencode - 2; 817 if (0 == cp[2]) 818 cp[0] = cp[1] = '_'; 819 } 820 821 } 822 823 /* 824 * Note if we're only using GPS timescale from now on. 825 */ 826 if (cmdtypezdg && !up->gps_time) { 827 up->gps_time = 1; 828 NLOG(NLOG_CLOCKINFO) 829 msyslog(LOG_INFO, "%s using only $GPZDG", 830 refnumtoa(&peer->srcadr)); 831 } 832 833 /* 834 * Process the new sample in the median filter and determine the 835 * timecode timestamp, but only if the PPS is not in control. 836 */ 837#ifdef HAVE_PPSAPI 838 up->tcount++; 839 if (peer->flags & FLAG_PPS) 840 return; 841#endif /* HAVE_PPSAPI */ 842 if (!refclock_process_f(pp, pp->fudgetime2)) 843 refclock_report(peer, CEVNT_BADTIME); 844} 845 846 847/* 848 * nmea_poll - called by the transmit procedure 849 * 850 * We go to great pains to avoid changing state here, since there may be 851 * more than one eavesdropper receiving the same timecode. 852 */ 853static void 854nmea_poll( 855 int unit, 856 struct peer *peer 857 ) 858{ 859 register struct nmeaunit *up; 860 struct refclockproc *pp; 861 862 pp = peer->procptr; 863 up = (struct nmeaunit *)pp->unitptr; 864 865 /* 866 * Process median filter samples. If none received, declare a 867 * timeout and keep going. 868 */ 869#ifdef HAVE_PPSAPI 870 if (up->pcount == 0) { 871 peer->flags &= ~FLAG_PPS; 872 peer->precision = PRECISION; 873 } 874 if (up->tcount == 0) { 875 pp->coderecv = pp->codeproc; 876 refclock_report(peer, CEVNT_TIMEOUT); 877 return; 878 } 879 up->pcount = up->tcount = 0; 880#else /* HAVE_PPSAPI */ 881 if (pp->coderecv == pp->codeproc) { 882 refclock_report(peer, CEVNT_TIMEOUT); 883 return; 884 } 885#endif /* HAVE_PPSAPI */ 886 887 pp->polls++; 888 pp->lastref = pp->lastrec; 889 refclock_receive(peer); 890 record_clock_stats(&peer->srcadr, pp->a_lastcode); 891 892 /* 893 * usually nmea_receive can get a timestamp every second, 894 * but at least one Motorola unit needs prompting each 895 * time. 896 */ 897 898 gps_send(pp->io.fd,"$PMOTG,RMC,0000*1D\r\n", peer); 899} 900 901 902/* 903 * 904 * gps_send(fd,cmd, peer) Sends a command to the GPS receiver. 905 * as gps_send(fd,"rqts,u\r", peer); 906 * 907 * We don't currently send any data, but would like to send 908 * RTCM SC104 messages for differential positioning. It should 909 * also give us better time. Without a PPS output, we're 910 * Just fooling ourselves because of the serial code paths 911 * 912 */ 913static void 914gps_send( 915 int fd, 916 const char *cmd, 917 struct peer *peer 918 ) 919{ 920 if (write(fd, cmd, strlen(cmd)) == -1) { 921 refclock_report(peer, CEVNT_FAULT); 922 } 923} 924 925 926static char * 927field_parse( 928 char *cp, 929 int fn 930 ) 931{ 932 char *tp; 933 int i = fn; 934 935 for (tp = cp; i && *tp; tp++) 936 if (*tp == ',') 937 i--; 938 939 return tp; 940} 941 942 943/* 944 * nmea_checksum_ok verifies 8-bit XOR checksum is correct then returns 1 945 * 946 * format is $XXXXX,1,2,3,4*ML 947 * 948 * 8-bit XOR of characters between $ and * noninclusive is transmitted 949 * in last two chars M and L holding most and least significant nibbles 950 * in hex representation such as: 951 * 952 * $GPGLL,5057.970,N,00146.110,E,142451,A*27 953 * $GPVTG,089.0,T,,,15.2,N,,*7F 954 */ 955int 956nmea_checksum_ok( 957 const char *sentence 958 ) 959{ 960 u_char my_cs; 961 u_long input_cs; 962 const char *p; 963 964 my_cs = 0; 965 p = sentence; 966 967 if ('$' != *p++) 968 return 0; 969 970 for ( ; *p && '*' != *p; p++) { 971 972 my_cs ^= *p; 973 } 974 975 if ('*' != *p++) 976 return 0; 977 978 if (0 == p[0] || 0 == p[1] || 0 != p[2]) 979 return 0; 980 981 if (0 == hextoint(p, &input_cs)) 982 return 0; 983 984 if (my_cs != input_cs) 985 return 0; 986 987 return 1; 988} 989#else 990int refclock_nmea_bs; 991#endif /* REFCLOCK && CLOCK_NMEA */ 992