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 *) 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 */ 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 *) 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 */ 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 if (up->leap_status & PALISADE_LEAP_PENDING) { 588 if (up->leap_status & PALISADE_UTC_TIME) 589 pp->leap = LEAP_ADDSECOND; 590 else 591 pp->leap = LEAP_DELSECOND; 592 } 593 else if (up->leap_status) 594 pp->leap = LEAP_NOWARNING; 595 596 else { /* UTC flag is not set: 597 * Receiver may have been reset, and lost 598 * its UTC almanac data */ 599 pp->leap = LEAP_NOTINSYNC; 600 #ifdef DEBUG 601 printf("TSIP_decode: UTC Almanac unavailable: %d\n", 602 mb(19)); 603 #endif 604 refclock_report(peer, CEVNT_BADTIME); 605 up->polled = -1; 606 return 0; 607 } 608 609 pp->nsec = (long) (getdbl((u_char *) &mb(3)) 610 * 1000000000); 611 612 if ((pp->day = day_of_year(&mb(14))) < 0) 613 break; 614 pp->year = getint((u_char *) &mb(16)); 615 pp->hour = mb(11); 616 pp->minute = mb(12); 617 pp->second = mb(13); 618 619 #ifdef DEBUG 620 if (debug > 1) 621 printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d UTC %02x %s\n", 622 up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, 623 pp->second, pp->nsec, mb(15), mb(14), pp->year, 624 mb(19), *Tracking_Status[st]); 625 #endif 626 return 1; 627 break; 628 629 case PACKET_8FAC: 630 if (up->polled <= 0) 631 return 0; 632 633 if (up->rpt_cnt != LENCODE_8FAC)/* check length */ 634 break; 635 636 #ifdef DEBUG 637 if (debug > 1) { 638 double lat, lon, alt; 639 lat = getdbl((u_char *) &mb(36)) * R2D; 640 lon = getdbl((u_char *) &mb(44)) * R2D; 641 alt = getdbl((u_char *) &mb(52)); 642 643 printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n", 644 up->unit, lat,lon,alt); 645 printf("TSIP_decode: unit %d\n", up->unit); 646 } 647 #endif 648 if (getint((u_char *) &mb(10)) & 0x80) 649 pp->leap = LEAP_ADDSECOND; /* we ASSUME addsecond */ 650 else 651 pp->leap = LEAP_NOWARNING; 652 653 #ifdef DEBUG 654 if (debug > 1) 655 printf("TSIP_decode: unit %d: 0x%02x leap %d\n", 656 up->unit, mb(0) & 0xff, pp->leap); 657 if (debug > 1) { 658 printf("Receiver MODE: 0x%02X\n", (u_char)mb(1)); 659 if (mb(1) == 0x00) 660 printf(" AUTOMATIC\n"); 661 if (mb(1) == 0x01) 662 printf(" SINGLE SATELLITE\n"); 663 if (mb(1) == 0x03) 664 printf(" HORIZONTAL(2D)\n"); 665 if (mb(1) == 0x04) 666 printf(" FULL POSITION(3D)\n"); 667 if (mb(1) == 0x05) 668 printf(" DGPR REFERENCE\n"); 669 if (mb(1) == 0x06) 670 printf(" CLOCK HOLD(2D)\n"); 671 if (mb(1) == 0x07) 672 printf(" OVERDETERMINED CLOCK\n"); 673 674 printf("\n** Disciplining MODE 0x%02X:\n", (u_char)mb(2)); 675 if (mb(2) == 0x00) 676 printf(" NORMAL\n"); 677 if (mb(2) == 0x01) 678 printf(" POWER-UP\n"); 679 if (mb(2) == 0x02) 680 printf(" AUTO HOLDOVER\n"); 681 if (mb(2) == 0x03) 682 printf(" MANUAL HOLDOVER\n"); 683 if (mb(2) == 0x04) 684 printf(" RECOVERY\n"); 685 if (mb(2) == 0x06) 686 printf(" DISCIPLINING DISABLED\n"); 687 } 688 #endif 689 return 0; 690 break; 691 692 case PACKET_8FAB: 693 /* Thunderbolt Primary Timing Packet */ 694 695 if (up->rpt_cnt != LENCODE_8FAB) /* check length */ 696 break; 697 698 if (up->polled <= 0) 699 return 0; 700 701 GPS_UTC_Offset = getint((u_char *) &mb(7)); 702 703 if (GPS_UTC_Offset == 0){ /* Check UTC Offset */ 704 #ifdef DEBUG 705 printf("TSIP_decode: UTC Offset Unknown\n"); 706 #endif 707 break; 708 } 709 710 711 if ((mb(9) & 0x1d) == 0x0) { 712 /* if we know the GPS time and the UTC offset, 713 we expect UTC timing information !!! */ 714 715 pp->leap = LEAP_NOTINSYNC; 716 refclock_report(peer, CEVNT_BADTIME); 717 up->polled = -1; 718 return 0; 719 } 720 721 pp->nsec = 0; 722 #ifdef DEBUG 723 printf("\nTiming Flags are:\n"); 724 printf("Timing flag value is: 0x%X\n", mb(9)); 725 if ((mb(9) & 0x01) != 0) 726 printf (" Getting UTC time\n"); 727 else 728 printf (" Getting GPS time\n"); 729 if ((mb(9) & 0x02) != 0) 730 printf (" PPS is from UTC\n"); 731 else 732 printf (" PPS is from GPS\n"); 733 if ((mb(9) & 0x04) != 0) 734 printf (" Time is not Set\n"); 735 else 736 printf (" Time is Set\n"); 737 if ((mb(9) & 0x08) != 0) 738 printf(" I dont have UTC info\n"); 739 else 740 printf (" I have UTC info\n"); 741 if ((mb(9) & 0x10) != 0) 742 printf (" Time is from USER\n\n"); 743 else 744 printf (" Time is from GPS\n\n"); 745 #endif 746 747 if ((pp->day = day_of_year(&mb(13))) < 0) 748 break; 749 tow = getlong((u_char *) &mb(1)); 750 #ifdef DEBUG 751 if (debug > 1) { 752 printf("pp->day: %d\n", pp->day); 753 printf("TOW: %ld\n", tow); 754 printf("DAY: %d\n", mb(13)); 755 } 756 #endif 757 pp->year = getint((u_char *) &mb(15)); 758 pp->hour = mb(12); 759 pp->minute = mb(11); 760 pp->second = mb(10); 761 762 763 #ifdef DEBUG 764 if (debug > 1) 765 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); 766 #endif 767 return 1; 768 break; 769 770 default: 771 /* Ignore Packet */ 772 return 0; 773 } /* switch */ 774 } /* if 8F packets */ 775 776 else if (up->rpt_buf[0] == (u_char)0x42) { 777 printf("0x42\n"); 778 return 0; 779 } 780 else if (up->rpt_buf[0] == (u_char)0x43) { 781 printf("0x43\n"); 782 return 0; 783 } 784 else if ((up->rpt_buf[0] == PACKET_41) & (up->type == CLK_THUNDERBOLT)){ 785 printf("Undocumented 0x41 packet on Thunderbolt\n"); 786 return 0; 787 } 788 else if ((up->rpt_buf[0] == PACKET_41A) & (up->type == CLK_ACUTIME)) { 789 #ifdef DEBUG 790 printf("GPS TOW: %ld\n", (long)getlong((u_char *) &mb(0))); 791 printf("GPS WN: %d\n", getint((u_char *) &mb(4))); 792 printf("GPS UTC-GPS Offser: %ld\n", (long)getlong((u_char *) &mb(6))); 793 #endif 794 return 0; 795 } 796 797 /* Health Status for Acutime Receiver */ 798 else if ((up->rpt_buf[0] == PACKET_46) & (up->type == CLK_ACUTIME)) { 799 #ifdef DEBUG 800 if (debug > 1) 801 /* Status Codes */ 802 switch (mb(0)) { 803 case 0x00: 804 printf ("Doing Position Fixes\n"); 805 break; 806 case 0x01: 807 printf ("Do no have GPS time yet\n"); 808 break; 809 case 0x03: 810 printf ("PDOP is too high\n"); 811 break; 812 case 0x08: 813 printf ("No usable satellites\n"); 814 break; 815 case 0x09: 816 printf ("Only 1 usable satellite\n"); 817 break; 818 case 0x0A: 819 printf ("Only 2 usable satellites\n"); 820 break; 821 case 0x0B: 822 printf ("Only 3 usable satellites\n"); 823 break; 824 case 0x0C: 825 printf("The Chosen satellite is unusable\n"); 826 break; 827 } 828 #endif 829 /* Error Codes */ 830 if (mb(1) != 0) { 831 832 refclock_report(peer, CEVNT_BADTIME); 833 up->polled = -1; 834 #ifdef DEBUG 835 if (debug > 1) { 836 if (mb(1) & 0x01) 837 printf ("Signal Processor Error, reset unit.\n"); 838 if (mb(1) & 0x02) 839 printf ("Alignment error, channel or chip 1, reset unit.\n"); 840 if (mb(1) & 0x03) 841 printf ("Alignment error, channel or chip 2, reset unit.\n"); 842 if (mb(1) & 0x04) 843 printf ("Antenna feed line fault (open or short)\n"); 844 if (mb(1) & 0x05) 845 printf ("Excessive reference frequency error, refer to packet 0x2D and packet 0x4D documentation for further information\n"); 846 } 847 #endif 848 849 return 0; 850 } 851 } 852 else if (up->rpt_buf[0] == 0x54) 853 return 0; 854 855 else if (up->rpt_buf[0] == PACKET_6D) { 856 #ifdef DEBUG 857 int sats; 858 859 if ((mb(0) & 0x01) && (mb(0) & 0x02)) 860 printf("2d Fix Dimension\n"); 861 if (mb(0) & 0x04) 862 printf("3d Fix Dimension\n"); 863 864 if (mb(0) & 0x08) 865 printf("Fix Mode is MANUAL\n"); 866 else 867 printf("Fix Mode is AUTO\n"); 868 869 sats = mb(0) & 0xF0; 870 sats = sats >> 4; 871 printf("Tracking %d Satellites\n", sats); 872 #endif 873 return 0; 874 } /* else if not super packet */ 875 refclock_report(peer, CEVNT_BADREPLY); 876 up->polled = -1; 877 #ifdef DEBUG 878 printf("TSIP_decode: unit %d: bad packet %02x-%02x event %d len %d\n", 879 up->unit, up->rpt_buf[0] & 0xff, mb(0) & 0xff, 880 event, up->rpt_cnt); 881 #endif 882 return 0; 883 } 884 885 /* 886 * palisade__receive - receive data from the serial interface 887 */ 888 889 static void 890 palisade_receive ( 891 struct peer * peer 892 ) 893 { 894 struct palisade_unit *up; 895 struct refclockproc *pp; 896 897 /* 898 * Initialize pointers and read the timecode and timestamp. 899 */ 900 pp = peer->procptr; 901 up = pp->unitptr; 902 903 if (! TSIP_decode(peer)) return; 904 905 if (up->polled <= 0) 906 return; /* no poll pending, already received or timeout */ 907 908 up->polled = 0; /* Poll reply received */ 909 pp->lencode = 0; /* clear time code */ 910 #ifdef DEBUG 911 if (debug) 912 printf( 913 "palisade_receive: unit %d: %4d %03d %02d:%02d:%02d.%09ld\n", 914 up->unit, pp->year, pp->day, pp->hour, pp->minute, 915 pp->second, pp->nsec); 916 #endif 917 918 /* 919 * Process the sample 920 * Generate timecode: YYYY DoY HH:MM:SS.microsec 921 * report and process 922 */ 923 924 snprintf(pp->a_lastcode, sizeof(pp->a_lastcode), 925 "%4d %03d %02d:%02d:%02d.%09ld", 926 pp->year, pp->day, 927 pp->hour,pp->minute, pp->second, pp->nsec); 928 pp->lencode = 24; 929 930 if (!refclock_process(pp)) { 931 refclock_report(peer, CEVNT_BADTIME); 932 933 #ifdef DEBUG 934 printf("palisade_receive: unit %d: refclock_process failed!\n", 935 up->unit); 936 #endif 937 return; 938 } 939 940 record_clock_stats(&peer->srcadr, pp->a_lastcode); 941 942 #ifdef DEBUG 943 if (debug) 944 printf("palisade_receive: unit %d: %s\n", 945 up->unit, prettydate(&pp->lastrec)); 946 #endif 947 pp->lastref = pp->lastrec; 948 refclock_receive(peer); 949 } 950 951 952 /* 953 * palisade_poll - called by the transmit procedure 954 * 955 */ 956 static void 957 palisade_poll ( 958 int unit, 959 struct peer *peer 960 ) 961 { 962 struct palisade_unit *up; 963 struct refclockproc *pp; 964 965 pp = peer->procptr; 966 up = pp->unitptr; 967 968 pp->polls++; 969 if (up->polled > 0) /* last reply never arrived or error */ 970 refclock_report(peer, CEVNT_TIMEOUT); 971 972 up->polled = 2; /* synchronous packet + 1 event */ 973 974 #ifdef DEBUG 975 if (debug) 976 printf("palisade_poll: unit %d: polling %s\n", unit, 977 (pp->sloppyclockflag & CLK_FLAG2) ? 978 "synchronous packet" : "event"); 979 #endif 980 981 if (pp->sloppyclockflag & CLK_FLAG2) 982 return; /* using synchronous packet input */ 983 984 if(up->type == CLK_PRAECIS) { 985 if(write(peer->procptr->io.fd,"SPSTAT\r\n",8) < 0) 986 msyslog(LOG_ERR, "Palisade(%d) write: %m:",unit); 987 else { 988 praecis_msg = 1; 989 return; 990 } 991 } 992 993 if (HW_poll(pp) < 0) 994 refclock_report(peer, CEVNT_FAULT); 995 } 996 997 static void 998 praecis_parse ( 999 struct recvbuf *rbufp, 1000 struct peer *peer 1001 ) 1002 { 1003 static char buf[100]; 1004 static int p = 0; 1005 struct refclockproc *pp; 1006 1007 pp = peer->procptr; 1008 1009 memcpy(buf+p,rbufp->recv_space.X_recv_buffer, rbufp->recv_length); 1010 p += rbufp->recv_length; 1011 1012 if(buf[p-2] == '\r' && buf[p-1] == '\n') { 1013 buf[p-2] = '\0'; 1014 record_clock_stats(&peer->srcadr, buf); 1015 1016 p = 0; 1017 praecis_msg = 0; 1018 1019 if (HW_poll(pp) < 0) 1020 refclock_report(peer, CEVNT_FAULT); 1021 1022 } 1023 } 1024 1025 static void 1026 palisade_io ( 1027 struct recvbuf *rbufp 1028 ) 1029 { 1030 /* 1031 * Initialize pointers and read the timecode and timestamp. 1032 */ 1033 struct palisade_unit *up; 1034 struct refclockproc *pp; 1035 struct peer *peer; 1036 1037 char * c, * d; 1038 1039 peer = rbufp->recv_peer; 1040 pp = peer->procptr; 1041 up = pp->unitptr; 1042 1043 if(up->type == CLK_PRAECIS) { 1044 if(praecis_msg) { 1045 praecis_parse(rbufp,peer); 1046 return; 1047 } 1048 } 1049 1050 c = (char *) &rbufp->recv_space; 1051 d = c + rbufp->recv_length; 1052 1053 while (c != d) { 1054 1055 /* Build time packet */ 1056 switch (up->rpt_status) { 1057 1058 case TSIP_PARSED_DLE_1: 1059 switch (*c) 1060 { 1061 case 0: 1062 case DLE: 1063 case ETX: 1064 up->rpt_status = TSIP_PARSED_EMPTY; 1065 break; 1066 1067 default: 1068 up->rpt_status = TSIP_PARSED_DATA; 1069 /* save packet ID */ 1070 up->rpt_buf[0] = *c; 1071 break; 1072 } 1073 break; 1074 1075 case TSIP_PARSED_DATA: 1076 if (*c == DLE) 1077 up->rpt_status = TSIP_PARSED_DLE_2; 1078 else 1079 mb(up->rpt_cnt++) = *c; 1080 break; 1081 1082 case TSIP_PARSED_DLE_2: 1083 if (*c == DLE) { 1084 up->rpt_status = TSIP_PARSED_DATA; 1085 mb(up->rpt_cnt++) = 1086 *c; 1087 } 1088 else if (*c == ETX) 1089 up->rpt_status = TSIP_PARSED_FULL; 1090 else { 1091 /* error: start new report packet */ 1092 up->rpt_status = TSIP_PARSED_DLE_1; 1093 up->rpt_buf[0] = *c; 1094 } 1095 break; 1096 1097 case TSIP_PARSED_FULL: 1098 case TSIP_PARSED_EMPTY: 1099 default: 1100 if ( *c != DLE) 1101 up->rpt_status = TSIP_PARSED_EMPTY; 1102 else 1103 up->rpt_status = TSIP_PARSED_DLE_1; 1104 break; 1105 } 1106 1107 c++; 1108 1109 if (up->rpt_status == TSIP_PARSED_DLE_1) { 1110 up->rpt_cnt = 0; 1111 if (pp->sloppyclockflag & CLK_FLAG2) 1112 /* stamp it */ 1113 get_systime(&pp->lastrec); 1114 } 1115 else if (up->rpt_status == TSIP_PARSED_EMPTY) 1116 up->rpt_cnt = 0; 1117 1118 else if (up->rpt_cnt > BMAX) 1119 up->rpt_status =TSIP_PARSED_EMPTY; 1120 1121 if (up->rpt_status == TSIP_PARSED_FULL) 1122 palisade_receive(peer); 1123 1124 } /* while chars in buffer */ 1125 } 1126 1127 1128 /* 1129 * Trigger the Palisade's event input, which is driven off the RTS 1130 * 1131 * Take a system time stamp to match the GPS time stamp. 1132 * 1133 */ 1134 long 1135 HW_poll ( 1136 struct refclockproc * pp /* pointer to unit structure */ 1137 ) 1138 { 1139 int x; /* state before & after RTS set */ 1140 struct palisade_unit *up; 1141 1142 up = pp->unitptr; 1143 1144 /* read the current status, so we put things back right */ 1145 if (ioctl(pp->io.fd, TIOCMGET, &x) < 0) { 1146 DPRINTF(1, ("Palisade HW_poll: unit %d: GET %m\n", 1147 up->unit)); 1148 msyslog(LOG_ERR, "Palisade(%d) HW_poll: ioctl(fd,GET): %m", 1149 up->unit); 1150 return -1; 1151 } 1152 1153 x |= TIOCM_RTS; /* turn on RTS */ 1154 1155 /* Edge trigger */ 1156 if (up->type == CLK_ACUTIME) 1157 write (pp->io.fd, "", 1); 1158 1159 if (ioctl(pp->io.fd, TIOCMSET, &x) < 0) { 1160 #ifdef DEBUG 1161 if (debug) 1162 printf("Palisade HW_poll: unit %d: SET \n", up->unit); 1163 #endif 1164 msyslog(LOG_ERR, 1165 "Palisade(%d) HW_poll: ioctl(fd, SET, RTS_on): %m", 1166 up->unit); 1167 return -1; 1168 } 1169 1170 x &= ~TIOCM_RTS; /* turn off RTS */ 1171 1172 /* poll timestamp */ 1173 get_systime(&pp->lastrec); 1174 1175 if (ioctl(pp->io.fd, TIOCMSET, &x) == -1) { 1176 #ifdef DEBUG 1177 if (debug) 1178 printf("Palisade HW_poll: unit %d: UNSET \n", up->unit); 1179 #endif 1180 msyslog(LOG_ERR, 1181 "Palisade(%d) HW_poll: ioctl(fd, UNSET, RTS_off): %m", 1182 up->unit); 1183 return -1; 1184 } 1185 1186 return 0; 1187 } 1188 1189 /* 1190 * copy/swap a big-endian palisade double into a host double 1191 */ 1192 static double 1193 getdbl ( 1194 u_char *bp 1195 ) 1196 { 1197 #ifdef WORDS_BIGENDIAN 1198 double out; 1199 1200 memcpy(&out, bp, sizeof(out)); 1201 return out; 1202 #else 1203 union { 1204 u_char ch[8]; 1205 u_int32 u32[2]; 1206 } ui; 1207 1208 union { 1209 double out; 1210 u_int32 u32[2]; 1211 } uo; 1212 1213 memcpy(ui.ch, bp, sizeof(ui.ch)); 1214 /* least-significant 32 bits of double from swapped bp[4] to bp[7] */ 1215 uo.u32[0] = ntohl(ui.u32[1]); 1216 /* most-significant 32 bits from swapped bp[0] to bp[3] */ 1217 uo.u32[1] = ntohl(ui.u32[0]); 1218 1219 return uo.out; 1220 #endif 1221 } 1222 1223 /* 1224 * copy/swap a big-endian palisade short into a host short 1225 */ 1226 static short 1227 getint ( 1228 u_char *bp 1229 ) 1230 { 1231 u_short us; 1232 1233 memcpy(&us, bp, sizeof(us)); 1234 return (short)ntohs(us); 1235 } 1236 1237 /* 1238 * copy/swap a big-endian palisade 32-bit int into a host 32-bit int 1239 */ 1240 static int32 1241 getlong( 1242 u_char *bp 1243 ) 1244 { 1245 u_int32 u32; 1246 1247 memcpy(&u32, bp, sizeof(u32)); 1248 return (int32)(u_int32)ntohl(u32); 1249 } 1250 1251 #else /* REFCLOCK && CLOCK_PALISADE*/ 1252 int refclock_palisade_c_notempty; 1253 #endif 1254