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