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