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