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