1 /* 2 * This software was developed by the Software and Component Technologies 3 * group of Trimble Navigation, Ltd. 4 * 5 * Copyright (c) 1997, 1998, 1999, 2000 Trimble Navigation Ltd. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Trimble Navigation, Ltd. 19 * 4. The name of Trimble Navigation Ltd. may not be used to endorse or 20 * promote products derived from this software without specific prior 21 * written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY TRIMBLE NAVIGATION LTD. ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL TRIMBLE NAVIGATION LTD. BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 /* 37 * refclock_palisade - clock driver for the Trimble Palisade GPS 38 * timing receiver 39 * 40 * For detailed information on this program, please refer to the html 41 * Refclock 29 page accompanying the NTP distribution. 42 * 43 * for questions / bugs / comments, contact: 44 * sven_dietrich@trimble.com 45 * 46 * Sven-Thorsten Dietrich 47 * 645 North Mary Avenue 48 * Post Office Box 3642 49 * Sunnyvale, CA 94088-3642 50 * 51 * Version 2.45; July 14, 1999 52 * 53 * 54 * 55 * 31/03/06: Added support for Thunderbolt GPS Disciplined Clock. 56 * Contact: Fernando Pablo Hauscarriaga 57 * E-mail: fernandoph@iar.unlp.edu.ar 58 * Home page: www.iar.unlp.edu.ar/~fernandoph 59 * Instituto Argentino de Radioastronomia 60 * www.iar.unlp.edu.ar 61 * 62 * 14/01/07: Conditinal compilation for Thunderbolt support no longer needed 63 * now we use mode 2 for decode thunderbolt packets. 64 * Fernando P. Hauscarriaga 65 * 66 * 30/08/09: Added support for Trimble Acutime Gold Receiver. 67 * Fernando P. Hauscarriaga (fernandoph@iar.unlp.edu.ar) 68 */ 69 70 #ifdef HAVE_CONFIG_H 71 # include "config.h" 72 #endif 73 74 #if defined(REFCLOCK) && defined(CLOCK_PALISADE) 75 76 #ifdef SYS_WINNT 77 extern int async_write(int, const void *, unsigned int); 78 #undef write 79 #define write(fd, data, octets) async_write(fd, data, octets) 80 #endif 81 82 #include "refclock_palisade.h" 83 84 #ifdef DEBUG 85 const char * Tracking_Status[15][15] = { 86 { "Doing Fixes\0" }, { "Good 1SV\0" }, { "Approx. 1SV\0" }, 87 {"Need Time\0" }, { "Need INIT\0" }, { "PDOP too High\0" }, 88 { "Bad 1SV\0" }, { "0SV Usable\0" }, { "1SV Usable\0" }, 89 { "2SV Usable\0" }, { "3SV Usable\0" }, { "No Integrity\0" }, 90 { "Diff Corr\0" }, { "Overdet Clock\0" }, { "Invalid\0" } }; 91 #endif 92 93 /* 94 * Transfer vector 95 */ 96 struct refclock refclock_palisade = { 97 palisade_start, /* start up driver */ 98 palisade_shutdown, /* shut down driver */ 99 palisade_poll, /* transmit poll message */ 100 noentry, /* not used */ 101 noentry, /* initialize driver (not used) */ 102 noentry, /* not used */ 103 NOFLAGS /* not used */ 104 }; 105 106 static int decode_date(struct refclockproc *pp, const char *cp); 107 108 /* Extract the clock type from the mode setting */ 109 #define CLK_TYPE(x) ((int)(((x)->ttl) & 0x7F)) 110 111 /* Supported clock types */ 112 #define CLK_TRIMBLE 0 /* Trimble Palisade */ 113 #define CLK_PRAECIS 1 /* Endrun Technologies Praecis */ 114 #define CLK_THUNDERBOLT 2 /* Trimble Thunderbolt GPS Receiver */ 115 #define CLK_ACUTIME 3 /* Trimble Acutime Gold */ 116 #define CLK_ACUTIMEB 4 /* Trimble Actutime Gold Port B */ 117 118 int praecis_msg; 119 static void praecis_parse(struct recvbuf *rbufp, struct peer *peer); 120 121 /* These routines are for sending packets to the Thunderbolt receiver 122 * They are taken from Markus Prosch 123 */ 124 125 #ifdef PALISADE_SENDCMD_RESURRECTED 126 /* 127 * sendcmd - Build data packet for sending 128 */ 129 static void 130 sendcmd ( 131 struct packettx *buffer, 132 int c 133 ) 134 { 135 *buffer->data = DLE; 136 *(buffer->data + 1) = (unsigned char)c; 137 buffer->size = 2; 138 } 139 #endif /* PALISADE_SENDCMD_RESURRECTED */ 140 141 /* 142 * sendsupercmd - Build super data packet for sending 143 */ 144 static void 145 sendsupercmd ( 146 struct packettx *buffer, 147 int c1, 148 int c2 149 ) 150 { 151 *buffer->data = DLE; 152 *(buffer->data + 1) = (unsigned char)c1; 153 *(buffer->data + 2) = (unsigned char)c2; 154 buffer->size = 3; 155 } 156 157 /* 158 * sendbyte - 159 */ 160 static void 161 sendbyte ( 162 struct packettx *buffer, 163 int b 164 ) 165 { 166 if (b == DLE) 167 *(buffer->data+buffer->size++) = DLE; 168 *(buffer->data+buffer->size++) = (unsigned char)b; 169 } 170 171 /* 172 * sendint - 173 */ 174 static void 175 sendint ( 176 struct packettx *buffer, 177 int a 178 ) 179 { 180 sendbyte(buffer, (unsigned char)((a>>8) & 0xff)); 181 sendbyte(buffer, (unsigned char)(a & 0xff)); 182 } 183 184 /* 185 * sendetx - Send packet or super packet to the device 186 */ 187 static int 188 sendetx ( 189 struct packettx *buffer, 190 int fd 191 ) 192 { 193 int result; 194 195 *(buffer->data+buffer->size++) = DLE; 196 *(buffer->data+buffer->size++) = ETX; 197 result = write(fd, buffer->data, (unsigned long)buffer->size); 198 199 if (result != -1) 200 return (result); 201 else 202 return (-1); 203 } 204 205 /* 206 * init_thunderbolt - Prepares Thunderbolt receiver to be used with 207 * NTP (also taken from Markus Prosch). 208 */ 209 static void 210 init_thunderbolt ( 211 int fd 212 ) 213 { 214 struct packettx tx; 215 216 tx.size = 0; 217 tx.data = (u_char *) emalloc(100); 218 219 /* set UTC time */ 220 sendsupercmd (&tx, 0x8E, 0xA2); 221 sendbyte (&tx, 0x3); 222 sendetx (&tx, fd); 223 224 /* activate packets 0x8F-AB and 0x8F-AC */ 225 sendsupercmd (&tx, 0x8E, 0xA5); 226 sendint (&tx, 0x5); 227 sendetx (&tx, fd); 228 229 free(tx.data); 230 } 231 232 /* 233 * init_acutime - Prepares Acutime Receiver to be used with NTP 234 */ 235 static void 236 init_acutime ( 237 int fd 238 ) 239 { 240 /* Disable all outputs, Enable Event-Polling on PortA so 241 we can ask for time packets */ 242 struct packettx tx; 243 244 tx.size = 0; 245 tx.data = (u_char *) emalloc(100); 246 247 sendsupercmd(&tx, 0x8E, 0xA5); 248 sendbyte(&tx, 0x02); 249 sendbyte(&tx, 0x00); 250 sendbyte(&tx, 0x00); 251 sendbyte(&tx, 0x00); 252 sendetx(&tx, fd); 253 254 free(tx.data); 255 } 256 257 /* 258 * palisade_start - open the devices and initialize data for processing 259 */ 260 static int 261 palisade_start ( 262 int unit, 263 struct peer *peer 264 ) 265 { 266 struct palisade_unit *up; 267 struct refclockproc *pp; 268 int fd; 269 char gpsdev[20]; 270 struct termios tio; 271 272 snprintf(gpsdev, sizeof(gpsdev), DEVICE, unit); 273 274 /* 275 * Open serial port. 276 */ 277 fd = refclock_open(gpsdev, SPEED232, LDISC_RAW); 278 if (fd <= 0) { 279 #ifdef DEBUG 280 printf("Palisade(%d) start: open %s failed\n", unit, gpsdev); 281 #endif 282 return 0; 283 } 284 285 msyslog(LOG_NOTICE, "Palisade(%d) fd: %d dev: %s", unit, fd, 286 gpsdev); 287 288 if (tcgetattr(fd, &tio) < 0) { 289 msyslog(LOG_ERR, 290 "Palisade(%d) tcgetattr(fd, &tio): %m",unit); 291 #ifdef DEBUG 292 printf("Palisade(%d) tcgetattr(fd, &tio)\n",unit); 293 #endif 294 close(fd); 295 return (0); 296 } 297 298 tio.c_cflag |= (PARENB|PARODD); 299 tio.c_iflag &= ~ICRNL; 300 301 /* 302 * Allocate and initialize unit structure 303 */ 304 up = emalloc_zero(sizeof(*up)); 305 306 up->type = CLK_TYPE(peer); 307 switch (up->type) { 308 case CLK_TRIMBLE: 309 /* Normal mode, do nothing */ 310 break; 311 case CLK_PRAECIS: 312 msyslog(LOG_NOTICE, "Palisade(%d) Praecis mode enabled" 313 ,unit); 314 break; 315 case CLK_THUNDERBOLT: 316 msyslog(LOG_NOTICE, "Palisade(%d) Thunderbolt mode enabled" 317 ,unit); 318 tio.c_cflag = (CS8|CLOCAL|CREAD); 319 break; 320 case CLK_ACUTIME: 321 msyslog(LOG_NOTICE, "Palisade(%d) Acutime Gold mode enabled" 322 ,unit); 323 break; 324 default: 325 msyslog(LOG_NOTICE, "Palisade(%d) mode unknown",unit); 326 break; 327 } 328 if (tcsetattr(fd, TCSANOW, &tio) == -1) { 329 msyslog(LOG_ERR, "Palisade(%d) tcsetattr(fd, &tio): %m",unit); 330 #ifdef DEBUG 331 printf("Palisade(%d) tcsetattr(fd, &tio)\n",unit); 332 #endif 333 close(fd); 334 free(up); 335 return 0; 336 } 337 338 pp = peer->procptr; 339 pp->io.clock_recv = palisade_io; 340 pp->io.srcclock = peer; 341 pp->io.datalen = 0; 342 pp->io.fd = fd; 343 if (!io_addclock(&pp->io)) { 344 #ifdef DEBUG 345 printf("Palisade(%d) io_addclock\n",unit); 346 #endif 347 close(fd); 348 pp->io.fd = -1; 349 free(up); 350 return (0); 351 } 352 353 /* 354 * Initialize miscellaneous variables 355 */ 356 pp->unitptr = up; 357 pp->clockdesc = DESCRIPTION; 358 359 peer->precision = PRECISION; 360 peer->sstclktype = CTL_SST_TS_UHF; 361 peer->minpoll = TRMB_MINPOLL; 362 peer->maxpoll = TRMB_MAXPOLL; 363 memcpy((char *)&pp->refid, REFID, 4); 364 365 up->leap_status = 0; 366 up->unit = (short) unit; 367 up->rpt_status = TSIP_PARSED_EMPTY; 368 up->rpt_cnt = 0; 369 370 if (up->type == CLK_THUNDERBOLT) 371 init_thunderbolt(fd); 372 if (up->type == CLK_ACUTIME) 373 init_acutime(fd); 374 375 return 1; 376 } 377 378 379 /* 380 * palisade_shutdown - shut down the clock 381 */ 382 static void 383 palisade_shutdown ( 384 int unit, 385 struct peer *peer 386 ) 387 { 388 struct palisade_unit *up; 389 struct refclockproc *pp; 390 pp = peer->procptr; 391 up = pp->unitptr; 392 if (-1 != pp->io.fd) 393 io_closeclock(&pp->io); 394 if (NULL != up) 395 free(up); 396 } 397 398 399 /* 400 * unpack helpers 401 */ 402 403 static inline uint8_t 404 get_u8( 405 const char *cp) 406 { 407 return ((const u_char*)cp)[0]; 408 } 409 410 static inline uint16_t 411 get_u16( 412 const char *cp) 413 { 414 return ((uint16_t)get_u8(cp) << 8) | get_u8(cp + 1); 415 } 416 417 /* 418 * unpack & fix date (the receiver provides a valid time for 1024 weeks 419 * after 1997-12-14 and therefore folds back in 2017, 2037,...) 420 * 421 * Returns -1 on error, day-of-month + (month * 32) othertwise. 422 */ 423 int 424 decode_date( 425 struct refclockproc *pp, 426 const char *cp) 427 { 428 static int32_t s_baseday = 0; 429 430 struct calendar jd; 431 int32_t rd; 432 433 if (0 == s_baseday) { 434 if (!ntpcal_get_build_date(&jd)) { 435 jd.year = 2015; 436 jd.month = 1; 437 jd.monthday = 1; 438 } 439 s_baseday = ntpcal_date_to_rd(&jd); 440 } 441 442 /* get date fields and convert to RDN */ 443 jd.monthday = get_u8 ( cp ); 444 jd.month = get_u8 (cp + 1); 445 jd.year = get_u16(cp + 2); 446 rd = ntpcal_date_to_rd(&jd); 447 448 /* for the paranoid: do reverse calculation and cross-check */ 449 ntpcal_rd_to_date(&jd, rd); 450 if ((jd.monthday != get_u8 ( cp )) || 451 (jd.month != get_u8 (cp + 1)) || 452 (jd.year != get_u16(cp + 2)) ) 453 return - 1; 454 455 /* calculate cycle shift to base day and calculate re-folded 456 * date 457 * 458 * One could do a proper modulo calculation here, but a counting 459 * loop is probably faster for the next few rollovers... 460 */ 461 while (rd < s_baseday) 462 rd += 7*1024; 463 ntpcal_rd_to_date(&jd, rd); 464 465 /* fill refclock structure & indicate success */ 466 pp->day = jd.yearday; 467 pp->year = jd.year; 468 return ((int)jd.month << 5) | jd.monthday; 469 } 470 471 472 /* 473 * TSIP_decode - decode the TSIP data packets 474 */ 475 int 476 TSIP_decode ( 477 struct peer *peer 478 ) 479 { 480 int st; 481 long secint; 482 double secs; 483 double secfrac; 484 unsigned short event = 0; 485 int mmday; 486 487 struct palisade_unit *up; 488 struct refclockproc *pp; 489 490 pp = peer->procptr; 491 up = pp->unitptr; 492 493 /* 494 * Check the time packet, decode its contents. 495 * If the timecode has invalid length or is not in 496 * proper format, declare bad format and exit. 497 */ 498 499 if ((up->type != CLK_THUNDERBOLT) & (up->type != CLK_ACUTIME)){ 500 if ((up->rpt_buf[0] == (char) 0x41) || 501 (up->rpt_buf[0] == (char) 0x46) || 502 (up->rpt_buf[0] == (char) 0x54) || 503 (up->rpt_buf[0] == (char) 0x4B) || 504 (up->rpt_buf[0] == (char) 0x6D)) { 505 506 /* standard time packet - GPS time and GPS week number */ 507 #ifdef DEBUG 508 printf("Palisade Port B packets detected. Connect to Port A\n"); 509 #endif 510 511 return 0; 512 } 513 } 514 515 /* 516 * We cast both to u_char to as 0x8f uses the sign bit on a char 517 */ 518 if ((u_char) up->rpt_buf[0] == (u_char) 0x8f) { 519 /* 520 * Superpackets 521 */ 522 event = (unsigned short) (getint((u_char *) &mb(1)) & 0xffff); 523 if (!((pp->sloppyclockflag & CLK_FLAG2) || event)) 524 /* Ignore Packet */ 525 return 0; 526 527 switch (mb(0) & 0xff) { 528 int GPS_UTC_Offset; 529 long tow; 530 531 case PACKET_8F0B: 532 533 if (up->polled <= 0) 534 return 0; 535 536 if (up->rpt_cnt != LENCODE_8F0B) /* check length */ 537 break; 538 539 #ifdef DEBUG 540 if (debug > 1) { 541 int ts; 542 double lat, lon, alt; 543 lat = getdbl((u_char *) &mb(42)) * R2D; 544 lon = getdbl((u_char *) &mb(50)) * R2D; 545 alt = getdbl((u_char *) &mb(58)); 546 547 printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n", 548 up->unit, lat,lon,alt); 549 printf("TSIP_decode: unit %d: Sats:", 550 up->unit); 551 for (st = 66, ts = 0; st <= 73; st++) 552 if (mb(st)) { 553 if (mb(st) > 0) ts++; 554 printf(" %02d", mb(st)); 555 } 556 printf(" : Tracking %d\n", ts); 557 } 558 #endif 559 560 GPS_UTC_Offset = getint((u_char *) &mb(16)); 561 if (GPS_UTC_Offset == 0) { /* Check UTC offset */ 562 #ifdef DEBUG 563 printf("TSIP_decode: UTC Offset Unknown\n"); 564 #endif 565 break; 566 } 567 568 secs = getdbl((u_char *) &mb(3)); 569 secint = (long) secs; 570 secfrac = secs - secint; /* 0.0 <= secfrac < 1.0 */ 571 572 pp->nsec = (long) (secfrac * 1000000000); 573 574 secint %= 86400; /* Only care about today */ 575 pp->hour = secint / 3600; 576 secint %= 3600; 577 pp->minute = secint / 60; 578 secint %= 60; 579 pp->second = secint % 60; 580 581 mmday = decode_date(pp, &mb(11)); 582 if (mmday < 0) 583 break; 584 585 #ifdef DEBUG 586 if (debug > 1) 587 printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d UTC %02d\n", 588 up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, 589 pp->second, pp->nsec, (mmday >> 5), (mmday & 31), pp->year, GPS_UTC_Offset); 590 #endif 591 /* Only use this packet when no 592 * 8F-AD's are being received 593 */ 594 595 if (up->leap_status) { 596 up->leap_status = 0; 597 return 0; 598 } 599 600 return 2; 601 break; 602 603 case PACKET_NTP: 604 /* Palisade-NTP Packet */ 605 606 if (up->rpt_cnt != LENCODE_NTP) /* check length */ 607 break; 608 609 up->leap_status = mb(19); 610 611 if (up->polled <= 0) 612 return 0; 613 614 /* Check Tracking Status */ 615 st = mb(18); 616 if (st < 0 || st > 14) 617 st = 14; 618 if ((st >= 2 && st <= 7) || st == 11 || st == 12) { 619 #ifdef DEBUG 620 printf("TSIP_decode: Not Tracking Sats : %s\n", 621 *Tracking_Status[st]); 622 #endif 623 refclock_report(peer, CEVNT_BADTIME); 624 up->polled = -1; 625 return 0; 626 break; 627 } 628 629 mmday = decode_date(pp, &mb(14)); 630 if (mmday < 0) 631 break; 632 up->month = (mmday >> 5); /* Save for LEAP check */ 633 634 if ( (up->leap_status & PALISADE_LEAP_PENDING) && 635 /* Avoid early announce: https://bugs.ntp.org/2773 */ 636 (6 == up->month || 12 == up->month) ) { 637 if (up->leap_status & PALISADE_UTC_TIME) 638 pp->leap = LEAP_ADDSECOND; 639 else 640 pp->leap = LEAP_DELSECOND; 641 } 642 else if (up->leap_status) 643 pp->leap = LEAP_NOWARNING; 644 645 else { /* UTC flag is not set: 646 * Receiver may have been reset, and lost 647 * its UTC almanac data */ 648 pp->leap = LEAP_NOTINSYNC; 649 #ifdef DEBUG 650 printf("TSIP_decode: UTC Almanac unavailable: %d\n", 651 mb(19)); 652 #endif 653 refclock_report(peer, CEVNT_BADTIME); 654 up->polled = -1; 655 return 0; 656 } 657 658 pp->nsec = (long) (getdbl((u_char *) &mb(3)) 659 * 1000000000); 660 661 pp->hour = mb(11); 662 pp->minute = mb(12); 663 pp->second = mb(13); 664 665 #ifdef DEBUG 666 if (debug > 1) 667 printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d UTC %02x %s\n", 668 up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, 669 pp->second, pp->nsec, (mmday >> 5), (mmday & 31), pp->year, 670 mb(19), *Tracking_Status[st]); 671 #endif 672 return 1; 673 break; 674 675 case PACKET_8FAC: 676 if (up->polled <= 0) 677 return 0; 678 679 if (up->rpt_cnt != LENCODE_8FAC)/* check length */ 680 break; 681 682 #ifdef DEBUG 683 if (debug > 1) { 684 double lat, lon, alt; 685 lat = getdbl((u_char *) &mb(36)) * R2D; 686 lon = getdbl((u_char *) &mb(44)) * R2D; 687 alt = getdbl((u_char *) &mb(52)); 688 689 printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n", 690 up->unit, lat,lon,alt); 691 printf("TSIP_decode: unit %d\n", up->unit); 692 } 693 #endif 694 if ( (getint((u_char *) &mb(10)) & 0x80) && 695 /* Avoid early announce: https://bugs.ntp.org/2773 */ 696 (6 == up->month || 12 == up->month) ) 697 pp->leap = LEAP_ADDSECOND; /* we ASSUME addsecond */ 698 else 699 pp->leap = LEAP_NOWARNING; 700 701 #ifdef DEBUG 702 if (debug > 1) 703 printf("TSIP_decode: unit %d: 0x%02x leap %d\n", 704 up->unit, mb(0) & 0xff, pp->leap); 705 if (debug > 1) { 706 printf("Receiver MODE: 0x%02X\n", (u_char)mb(1)); 707 if (mb(1) == 0x00) 708 printf(" AUTOMATIC\n"); 709 if (mb(1) == 0x01) 710 printf(" SINGLE SATELLITE\n"); 711 if (mb(1) == 0x03) 712 printf(" HORIZONTAL(2D)\n"); 713 if (mb(1) == 0x04) 714 printf(" FULL POSITION(3D)\n"); 715 if (mb(1) == 0x05) 716 printf(" DGPR REFERENCE\n"); 717 if (mb(1) == 0x06) 718 printf(" CLOCK HOLD(2D)\n"); 719 if (mb(1) == 0x07) 720 printf(" OVERDETERMINED CLOCK\n"); 721 722 printf("\n** Disciplining MODE 0x%02X:\n", (u_char)mb(2)); 723 if (mb(2) == 0x00) 724 printf(" NORMAL\n"); 725 if (mb(2) == 0x01) 726 printf(" POWER-UP\n"); 727 if (mb(2) == 0x02) 728 printf(" AUTO HOLDOVER\n"); 729 if (mb(2) == 0x03) 730 printf(" MANUAL HOLDOVER\n"); 731 if (mb(2) == 0x04) 732 printf(" RECOVERY\n"); 733 if (mb(2) == 0x06) 734 printf(" DISCIPLINING DISABLED\n"); 735 } 736 #endif 737 return 0; 738 break; 739 740 case PACKET_8FAB: 741 /* Thunderbolt Primary Timing Packet */ 742 743 if (up->rpt_cnt != LENCODE_8FAB) /* check length */ 744 break; 745 746 if (up->polled <= 0) 747 return 0; 748 749 GPS_UTC_Offset = getint((u_char *) &mb(7)); 750 751 if (GPS_UTC_Offset == 0){ /* Check UTC Offset */ 752 #ifdef DEBUG 753 printf("TSIP_decode: UTC Offset Unknown\n"); 754 #endif 755 break; 756 } 757 758 759 if ((mb(9) & 0x1d) == 0x0) { 760 /* if we know the GPS time and the UTC offset, 761 we expect UTC timing information !!! */ 762 763 pp->leap = LEAP_NOTINSYNC; 764 refclock_report(peer, CEVNT_BADTIME); 765 up->polled = -1; 766 return 0; 767 } 768 769 pp->nsec = 0; 770 #ifdef DEBUG 771 printf("\nTiming Flags are:\n"); 772 printf("Timing flag value is: 0x%X\n", mb(9)); 773 if ((mb(9) & 0x01) != 0) 774 printf (" Getting UTC time\n"); 775 else 776 printf (" Getting GPS time\n"); 777 if ((mb(9) & 0x02) != 0) 778 printf (" PPS is from UTC\n"); 779 else 780 printf (" PPS is from GPS\n"); 781 if ((mb(9) & 0x04) != 0) 782 printf (" Time is not Set\n"); 783 else 784 printf (" Time is Set\n"); 785 if ((mb(9) & 0x08) != 0) 786 printf(" I dont have UTC info\n"); 787 else 788 printf (" I have UTC info\n"); 789 if ((mb(9) & 0x10) != 0) 790 printf (" Time is from USER\n\n"); 791 else 792 printf (" Time is from GPS\n\n"); 793 #endif 794 795 mmday = decode_date(pp, &mb(13)); 796 if (mmday < 0) 797 break; 798 tow = getlong((u_char *) &mb(1)); 799 #ifdef DEBUG 800 if (debug > 1) { 801 printf("pp->day: %d\n", pp->day); 802 printf("TOW: %ld\n", tow); 803 printf("DAY: %d\n", (mmday & 31)); 804 } 805 #endif 806 pp->hour = mb(12); 807 pp->minute = mb(11); 808 pp->second = mb(10); 809 810 811 #ifdef DEBUG 812 if (debug > 1) 813 printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d ", 814 up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, pp->second, 815 pp->nsec, (mmday >> 5), (mmday & 31), pp->year); 816 #endif 817 return 1; 818 break; 819 820 default: 821 /* Ignore Packet */ 822 return 0; 823 } /* switch */ 824 } /* if 8F packets */ 825 826 else if (up->rpt_buf[0] == (u_char)0x42) { 827 printf("0x42\n"); 828 return 0; 829 } 830 else if (up->rpt_buf[0] == (u_char)0x43) { 831 printf("0x43\n"); 832 return 0; 833 } 834 else if ((up->rpt_buf[0] == PACKET_41) & (up->type == CLK_THUNDERBOLT)){ 835 printf("Undocumented 0x41 packet on Thunderbolt\n"); 836 return 0; 837 } 838 else if ((up->rpt_buf[0] == PACKET_41A) & (up->type == CLK_ACUTIME)) { 839 #ifdef DEBUG 840 printf("GPS TOW: %ld\n", (long)getlong((u_char *) &mb(0))); 841 printf("GPS WN: %d\n", getint((u_char *) &mb(4))); 842 printf("GPS UTC-GPS Offser: %ld\n", (long)getlong((u_char *) &mb(6))); 843 #endif 844 return 0; 845 } 846 847 /* Health Status for Acutime Receiver */ 848 else if ((up->rpt_buf[0] == PACKET_46) & (up->type == CLK_ACUTIME)) { 849 #ifdef DEBUG 850 if (debug > 1) 851 /* Status Codes */ 852 switch (mb(0)) { 853 case 0x00: 854 printf ("Doing Position Fixes\n"); 855 break; 856 case 0x01: 857 printf ("Do no have GPS time yet\n"); 858 break; 859 case 0x03: 860 printf ("PDOP is too high\n"); 861 break; 862 case 0x08: 863 printf ("No usable satellites\n"); 864 break; 865 case 0x09: 866 printf ("Only 1 usable satellite\n"); 867 break; 868 case 0x0A: 869 printf ("Only 2 usable satellites\n"); 870 break; 871 case 0x0B: 872 printf ("Only 3 usable satellites\n"); 873 break; 874 case 0x0C: 875 printf("The Chosen satellite is unusable\n"); 876 break; 877 } 878 #endif 879 /* Error Codes */ 880 if (mb(1) != 0) { 881 882 refclock_report(peer, CEVNT_BADTIME); 883 up->polled = -1; 884 #ifdef DEBUG 885 if (debug > 1) { 886 if (mb(1) & 0x01) 887 printf ("Signal Processor Error, reset unit.\n"); 888 if (mb(1) & 0x02) 889 printf ("Alignment error, channel or chip 1, reset unit.\n"); 890 if (mb(1) & 0x03) 891 printf ("Alignment error, channel or chip 2, reset unit.\n"); 892 if (mb(1) & 0x04) 893 printf ("Antenna feed line fault (open or short)\n"); 894 if (mb(1) & 0x05) 895 printf ("Excessive reference frequency error, refer to packet 0x2D and packet 0x4D documentation for further information\n"); 896 } 897 #endif 898 899 return 0; 900 } 901 } 902 else if (up->rpt_buf[0] == 0x54) 903 return 0; 904 905 else if (up->rpt_buf[0] == PACKET_6D) { 906 #ifdef DEBUG 907 int sats; 908 909 if ((mb(0) & 0x01) && (mb(0) & 0x02)) 910 printf("2d Fix Dimension\n"); 911 if (mb(0) & 0x04) 912 printf("3d Fix Dimension\n"); 913 914 if (mb(0) & 0x08) 915 printf("Fix Mode is MANUAL\n"); 916 else 917 printf("Fix Mode is AUTO\n"); 918 919 sats = mb(0) & 0xF0; 920 sats = sats >> 4; 921 printf("Tracking %d Satellites\n", sats); 922 #endif 923 return 0; 924 } /* else if not super packet */ 925 refclock_report(peer, CEVNT_BADREPLY); 926 up->polled = -1; 927 #ifdef DEBUG 928 printf("TSIP_decode: unit %d: bad packet %02x-%02x event %d len %d\n", 929 up->unit, up->rpt_buf[0] & 0xff, mb(0) & 0xff, 930 event, up->rpt_cnt); 931 #endif 932 return 0; 933 } 934 935 /* 936 * palisade__receive - receive data from the serial interface 937 */ 938 939 static void 940 palisade_receive ( 941 struct peer * peer 942 ) 943 { 944 struct palisade_unit *up; 945 struct refclockproc *pp; 946 947 /* 948 * Initialize pointers and read the timecode and timestamp. 949 */ 950 pp = peer->procptr; 951 up = pp->unitptr; 952 953 if (! TSIP_decode(peer)) return; 954 955 if (up->polled <= 0) 956 return; /* no poll pending, already received or timeout */ 957 958 up->polled = 0; /* Poll reply received */ 959 pp->lencode = 0; /* clear time code */ 960 #ifdef DEBUG 961 if (debug) 962 printf( 963 "palisade_receive: unit %d: %4d %03d %02d:%02d:%02d.%09ld\n", 964 up->unit, pp->year, pp->day, pp->hour, pp->minute, 965 pp->second, pp->nsec); 966 #endif 967 968 /* 969 * Process the sample 970 * Generate timecode: YYYY DoY HH:MM:SS.microsec 971 * report and process 972 */ 973 974 snprintf(pp->a_lastcode, sizeof(pp->a_lastcode), 975 "%4d %03d %02d:%02d:%02d.%09ld", 976 pp->year, pp->day, 977 pp->hour,pp->minute, pp->second, pp->nsec); 978 pp->lencode = 24; 979 980 if (!refclock_process(pp)) { 981 refclock_report(peer, CEVNT_BADTIME); 982 983 #ifdef DEBUG 984 printf("palisade_receive: unit %d: refclock_process failed!\n", 985 up->unit); 986 #endif 987 return; 988 } 989 990 record_clock_stats(&peer->srcadr, pp->a_lastcode); 991 992 #ifdef DEBUG 993 if (debug) 994 printf("palisade_receive: unit %d: %s\n", 995 up->unit, prettydate(&pp->lastrec)); 996 #endif 997 pp->lastref = pp->lastrec; 998 refclock_receive(peer); 999 } 1000 1001 1002 /* 1003 * palisade_poll - called by the transmit procedure 1004 * 1005 */ 1006 static void 1007 palisade_poll ( 1008 int unit, 1009 struct peer *peer 1010 ) 1011 { 1012 struct palisade_unit *up; 1013 struct refclockproc *pp; 1014 1015 pp = peer->procptr; 1016 up = pp->unitptr; 1017 1018 pp->polls++; 1019 if (up->polled > 0) /* last reply never arrived or error */ 1020 refclock_report(peer, CEVNT_TIMEOUT); 1021 1022 up->polled = 2; /* synchronous packet + 1 event */ 1023 1024 #ifdef DEBUG 1025 if (debug) 1026 printf("palisade_poll: unit %d: polling %s\n", unit, 1027 (pp->sloppyclockflag & CLK_FLAG2) ? 1028 "synchronous packet" : "event"); 1029 #endif 1030 1031 if (pp->sloppyclockflag & CLK_FLAG2) 1032 return; /* using synchronous packet input */ 1033 1034 if(up->type == CLK_PRAECIS) { 1035 if(write(peer->procptr->io.fd,"SPSTAT\r\n",8) < 0) 1036 msyslog(LOG_ERR, "Palisade(%d) write: %m:",unit); 1037 else { 1038 praecis_msg = 1; 1039 return; 1040 } 1041 } 1042 1043 if (HW_poll(pp) < 0) 1044 refclock_report(peer, CEVNT_FAULT); 1045 } 1046 1047 static void 1048 praecis_parse ( 1049 struct recvbuf *rbufp, 1050 struct peer *peer 1051 ) 1052 { 1053 static char buf[100]; 1054 static int p = 0; 1055 struct refclockproc *pp; 1056 1057 pp = peer->procptr; 1058 1059 memcpy(buf+p,rbufp->recv_space.X_recv_buffer, rbufp->recv_length); 1060 p += rbufp->recv_length; 1061 1062 if(buf[p-2] == '\r' && buf[p-1] == '\n') { 1063 buf[p-2] = '\0'; 1064 record_clock_stats(&peer->srcadr, buf); 1065 1066 p = 0; 1067 praecis_msg = 0; 1068 1069 if (HW_poll(pp) < 0) 1070 refclock_report(peer, CEVNT_FAULT); 1071 1072 } 1073 } 1074 1075 static void 1076 palisade_io ( 1077 struct recvbuf *rbufp 1078 ) 1079 { 1080 /* 1081 * Initialize pointers and read the timecode and timestamp. 1082 */ 1083 struct palisade_unit *up; 1084 struct refclockproc *pp; 1085 struct peer *peer; 1086 1087 char * c, * d; 1088 1089 peer = rbufp->recv_peer; 1090 pp = peer->procptr; 1091 up = pp->unitptr; 1092 1093 if(up->type == CLK_PRAECIS) { 1094 if(praecis_msg) { 1095 praecis_parse(rbufp,peer); 1096 return; 1097 } 1098 } 1099 1100 c = (char *) &rbufp->recv_space; 1101 d = c + rbufp->recv_length; 1102 1103 while (c != d) { 1104 1105 /* Build time packet */ 1106 switch (up->rpt_status) { 1107 1108 case TSIP_PARSED_DLE_1: 1109 switch (*c) 1110 { 1111 case 0: 1112 case DLE: 1113 case ETX: 1114 up->rpt_status = TSIP_PARSED_EMPTY; 1115 break; 1116 1117 default: 1118 up->rpt_status = TSIP_PARSED_DATA; 1119 /* save packet ID */ 1120 up->rpt_buf[0] = *c; 1121 break; 1122 } 1123 break; 1124 1125 case TSIP_PARSED_DATA: 1126 if (*c == DLE) 1127 up->rpt_status = TSIP_PARSED_DLE_2; 1128 else 1129 mb(up->rpt_cnt++) = *c; 1130 break; 1131 1132 case TSIP_PARSED_DLE_2: 1133 if (*c == DLE) { 1134 up->rpt_status = TSIP_PARSED_DATA; 1135 mb(up->rpt_cnt++) = 1136 *c; 1137 } 1138 else if (*c == ETX) 1139 up->rpt_status = TSIP_PARSED_FULL; 1140 else { 1141 /* error: start new report packet */ 1142 up->rpt_status = TSIP_PARSED_DLE_1; 1143 up->rpt_buf[0] = *c; 1144 } 1145 break; 1146 1147 case TSIP_PARSED_FULL: 1148 case TSIP_PARSED_EMPTY: 1149 default: 1150 if ( *c != DLE) 1151 up->rpt_status = TSIP_PARSED_EMPTY; 1152 else 1153 up->rpt_status = TSIP_PARSED_DLE_1; 1154 break; 1155 } 1156 1157 c++; 1158 1159 if (up->rpt_status == TSIP_PARSED_DLE_1) { 1160 up->rpt_cnt = 0; 1161 if (pp->sloppyclockflag & CLK_FLAG2) 1162 /* stamp it */ 1163 get_systime(&pp->lastrec); 1164 } 1165 else if (up->rpt_status == TSIP_PARSED_EMPTY) 1166 up->rpt_cnt = 0; 1167 1168 else if (up->rpt_cnt > BMAX) 1169 up->rpt_status =TSIP_PARSED_EMPTY; 1170 1171 if (up->rpt_status == TSIP_PARSED_FULL) 1172 palisade_receive(peer); 1173 1174 } /* while chars in buffer */ 1175 } 1176 1177 1178 /* 1179 * Trigger the Palisade's event input, which is driven off the RTS 1180 * 1181 * Take a system time stamp to match the GPS time stamp. 1182 * 1183 */ 1184 long 1185 HW_poll ( 1186 struct refclockproc * pp /* pointer to unit structure */ 1187 ) 1188 { 1189 int x; /* state before & after RTS set */ 1190 struct palisade_unit *up; 1191 1192 up = pp->unitptr; 1193 1194 /* read the current status, so we put things back right */ 1195 if (ioctl(pp->io.fd, TIOCMGET, &x) < 0) { 1196 DPRINTF(1, ("Palisade HW_poll: unit %d: GET %m\n", 1197 up->unit)); 1198 msyslog(LOG_ERR, "Palisade(%d) HW_poll: ioctl(fd,GET): %m", 1199 up->unit); 1200 return -1; 1201 } 1202 1203 x |= TIOCM_RTS; /* turn on RTS */ 1204 1205 /* Edge trigger */ 1206 if (up->type == CLK_ACUTIME) 1207 write (pp->io.fd, "", 1); 1208 1209 if (ioctl(pp->io.fd, TIOCMSET, &x) < 0) { 1210 #ifdef DEBUG 1211 if (debug) 1212 printf("Palisade HW_poll: unit %d: SET \n", up->unit); 1213 #endif 1214 msyslog(LOG_ERR, 1215 "Palisade(%d) HW_poll: ioctl(fd, SET, RTS_on): %m", 1216 up->unit); 1217 return -1; 1218 } 1219 1220 x &= ~TIOCM_RTS; /* turn off RTS */ 1221 1222 /* poll timestamp */ 1223 get_systime(&pp->lastrec); 1224 1225 if (ioctl(pp->io.fd, TIOCMSET, &x) == -1) { 1226 #ifdef DEBUG 1227 if (debug) 1228 printf("Palisade HW_poll: unit %d: UNSET \n", up->unit); 1229 #endif 1230 msyslog(LOG_ERR, 1231 "Palisade(%d) HW_poll: ioctl(fd, UNSET, RTS_off): %m", 1232 up->unit); 1233 return -1; 1234 } 1235 1236 return 0; 1237 } 1238 1239 /* 1240 * copy/swap a big-endian palisade double into a host double 1241 */ 1242 static double 1243 getdbl ( 1244 u_char *bp 1245 ) 1246 { 1247 #ifdef WORDS_BIGENDIAN 1248 double out; 1249 1250 memcpy(&out, bp, sizeof(out)); 1251 return out; 1252 #else 1253 union { 1254 u_char ch[8]; 1255 u_int32 u32[2]; 1256 } ui; 1257 1258 union { 1259 double out; 1260 u_int32 u32[2]; 1261 } uo; 1262 1263 memcpy(ui.ch, bp, sizeof(ui.ch)); 1264 /* least-significant 32 bits of double from swapped bp[4] to bp[7] */ 1265 uo.u32[0] = ntohl(ui.u32[1]); 1266 /* most-significant 32 bits from swapped bp[0] to bp[3] */ 1267 uo.u32[1] = ntohl(ui.u32[0]); 1268 1269 return uo.out; 1270 #endif 1271 } 1272 1273 /* 1274 * copy/swap a big-endian palisade short into a host short 1275 */ 1276 static short 1277 getint ( 1278 u_char *bp 1279 ) 1280 { 1281 u_short us; 1282 1283 memcpy(&us, bp, sizeof(us)); 1284 return (short)ntohs(us); 1285 } 1286 1287 /* 1288 * copy/swap a big-endian palisade 32-bit int into a host 32-bit int 1289 */ 1290 static int32 1291 getlong( 1292 u_char *bp 1293 ) 1294 { 1295 u_int32 u32; 1296 1297 memcpy(&u32, bp, sizeof(u32)); 1298 return (int32)(u_int32)ntohl(u32); 1299 } 1300 1301 #else /* REFCLOCK && CLOCK_PALISADE*/ 1302 int refclock_palisade_c_notempty; 1303 #endif 1304