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