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