1 /* 2 * ---------------------------------------------------------------------------- 3 * "THE BEER-WARE LICENSE" (Revision 42): 4 * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you 5 * can do whatever you want with this stuff. If we meet some day, and you think 6 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 7 * ---------------------------------------------------------------------------- 8 * 9 * refclock_oncore.c 10 * 11 * Driver for some of the various the Motorola Oncore GPS receivers. 12 * 13 * Tested with: 14 * 15 * (UT) (VP) 16 * COPYRIGHT 1991-1997 MOTOROLA INC. COPYRIGHT 1991-1996 MOTOROLA INC. 17 * SFTW P/N # 98-P36848P SFTW P/N # 98-P36830P 18 * SOFTWARE VER # 2 SOFTWARE VER # 8 19 * SOFTWARE REV # 2 SOFTWARE REV # 8 20 * SOFTWARE DATE APR 24 1998 SOFTWARE DATE 06 Aug 1996 21 * MODEL # R1121N1114 MODEL # B4121P1155 22 * HWDR P/N # 1 HDWR P/N # _ 23 * SERIAL # R0010A SERIAL # SSG0226478 24 * MANUFACTUR DATE 6H07 MANUFACTUR DATE 7E02 25 * OPTIONS LIST IB 26 * 27 * -------------------------------------------------------------------------- 28 * This code uses the two devices 29 * /dev/oncore.serial.n 30 * /dev/oncore.pps.n 31 * which may be linked to the same device. 32 * and can read initialization data from the file 33 * /etc/ntp.oncoreN (where n and N are the unit number, viz 127.127.30.N) 34 * or /etc/ntp.oncore 35 * -------------------------------------------------------------------------- 36 * Reg.Clemens <reg@dwf.com> Sep98. 37 * Original code written for FreeBSD. 38 * With these mods it works on SunOS, Solaris (untested) and Linux 39 * (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + changes). 40 * 41 * Lat,Long,Ht, cable-delay, offset, and the ReceiverID (along with the 42 * state machine state) are printed to CLOCKSTATS if that file is enabled 43 * in /etc/ntp.conf. 44 * 45 * -------------------------------------------------------------------------- 46 */ 47 48 /* 49 * According to the ONCORE manual (TRM0003, Rev 3.2, June 1998, page 3.13) 50 * doing an average of 10000 valid 2D and 3D fixes is what the automatic 51 * site survey mode does. Looking at the output from the receiver 52 * it seems like it is only using 3D fixes. 53 * When we do it ourselves, take 10000 3D fixes. 54 */ 55 56 #define POS_HOLD_AVERAGE 10000 /* nb, 10000s ~= 2h45m */ 57 58 /* 59 * ONCORE_SHMEM_STATUS will create a mmap(2)'ed file named according to a 60 * "STATUS" line in the oncore config file, which contains the most recent 61 * copy of all types of messages we recognize. This file can be mmap(2)'ed 62 * by monitoring and statistics programs. 63 */ 64 65 #ifdef HAVE_CONFIG_H 66 #include <config.h> 67 #endif 68 69 #if defined(REFCLOCK) && defined(CLOCK_ONCORE) 70 71 #include <stdio.h> 72 #include <ctype.h> 73 #include <sys/types.h> 74 #include <sys/time.h> 75 #include <sys/stat.h> 76 #ifdef ONCORE_SHMEM_STATUS 77 # ifdef HAVE_SYS_MMAN_H 78 # include <sys/mman.h> 79 # ifndef MAP_FAILED 80 # define MAP_FAILED ((u_char *) -1) 81 # endif /* not MAP_FAILED */ 82 # endif /* HAVE_SYS_MMAN_H */ 83 #endif /* ONCORE_SHMEM_STATUS */ 84 85 #ifdef HAVE_PPSAPI 86 # ifdef HAVE_TIMEPPS_H 87 # include <timepps.h> 88 # else 89 # ifdef HAVE_SYS_TIMEPPS_H 90 # include <sys/timepps.h> 91 # endif 92 # endif 93 #endif 94 95 #ifdef HAVE_SYS_SIO_H 96 # include <sys/sio.h> 97 #endif 98 99 #include "ntpd.h" 100 #include "ntp_io.h" 101 #include "ntp_unixtime.h" 102 #include "ntp_refclock.h" 103 #include "ntp_stdlib.h" 104 105 #ifdef HAVE_SYS_TERMIOS_H 106 #include <sys/termios.h> 107 #endif 108 109 #ifdef HAVE_SYS_PPSCLOCK_H 110 # include <sys/ppsclock.h> 111 #endif 112 113 #ifndef HAVE_STRUCT_PPSCLOCKEV 114 struct ppsclockev { 115 # ifdef HAVE_TIMESPEC 116 struct timespec tv; 117 # else 118 struct timeval tv; 119 # endif 120 u_int serial; 121 }; 122 #endif /* not HAVE_STRUCT_PPSCLOCKEV */ 123 124 enum receive_state { 125 ONCORE_NO_IDEA, 126 ONCORE_RESET_SENT, 127 ONCORE_TEST_SENT, 128 ONCORE_ID_SENT, 129 ONCORE_ALMANAC, 130 ONCORE_RUN 131 }; 132 133 enum site_survey_state { 134 ONCORE_SS_UNKNOWN, 135 ONCORE_SS_HW, 136 ONCORE_SS_SW, 137 ONCORE_SS_DONE 138 }; 139 140 struct instance { 141 int unit; /* 127.127.30.unit */ 142 int ttyfd; /* TTY file descriptor */ 143 int ppsfd; /* PPS file descriptor */ 144 int statusfd; /* Status shm descriptor */ 145 u_char *shmem; 146 #ifdef HAVE_PPSAPI 147 pps_handle_t pps_h; 148 pps_params_t pps_p; 149 #endif 150 enum receive_state o_state; /* Receive state */ 151 152 enum site_survey_state site_survey; /* Site Survey state */ 153 154 struct refclockproc *pp; 155 struct peer *peer; 156 157 int Bj_day; 158 159 long delay; /* ns */ 160 long offset; /* ns */ 161 162 double ss_lat; 163 double ss_long; 164 double ss_ht; 165 int ss_count; 166 u_char ss_ht_type; 167 u_char posn_set; 168 169 u_char printed; 170 u_char polled; 171 int pollcnt; 172 u_int ev_serial; 173 int Rcvptr; 174 u_char Rcvbuf[500]; 175 u_char Ea[77]; 176 u_char En[70]; 177 u_char Cj[300]; 178 u_char As; 179 u_char Ay; 180 u_char Az; 181 u_char init_type; 182 s_char saw_tooth; 183 u_char timeout; /* flag to retry Cj after Fa reset */ 184 s_char assert; 185 }; 186 187 #define rcvbuf instance->Rcvbuf 188 #define rcvptr instance->Rcvptr 189 190 static void oncore_consume P((struct instance *)); 191 static void oncore_poll P((int, struct peer *)); 192 static void oncore_read_config P((struct instance *)); 193 static void oncore_receive P((struct recvbuf *)); 194 static void oncore_sendmsg P((int fd, u_char *, u_int)); 195 static void oncore_shutdown P((int, struct peer *)); 196 static int oncore_start P((int, struct peer *)); 197 198 static void oncore_msg_any P((struct instance *, u_char *, u_int, int)); 199 static void oncore_msg_As P((struct instance *, u_char *, u_int)); 200 static void oncore_msg_At P((struct instance *, u_char *, u_int)); 201 static void oncore_msg_Ay P((struct instance *, u_char *, u_int)); 202 static void oncore_msg_Az P((struct instance *, u_char *, u_int)); 203 static void oncore_msg_Bj P((struct instance *, u_char *, u_int)); 204 static void oncore_msg_Cb P((struct instance *, u_char *, u_int)); 205 static void oncore_msg_Cf P((struct instance *, u_char *, u_int)); 206 static void oncore_msg_Cj P((struct instance *, u_char *, u_int)); 207 static void oncore_msg_Ea P((struct instance *, u_char *, u_int)); 208 static void oncore_msg_En P((struct instance *, u_char *, u_int)); 209 static void oncore_msg_Fa P((struct instance *, u_char *, u_int)); 210 211 struct refclock refclock_oncore = { 212 oncore_start, /* start up driver */ 213 oncore_shutdown, /* shut down driver */ 214 oncore_poll, /* transmit poll message */ 215 noentry, /* not used */ 216 noentry, /* not used */ 217 noentry, /* not used */ 218 NOFLAGS /* not used */ 219 }; 220 221 /* 222 * Understanding the next bit here is not easy unless you have a manual 223 * for the the UT or VP Oncore. 224 */ 225 226 static struct msg_desc { 227 const char flag[3]; 228 const int len; 229 void (*handler) P((struct instance *, u_char *, u_int)); 230 const char *fmt; 231 int shmem; 232 } oncore_messages[] = { 233 /* Ea and En first since they're most common */ 234 { "Ea", 76, oncore_msg_Ea, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" }, 235 { "En", 69, oncore_msg_En, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" }, 236 { "Ab", 10, 0, "" }, 237 { "Ac", 11, 0, "" }, 238 { "Ad", 11, 0, "" }, 239 { "Ae", 11, 0, "" }, 240 { "Af", 15, 0, "" }, 241 { "As", 20, oncore_msg_As, "" }, 242 { "At", 8, oncore_msg_At, "" }, 243 { "Aw", 8, 0, "" }, 244 { "Ay", 11, oncore_msg_Ay, "" }, 245 { "Az", 11, oncore_msg_Az, "" }, 246 { "AB", 8, 0, "" }, 247 { "Bb", 92, 0, "" }, 248 { "Bj", 8, oncore_msg_Bj, "" }, 249 { "Cb", 33, oncore_msg_Cb, "" }, 250 { "Cf", 7, oncore_msg_Cf, "" }, 251 { "Cg", 8, 0, "" }, 252 { "Ch", 9, 0, "" }, 253 { "Cj", 294, oncore_msg_Cj, "" }, 254 { "Ek", 71, 0, "" }, 255 { "Fa", 9, oncore_msg_Fa, "" }, 256 { "Sz", 8, 0, "" }, 257 { {0}, 7, 0, ""} 258 }; 259 260 static unsigned int oncore_shmem_Cb; 261 262 /* 263 * Position Set. 264 */ 265 u_char oncore_cmd_Ad[] = { 'A', 'd', 0,0,0,0 }; 266 u_char oncore_cmd_Ae[] = { 'A', 'e', 0,0,0,0 }; 267 u_char oncore_cmd_Af[] = { 'A', 'f', 0,0,0,0, 0 }; 268 269 /* 270 * Position-Hold Mode 271 * Start automatic site survey 272 */ 273 static u_char oncore_cmd_At[] = { 'A', 't', 2 }; 274 275 /* 276 * Position-Hold Position 277 */ 278 u_char oncore_cmd_As[] = { 'A', 's', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; 279 u_char oncore_cmd_Asx[]= { 'A', 's', 0x7f, 0xff, 0xff, 0xff, 280 0x7f, 0xff, 0xff, 0xff, 281 0x7f, 0xff, 0xff, 0xff, 0xff }; 282 283 /* 284 * Set to UTC time (not GPS). 285 */ 286 u_char oncore_cmd_Aw[] = { 'A', 'w', 1 }; 287 288 /* 289 * Output Almanac when it changes 290 */ 291 u_char oncore_cmd_Be[] = { 'B', 'e', 1 }; 292 293 /* 294 * Read back PPS Offset for Output 295 */ 296 u_char oncore_cmd_Ay[] = { 'A', 'y', 0, 0, 0, 0 }; 297 u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff }; 298 299 /* 300 * Read back Cable Delay for Output 301 */ 302 u_char oncore_cmd_Az[] = { 'A', 'z', 0, 0, 0, 0 }; 303 u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff }; 304 305 /* 306 * Application type = static. 307 */ 308 u_char oncore_cmd_AB[] = { 'A', 'B', 4 }; 309 310 /* 311 * Visible Satellite Status Msg. 312 */ 313 u_char oncore_cmd_Bb[] = { 'B', 'b', 1 }; 314 315 /* 316 * Leap Second Pending Message 317 * Request message once 318 */ 319 u_char oncore_cmd_Bj[] = { 'B', 'j', 0 }; 320 321 /* 322 * Set to Defaults 323 */ 324 static u_char oncore_cmd_Cf[] = { 'C', 'f' }; 325 326 /* 327 * Set to Position Fix mode (only needed on VP). 328 */ 329 u_char oncore_cmd_Cg[] = { 'C', 'g', 1 }; 330 331 /* 332 * Receiver Id 333 */ 334 static u_char oncore_cmd_Cj[] = { 'C', 'j' }; 335 336 /* 337 * Position/Status/Data message 338 * Send once per second 339 */ 340 static u_char oncore_cmd_Ea[] = { 'E', 'a', 1 }; 341 342 /* 343 * Position/Status Extension Msg 344 */ 345 u_char oncore_cmd_Ek[] = { 'E', 'k', 0 }; /* just turn off */ 346 347 /* 348 * Time Raim Setup & Status Message 349 * Send once per second 350 * Time-RAIM on 351 * Alarm limit 1us 352 * PPS on when we have the first sat 353 */ 354 static u_char oncore_cmd_En[] = { 'E', 'n', 1, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 355 356 /* 357 * Self-test 358 */ 359 static u_char oncore_cmd_Fa[] = { 'F', 'a' }; 360 361 #define DEVICE1 "/dev/oncore.serial.%d" /* name of serial device */ 362 #define DEVICE2 "/dev/oncore.pps.%d" /* name of pps device */ 363 #define INIT_FILE "/etc/ntp.oncore" /* optional init file */ 364 365 #define SPEED B9600 /* Oncore Binary speed (9600 bps) */ 366 367 /* 368 * Assemble and disassemble 32bit signed quantities from a buffer. 369 * 370 */ 371 372 /* to buffer, int w, u_char *buf */ 373 #define w32_buf(buf,w) { unsigned int i_tmp; \ 374 i_tmp = (w<0) ? (~(-w)+1) : (w); \ 375 (buf)[0] = (i_tmp >> 24) & 0xff; \ 376 (buf)[1] = (i_tmp >> 16) & 0xff; \ 377 (buf)[2] = (i_tmp >> 8) & 0xff; \ 378 (buf)[3] = (i_tmp ) & 0xff; \ 379 } 380 381 #define w32(buf) (((buf)[0]&0xff) << 24 | \ 382 ((buf)[1]&0xff) << 16 | \ 383 ((buf)[2]&0xff) << 8 | \ 384 ((buf)[3]&0xff) ) 385 386 /* from buffer, char *buf, result to an int */ 387 #define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf)) 388 389 extern int pps_assert; 390 extern int pps_hardpps; 391 392 393 /* 394 * oncore_start - initialize data for processing 395 */ 396 static int 397 oncore_start( 398 int unit, 399 struct peer *peer 400 ) 401 { 402 register struct instance *instance; 403 struct refclockproc *pp; 404 int fd1, fd2, mode; 405 char device1[30], device2[30]; 406 const char *cp; 407 struct stat stat1, stat2; 408 409 /* OPEN DEVICES */ 410 /* opening different devices for fd1 and fd2 presents no problems */ 411 /* opening the SAME device twice, seems to be OS dependent. 412 (a) on Linux (no streams) no problem 413 (b) on SunOS (and possibly Solaris, untested), (streams) 414 never see the line discipline. 415 Since things ALWAYS work if we only open the device once, we check 416 to see if the two devices are in fact the same, then proceed to 417 do one open or two. 418 */ 419 420 (void)sprintf(device1, DEVICE1, unit); 421 (void)sprintf(device2, DEVICE2, unit); 422 423 if (stat(device1, &stat1)) { 424 perror("ONCORE: stat fd1"); 425 exit(1); 426 } 427 428 if (stat(device2, &stat2)) { 429 perror("ONCORE: stat fd2"); 430 exit(1); 431 } 432 433 if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino)) { 434 /* same device here */ 435 if (!(fd1 = refclock_open(device1, SPEED, LDISC_RAW 436 #if !defined(HAVE_PPSAPI) && !defined(TIOCDCDTIMESTAMP) 437 | LDISC_PPS 438 #endif 439 ))) { 440 perror("ONCORE: fd1"); 441 exit(1); 442 } 443 fd2 = fd1; 444 } else { /* different devices here */ 445 if (!(fd1=refclock_open(device1, SPEED, LDISC_RAW))) { 446 perror("ONCORE: fd1"); 447 exit(1); 448 } 449 if ((fd2=open(device2, O_RDWR)) < 0) { 450 perror("ONCORE: fd2"); 451 exit(1); 452 } 453 } 454 455 /* Devices now open, initialize instance structure */ 456 457 if (!(instance = (struct instance *)emalloc(sizeof *instance))) { 458 perror("malloc"); 459 close(fd1); 460 return (0); 461 } 462 memset((char *) instance, 0, sizeof *instance); 463 pp = peer->procptr; 464 pp->unitptr = (caddr_t)instance; 465 instance->unit = unit; 466 instance->ttyfd = fd1; 467 instance->ppsfd = fd2; 468 469 instance->Bj_day = -1; 470 instance->assert = pps_assert; 471 472 /* go read any input data in /etc/ntp.oncoreX */ 473 474 oncore_read_config(instance); 475 476 #ifdef HAVE_PPSAPI 477 if (time_pps_create(fd2, &instance->pps_h) < 0) { 478 perror("time_pps_create"); 479 return(0); 480 } 481 482 if (time_pps_getcap(instance->pps_h, &mode) < 0) { 483 msyslog(LOG_ERR, 484 "refclock_ioctl: time_pps_getcap failed: %m"); 485 return (0); 486 } 487 488 if (time_pps_getparams(instance->pps_h, &instance->pps_p) < 0) { 489 msyslog(LOG_ERR, 490 "refclock_ioctl: time_pps_getparams failed: %m"); 491 return (0); 492 } 493 494 /* nb. only turn things on, if someone else has turned something 495 * on before we get here, leave it alone! 496 */ 497 498 if (instance->assert) { /* nb, default or ON */ 499 instance->pps_p.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT; 500 instance->pps_p.assert_offset.tv_sec = 0; 501 instance->pps_p.assert_offset.tv_nsec = 0; 502 } else { 503 instance->pps_p.mode = PPS_CAPTURECLEAR | PPS_OFFSETCLEAR; 504 instance->pps_p.clear_offset.tv_sec = 0; 505 instance->pps_p.clear_offset.tv_nsec = 0; 506 } 507 instance->pps_p.mode |= PPS_TSFMT_TSPEC; 508 instance->pps_p.mode &= mode; /* only do it if it is legal */ 509 510 if (time_pps_setparams(instance->pps_h, &instance->pps_p) < 0) { 511 perror("time_pps_setparams"); 512 exit(1); 513 } 514 515 if (pps_device) { 516 if (stat(pps_device, &stat1)) { 517 perror("ONCORE: stat pps_device"); 518 return(0); 519 } 520 521 /* must have hardpps ON, and fd2 must be the same device as on the pps line */ 522 523 if (pps_hardpps && ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino))) { 524 int i; 525 526 if (instance->assert) 527 i = PPS_CAPTUREASSERT; 528 else 529 i = PPS_CAPTURECLEAR; 530 531 if (i&mode) { 532 if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i, 533 PPS_TSFMT_TSPEC) < 0) { 534 msyslog(LOG_ERR, 535 "refclock_ioctl: time_pps_kcbind failed: %m"); 536 return (0); 537 } 538 } 539 } 540 } 541 #endif 542 543 instance->pp = pp; 544 instance->peer = peer; 545 instance->o_state = ONCORE_NO_IDEA; 546 cp = "state = ONCORE_NO_IDEA"; 547 record_clock_stats(&(instance->peer->srcadr), cp); 548 549 /* 550 * Initialize miscellaneous variables 551 */ 552 553 peer->precision = -26; 554 peer->minpoll = 4; 555 peer->maxpoll = 4; 556 pp->clockdesc = "Motorola UT/VP Oncore GPS Receiver"; 557 memcpy((char *)&pp->refid, "GPS\0", 4); 558 559 pp->io.clock_recv = oncore_receive; 560 pp->io.srcclock = (caddr_t)peer; 561 pp->io.datalen = 0; 562 pp->io.fd = fd1; 563 if (!io_addclock(&pp->io)) { 564 perror("io_addclock"); 565 (void) close(fd1); 566 free(instance); 567 return (0); 568 } 569 pp->unitptr = (caddr_t)instance; 570 571 /* 572 * This will start the Oncore receiver. 573 * We send info from config to Oncore later. 574 */ 575 576 instance->timeout = 1; 577 mode = instance->init_type; 578 if (mode == 3 || mode == 4) { 579 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cf, sizeof oncore_cmd_Cf); 580 instance->o_state = ONCORE_RESET_SENT; 581 cp = "state = ONCORE_RESET_SENT"; 582 record_clock_stats(&(instance->peer->srcadr), cp); 583 } else { 584 oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof oncore_cmd_Fa); 585 instance->o_state = ONCORE_TEST_SENT; 586 cp = "state = ONCORE_TEST_SENT"; 587 record_clock_stats(&(instance->peer->srcadr), cp); 588 } 589 590 instance->pollcnt = 2; 591 return (1); 592 } 593 594 595 596 static void 597 oncore_init_shmem(struct instance *instance, char *filename) 598 { 599 #ifdef ONCORE_SHMEM_STATUS 600 int i, l, n; 601 char *buf; 602 struct msg_desc *mp; 603 static unsigned int oncore_shmem_length; 604 605 if (oncore_messages[0].shmem == 0) { 606 n = 1; 607 for (mp = oncore_messages; mp->flag[0]; mp++) { 608 mp->shmem = n; 609 /* Allocate space for multiplexed almanac */ 610 if (!strcmp(mp->flag, "Cb")) { 611 oncore_shmem_Cb = n; 612 n += (mp->len + 2) * 34; 613 } 614 n += mp->len + 2; 615 } 616 oncore_shmem_length = n + 2; 617 fprintf(stderr, "ONCORE: SHMEM length: %d bytes\n", oncore_shmem_length); 618 } 619 instance->statusfd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0644); 620 if (instance->statusfd < 0) { 621 perror(filename); 622 exit(4); 623 } 624 buf = malloc(oncore_shmem_length); 625 if (buf == NULL) { 626 perror("malloc"); 627 exit(4); 628 } 629 memset(buf, 0, sizeof(buf)); 630 i = write(instance->statusfd, buf, oncore_shmem_length); 631 if (i != oncore_shmem_length) { 632 perror(filename); 633 exit(4); 634 } 635 free(buf); 636 instance->shmem = (u_char *) mmap(0, oncore_shmem_length, 637 PROT_READ | PROT_WRITE, 638 #ifdef MAP_HASSEMAPHORE 639 MAP_HASSEMAPHORE | 640 #endif 641 MAP_SHARED, 642 instance->statusfd, (off_t)0); 643 if (instance->shmem == MAP_FAILED) { 644 instance->shmem = 0; 645 close (instance->statusfd); 646 exit(4); 647 } 648 for (mp = oncore_messages; mp->flag[0]; mp++) { 649 l = mp->shmem; 650 instance->shmem[l + 0] = mp->len >> 8; 651 instance->shmem[l + 1] = mp->len & 0xff; 652 instance->shmem[l + 2] = '@'; 653 instance->shmem[l + 3] = '@'; 654 instance->shmem[l + 4] = mp->flag[0]; 655 instance->shmem[l + 5] = mp->flag[1]; 656 if (!strcmp(mp->flag, "Cb")) { 657 for (i = 1; i < 35; i++) { 658 instance->shmem[l + i * 35 + 0] = mp->len >> 8; 659 instance->shmem[l + i * 35 + 1] = mp->len & 0xff; 660 instance->shmem[l + i * 35 + 2] = '@'; 661 instance->shmem[l + i * 35 + 3] = '@'; 662 instance->shmem[l + i * 35 + 4] = mp->flag[0]; 663 instance->shmem[l + i * 35 + 5] = mp->flag[1]; 664 } 665 } 666 } 667 #endif /* ONCORE_SHMEM_STATUS */ 668 } 669 670 /* 671 * Read Input file if it exists. 672 */ 673 static void 674 oncore_read_config( 675 struct instance *instance 676 ) 677 { 678 /* 679 * First we try to open the configuration file /etc/ntp.oncoreN, where 680 * N is the unit number viz 127.127.30.N. 681 * If we don't find it, then we try the file /etc/ntp.oncore. 682 * 683 * If we find NEITHER then we don't have the cable delay or PPS offset 684 * and we choose MODE (4) below. 685 * 686 * Five Choices for MODE 687 * (0) ONCORE is preinitialized, don't do anything to change it. 688 * nb, DON'T set 0D mode, DON'T set Delay, position... 689 * (1) NO RESET, Read Position, delays from data file, lock it in, go to 0D mode. 690 * (2) NO RESET, Read Delays from data file, do SITE SURVEY to get position, 691 * lock this in, go to 0D mode. 692 * (3) HARD RESET, Read Position, delays from data file, lock it in, go to 0D mode. 693 * (4) HARD RESET, Read Delays from data file, do SITE SURVEY to get position, 694 * lock this in, go to 0D mode. 695 * NB. If a POSITION is specified in the config file with mode=(2,4) [SITE SURVEY] 696 * then this position is set as the INITIAL position of the ONCORE. 697 * This can reduce the time to first fix. 698 * ------------------------------------------------------------------------------- 699 * Note that an Oncore UT without a battery backup retains NO information if it is 700 * power cycled, with a Battery Backup it remembers the almanac, etc. 701 * For an Oncore VP, there is an eeprom that will contain this data, along with the 702 * option of Battery Backup. 703 * So a UT without Battery Backup is equivalent to doing a HARD RESET on each 704 * power cycle, since there is nowhere to store the data. 705 * ------------------------------------------------------------------------------- 706 * 707 * If we open one or the other of the files, we read it looking for 708 * MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET 709 * then initialize using method MODE. For Mode = (1,3) all of (LAT, LON, HT) must 710 * be present or mode reverts to (2,4). 711 * 712 * Read input file. 713 * 714 * # is comment to end of line 715 * = allowed between 1st and 2nd fields. 716 * 717 * Expect to see one line with 'MODE' as first field, followed by an integer 718 * in the range 0-4 (default = 4). 719 * 720 * Expect to see two lines with 'LONG', 'LAT' followed by 1-3 fields. 721 * All numbers are floating point. 722 * DDD.ddd 723 * DDD MMM.mmm 724 * DDD MMM SSS.sss 725 * 726 * Expect to see one line with 'HT' (or 'HTMSL' or 'HTGPS') as first field. 727 * followed by 1-2 fields. First is a number, the second is 'FT' or 'M'. 728 * for feet or meters. HT is the same as HTGPS. 729 * HTMSL = HT above mean_sea_level, 730 * HTGPS = HT above GPS ellipse. 731 * 732 * There are two optional lines, starting with DELAY and OFFSET, followed 733 * by 1 or two fields. The first is a number (a time) the second is 734 * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds. 735 * DELAY is cable delay, typically a few tens of ns. 736 * OFFSET is the offset of the PPS pulse from 0. (only fully implemented 737 * with the PPSAPI, we need to be able to tell the Kernel about this 738 * offset if the Kernel PLL is in use, but can only do this presently 739 * when using the PPSAPI interface. If not using the Kernel PLL, 740 * then there is no problem. 741 * 742 * There is another optional line, with either ASSERT or CLEAR on it, which 743 * determine which transition of the PPS signal is used for timing by the 744 * PPSAPI. If neither is present, then ASSERT is assumed. 745 * 746 * So acceptable input would be 747 * # these are my coordinates (RWC) 748 * LON -106 34.610 749 * LAT 35 08.999 750 * HT 1589 # could equally well say HT 5215 FT 751 * DELAY 60 ns 752 */ 753 754 FILE *fd; 755 char *cp, *cc, *ca, line[100], units[2], device[20]; 756 int i, sign, lat_flg, long_flg, ht_flg, mode; 757 double f1, f2, f3; 758 759 sprintf(device, "%s%d", INIT_FILE, instance->unit); 760 if ((fd=fopen(device, "r")) == NULL) 761 if ((fd=fopen(INIT_FILE, "r")) == NULL) { 762 instance->init_type = 4; 763 return; 764 } 765 766 mode = 0; 767 lat_flg = long_flg = ht_flg = 0; 768 while (fgets(line, 100, fd)) { 769 770 /* Remove comments */ 771 if ((cp = strchr(line, '#'))) 772 *cp = '\0'; 773 774 /* Remove trailing space */ 775 for (i = strlen(line); 776 i > 0 && isascii((int)line[i - 1]) && isspace((int)line[i - 1]); 777 ) 778 line[--i] = '\0'; 779 780 /* Remove leading space */ 781 for (cc = line; *cc && isascii((int)*cc) && isspace((int)*cc); cc++) 782 continue; 783 784 /* Stop if nothing left */ 785 if (!*cc) 786 continue; 787 788 /* Lowercase the command and find the arg */ 789 for (ca = cc; *ca; ca++) { 790 if (isascii((int)*ca) && islower((int)*ca)) { 791 *ca = toupper(*ca); 792 } else if (isascii((int)*ca) && isspace((int)*ca)) { 793 break; 794 } else if (*ca == '=') { 795 *ca = ' '; 796 break; 797 } 798 } 799 800 /* Remove space leading the arg */ 801 for (; *ca && isascii((int)*ca) && isspace((int)*ca); ca++) 802 continue; 803 804 if (!strncmp(cc, "STATUS", 6)) { 805 oncore_init_shmem(instance, ca); 806 continue; 807 } 808 809 /* Uppercase argument as well */ 810 for (cp = ca; *cp; cp++) 811 if (isascii((int)*cp) && islower((int)*cp)) 812 *cp = toupper(*cp); 813 814 if (!strncmp(cc, "LAT", 3)) { 815 f1 = f2 = f3 = 0; 816 sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3); 817 sign = 1; 818 if (f1 < 0) { 819 f1 = -f1; 820 sign = -1; 821 } 822 instance->ss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/ 823 lat_flg++; 824 } else if (!strncmp(cc, "LON", 3)) { 825 f1 = f2 = f3 = 0; 826 sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3); 827 sign = 1; 828 if (f1 < 0) { 829 f1 = -f1; 830 sign = -1; 831 } 832 instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/ 833 long_flg++; 834 } else if (!strncmp(cc, "HT", 2)) { 835 if (!strncmp(cc, "HTGPS", 5)) 836 instance->ss_ht_type = 0; 837 else if (!strncmp(cc, "HTMSL", 5)) 838 instance->ss_ht_type = 1; 839 else 840 instance->ss_ht_type = 0; 841 f1 = 0; 842 units[0] = '\0'; 843 sscanf(ca, "%lf %1s", &f1, units); 844 if (units[0] == 'F') 845 f1 = 0.3048 * f1; 846 instance->ss_ht = 100 * f1; /* cm */ 847 ht_flg++; 848 } else if (!strncmp(cc, "DELAY", 5)) { 849 f1 = 0; 850 units[0] = '\0'; 851 sscanf(ca, "%lf %1s", &f1, units); 852 if (units[0] == 'N') 853 ; 854 else if (units[0] == 'U') 855 f1 = 1000 * f1; 856 else if (units[0] == 'M') 857 f1 = 1000000 * f1; 858 else 859 f1 = 1000000000 * f1; 860 if (f1 < 0 || f1 > 1.e9) 861 f1 = 0; 862 instance->delay = f1; /* delay in ns */ 863 } else if (!strncmp(cc, "OFFSET", 6)) { 864 f1 = 0; 865 units[0] = '\0'; 866 sscanf(ca, "%lf %1s", &f1, units); 867 if (units[0] == 'N') 868 ; 869 else if (units[0] == 'U') 870 f1 = 1000 * f1; 871 else if (units[0] == 'M') 872 f1 = 1000000 * f1; 873 else 874 f1 = 1000000000 * f1; 875 if (f1 < 0 || f1 > 1.e9) 876 f1 = 0; 877 instance->offset = f1; /* offset in ns */ 878 } else if (!strncmp(cc, "MODE", 4)) { 879 sscanf(ca, "%d", &mode); 880 if (mode < 0 || mode > 4) 881 mode = 4; 882 instance->init_type = mode; 883 } else if (!strncmp(cc, "ASSERT", 6)) { 884 instance->assert = 1; 885 } else if (!strncmp(cc, "CLEAR", 5)) { 886 instance->assert = 0; 887 } 888 } 889 fclose(fd); 890 891 /* 892 * OK, have read all of data file, and extracted the good stuff. 893 * If lat/long/ht specified they ALL must be specified for mode = (1,3). 894 */ 895 896 instance->posn_set = 1; 897 if ((lat_flg || long_flg || ht_flg) && !(lat_flg * long_flg * ht_flg)) { 898 printf("ONCORE: incomplete data on %s\n", INIT_FILE); 899 instance->posn_set = 0; 900 if (mode == 1 || mode == 3) 901 instance->init_type++; 902 } 903 } 904 905 906 907 /* 908 * oncore_shutdown - shut down the clock 909 */ 910 static void 911 oncore_shutdown( 912 int unit, 913 struct peer *peer 914 ) 915 { 916 register struct instance *instance; 917 struct refclockproc *pp; 918 919 pp = peer->procptr; 920 instance = (struct instance *) pp->unitptr; 921 free(instance); 922 } 923 924 925 926 /* 927 * oncore_poll - called by the transmit procedure 928 */ 929 static void 930 oncore_poll( 931 int unit, 932 struct peer *peer 933 ) 934 { 935 struct instance *instance; 936 937 instance = (struct instance *) peer->procptr->unitptr; 938 if (instance->timeout) { 939 char *cp; 940 941 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof oncore_cmd_Cj); 942 instance->o_state = ONCORE_ID_SENT; 943 cp = "state = ONCORE_ID_SENT"; 944 record_clock_stats(&(instance->peer->srcadr), cp); 945 return; 946 } 947 948 if (!instance->pollcnt) 949 refclock_report(peer, CEVNT_TIMEOUT); 950 else 951 instance->pollcnt--; 952 peer->procptr->polls++; 953 instance->polled = 1; 954 } 955 956 957 958 /* 959 * move dta from NTP to buffer (toss in unlikely case it wont fit) 960 */ 961 static void 962 oncore_receive( 963 struct recvbuf *rbufp 964 ) 965 { 966 u_int i; 967 u_char *p; 968 struct peer *peer; 969 struct instance *instance; 970 971 peer = (struct peer *)rbufp->recv_srcclock; 972 instance = (struct instance *) peer->procptr->unitptr; 973 p = (u_char *) &rbufp->recv_space; 974 975 #if 0 976 if (debug > 4) { 977 int i; 978 printf("ONCORE: >>>"); 979 for(i=0; i<rbufp->recv_length; i++) 980 printf("%02x ", p[i]); 981 printf("\n"); 982 printf("ONCORE: >>>"); 983 for(i=0; i<rbufp->recv_length; i++) 984 printf("%03o ", p[i]); 985 printf("\n"); 986 } 987 #endif 988 989 i = rbufp->recv_length; 990 if (rcvbuf+rcvptr+i > &rcvbuf[sizeof rcvbuf]) 991 i = sizeof(rcvbuf) - rcvptr; /* and some char will be lost */ 992 memcpy(rcvbuf+rcvptr, p, i); 993 rcvptr += i; 994 oncore_consume(instance); 995 } 996 997 998 999 /* 1000 * Deal with any complete messages 1001 */ 1002 static void 1003 oncore_consume( 1004 struct instance *instance 1005 ) 1006 { 1007 int i, j, m; 1008 unsigned l; 1009 1010 while (rcvptr >= 7) { 1011 if (rcvbuf[0] != '@' || rcvbuf[1] != '@') { 1012 /* We're not in sync, lets try to get there */ 1013 for (i=1; i < rcvptr-1; i++) 1014 if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@') 1015 break; 1016 if (debug > 4) 1017 printf("ONCORE: >>> skipping %d chars\n", i); 1018 if (i != rcvptr) 1019 memcpy(rcvbuf, rcvbuf+i, (unsigned)(rcvptr-i)); 1020 rcvptr -= i; 1021 } 1022 1023 /* Ok, we have a header now */ 1024 l = sizeof(oncore_messages)/sizeof(oncore_messages[0]) -1; 1025 for(m=0; m<l; m++) 1026 if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), 2)) 1027 break; 1028 l = oncore_messages[m].len; 1029 #if 0 1030 if (debug > 3) 1031 printf("ONCORE: GOT: %c%c %d of %d entry %d\n", rcvbuf[2], rcvbuf[3], rcvptr, l, m); 1032 #endif 1033 /* Got the entire message ? */ 1034 1035 if (rcvptr < l) 1036 return; 1037 1038 /* Check the checksum */ 1039 1040 j = 0; 1041 for (i = 2; i < l-3; i++) 1042 j ^= rcvbuf[i]; 1043 if (j == rcvbuf[l-3]) { 1044 if (instance->shmem != NULL) 1045 memcpy(instance->shmem + oncore_messages[m].shmem + 2, 1046 rcvbuf, l); 1047 oncore_msg_any(instance, rcvbuf, (unsigned) (l-3), m); 1048 if (oncore_messages[m].handler) 1049 oncore_messages[m].handler(instance, rcvbuf, (unsigned) (l-3)); 1050 } else if (debug) { 1051 printf("ONCORE: Checksum mismatch! calc %o is %o\n", j, rcvbuf[l-3]); 1052 printf("ONCORE: @@%c%c ", rcvbuf[2], rcvbuf[3]); 1053 for (i=4; i<l; i++) 1054 printf("%03o ", rcvbuf[i]); 1055 printf("\n"); 1056 } 1057 1058 if (l != rcvptr) 1059 memcpy(rcvbuf, rcvbuf+l, (unsigned) (rcvptr-l)); 1060 rcvptr -= l; 1061 } 1062 } 1063 1064 1065 1066 /* 1067 * write message to Oncore. 1068 */ 1069 static void 1070 oncore_sendmsg( 1071 int fd, 1072 u_char *ptr, 1073 u_int len 1074 ) 1075 { 1076 u_char cs = 0; 1077 1078 printf("ONCORE: Send @@%c%c %d\n", ptr[0], ptr[1], len); 1079 write(fd, "@@", 2); 1080 write(fd, ptr, len); 1081 while (len--) 1082 cs ^= *ptr++; 1083 write(fd, &cs, 1); 1084 write(fd, "\r\n", 2); 1085 } 1086 1087 1088 1089 static void 1090 oncore_msg_any( 1091 struct instance *instance, 1092 u_char *buf, 1093 u_int len, 1094 int idx 1095 ) 1096 { 1097 int i; 1098 const char *fmt = oncore_messages[idx].fmt; 1099 const char *p; 1100 struct timeval tv; 1101 1102 if (debug > 3) { 1103 GETTIMEOFDAY(&tv, 0); 1104 printf("ONCORE: %ld.%06ld\n", (long) tv.tv_sec, (long) tv.tv_usec); 1105 1106 if (!*fmt) { 1107 printf(">>@@%c%c ", buf[2], buf[3]); 1108 for(i=2; i < len && i < 2400 ; i++) 1109 printf("%02x", buf[i]); 1110 printf("\n"); 1111 return; 1112 } else { 1113 printf("##"); 1114 for (p = fmt; *p; p++) { 1115 putchar(*p); 1116 putchar('_'); 1117 } 1118 printf("\n%c%c", buf[2], buf[3]); 1119 i = 4; 1120 for (p = fmt; *p; p++) { 1121 printf("%02x", buf[i++]); 1122 } 1123 printf("\n"); 1124 } 1125 } 1126 } 1127 1128 1129 1130 /* 1131 * Demultiplex the almanac into shmem 1132 */ 1133 static void 1134 oncore_msg_Cb( 1135 struct instance *instance, 1136 u_char *buf, 1137 u_int len 1138 ) 1139 { 1140 int i; 1141 1142 if (instance->shmem == NULL) 1143 return; 1144 1145 if (buf[4] == 5) 1146 i = buf[5]; 1147 else if (buf[4] == 4 && buf[5] <= 5) 1148 i = buf[5] + 24; 1149 else if (buf[4] == 4 && buf[5] <= 10) 1150 i = buf[5] + 23; 1151 else 1152 i = 34; 1153 i *= 35; 1154 memcpy(instance->shmem + oncore_shmem_Cb + i + 2, buf, len + 3); 1155 } 1156 1157 /* 1158 * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup 1159 * not so for VP (eeprom) or UT with battery 1160 */ 1161 static void 1162 oncore_msg_Cf( 1163 struct instance *instance, 1164 u_char *buf, 1165 u_int len 1166 ) 1167 { 1168 const char *cp; 1169 1170 if (instance->o_state == ONCORE_RESET_SENT) { 1171 oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof oncore_cmd_Fa); 1172 instance->o_state = ONCORE_TEST_SENT; 1173 cp = "state = ONCORE_TEST_SENT"; 1174 record_clock_stats(&(instance->peer->srcadr), cp); 1175 } 1176 } 1177 1178 1179 1180 /* there are good reasons NOT to do a @@Fa command with the ONCORE. 1181 * Doing it, it was found that under some circumstances the following 1182 * command would fail if issued immediately after the return from the 1183 * @@Fa, but a 2sec delay seemed to fix things. Since simply calling 1184 * sleep(2) is wastefull, and may cause trouble for some OS's, repeating 1185 * itimer, we set a flag, and test it at the next POLL. If it hasnt 1186 * been cleared, we reissue the @@Ca that is issued below. 1187 */ 1188 1189 static void 1190 oncore_msg_Fa( 1191 struct instance *instance, 1192 u_char *buf, 1193 u_int len 1194 ) 1195 { 1196 const char *cp; 1197 1198 if (instance->o_state == ONCORE_TEST_SENT) { 1199 if (debug > 2) 1200 printf("ONCORE: >>@@Fa %x %x\n", buf[4], buf[5]); 1201 if (buf[4] || buf[5]) { 1202 printf("ONCORE: SELF TEST FAILED\n"); 1203 exit(1); 1204 } 1205 1206 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof oncore_cmd_Cj); 1207 instance->o_state = ONCORE_ID_SENT; 1208 cp = "state = ONCORE_ID_SENT"; 1209 record_clock_stats(&(instance->peer->srcadr), cp); 1210 } 1211 } 1212 1213 1214 1215 /* 1216 * preliminaries out of the way, this is the REAL start of initialization 1217 */ 1218 static void 1219 oncore_msg_Cj( 1220 struct instance *instance, 1221 u_char *buf, 1222 u_int len 1223 ) 1224 { 1225 char *cp, *cp1; 1226 int mode; 1227 1228 instance->timeout = 0; 1229 if (instance->o_state != ONCORE_ID_SENT) 1230 return; 1231 1232 memcpy(instance->Cj, buf, len); 1233 1234 /* Write Receiver ID to clockstats file */ 1235 1236 instance->Cj[294] = '\0'; 1237 for (cp=(char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) { 1238 cp1 = strchr(cp, '\r'); 1239 if (!cp1) 1240 cp1 = (char *)&instance->Cj[294]; 1241 *cp1 = '\0'; 1242 record_clock_stats(&(instance->peer->srcadr), cp); 1243 *cp1 = '\r'; 1244 cp = cp1+2; 1245 } 1246 #ifdef HAVE_PPSAPI 1247 if (instance->assert) 1248 cp = "Timing on Assert."; 1249 else 1250 cp = "Timing on Clear."; 1251 record_clock_stats(&(instance->peer->srcadr), cp); 1252 #endif 1253 1254 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof oncore_cmd_Cg); /* Set Posn Fix mode (not Idle (VP)) */ 1255 oncore_sendmsg(instance->ttyfd, oncore_cmd_Bb, sizeof oncore_cmd_Bb); /* turn off */ 1256 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ek, sizeof oncore_cmd_Ek); /* turn off */ 1257 oncore_sendmsg(instance->ttyfd, oncore_cmd_Aw, sizeof oncore_cmd_Aw); /* UTC time */ 1258 oncore_sendmsg(instance->ttyfd, oncore_cmd_AB, sizeof oncore_cmd_AB); /* Appl type static */ 1259 oncore_sendmsg(instance->ttyfd, oncore_cmd_Be, sizeof oncore_cmd_Be); /* Tell us the Almanac */ 1260 1261 mode = instance->init_type; 1262 if (debug) 1263 printf("ONCORE: INIT mode = %d\n", mode); 1264 1265 /* If there is Position input in the Config file 1266 * and mode = (1,3) set it as posn hold posn, goto 0D mode. 1267 * or mode = (2,4) set it as INITIAL position, and Site Survey. 1268 */ 1269 1270 switch (mode) { 1271 case 0: /* NO initialization, don't change anything */ 1272 instance->site_survey = ONCORE_SS_DONE; 1273 break; 1274 1275 case 1: 1276 case 3: 1277 w32_buf(&oncore_cmd_As[2], (int) instance->ss_lat); 1278 w32_buf(&oncore_cmd_As[6], (int) instance->ss_long); 1279 w32_buf(&oncore_cmd_As[10], (int) instance->ss_ht); 1280 oncore_cmd_As[14] = instance->ss_ht_type; 1281 oncore_sendmsg(instance->ttyfd, oncore_cmd_As, sizeof oncore_cmd_As); 1282 1283 instance->site_survey = ONCORE_SS_DONE; 1284 oncore_cmd_At[2] = 1; 1285 oncore_sendmsg(instance->ttyfd, oncore_cmd_At, sizeof oncore_cmd_At); 1286 record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode"); 1287 break; 1288 1289 case 2: 1290 case 4: 1291 if (instance->posn_set) { 1292 w32_buf(&oncore_cmd_Ad[2], (int) instance->ss_lat); 1293 w32_buf(&oncore_cmd_Ae[2], (int) instance->ss_long); 1294 w32_buf(&oncore_cmd_Af[2], (int) instance->ss_ht); 1295 oncore_cmd_Af[6] = instance->ss_ht_type; 1296 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ad, sizeof oncore_cmd_Ad); 1297 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ae, sizeof oncore_cmd_Ae); 1298 oncore_sendmsg(instance->ttyfd, oncore_cmd_Af, sizeof oncore_cmd_Af); 1299 } 1300 instance->site_survey = ONCORE_SS_UNKNOWN; 1301 oncore_cmd_At[2] = 2; 1302 oncore_sendmsg(instance->ttyfd, oncore_cmd_At, sizeof oncore_cmd_At); 1303 break; 1304 } 1305 1306 if (mode != 0) { 1307 /* cable delay in ns */ 1308 w32_buf(&oncore_cmd_Az[2], instance->delay); 1309 oncore_sendmsg(instance->ttyfd, oncore_cmd_Az, sizeof oncore_cmd_Az); 1310 1311 /* PPS offset in ns */ 1312 w32_buf(&oncore_cmd_Ay[2], instance->offset); 1313 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ay, sizeof oncore_cmd_Ay); 1314 } 1315 1316 /* 8chan - Position/Status/Data Output Message, 1/s */ 1317 1318 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea, sizeof oncore_cmd_Ea); 1319 1320 instance->o_state = ONCORE_ALMANAC; 1321 cp = "state = ONCORE_ALMANAC"; 1322 record_clock_stats(&(instance->peer->srcadr), cp); 1323 } 1324 1325 1326 1327 static void 1328 oncore_msg_Ea( 1329 struct instance *instance, 1330 u_char *buf, 1331 u_int len 1332 ) 1333 { 1334 const char *cp; 1335 char Msg[160]; 1336 1337 if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN) 1338 return; 1339 1340 memcpy(instance->Ea, buf, len); 1341 1342 /* When we have an almanac, start the En messages */ 1343 1344 if (instance->o_state == ONCORE_ALMANAC) { 1345 if ((instance->Ea[72] & 1)) { 1346 if (debug) 1347 printf("ONCORE: waiting for almanac\n"); 1348 return; 1349 } else { 1350 oncore_sendmsg(instance->ttyfd, oncore_cmd_En, sizeof oncore_cmd_En); 1351 instance->o_state = ONCORE_RUN; 1352 cp = "state = ONCORE_RUN"; 1353 record_clock_stats(&(instance->peer->srcadr), cp); 1354 } 1355 } 1356 1357 /* must be ONCORE_RUN if we are here */ 1358 /* First check if Hardware SiteSurvey has Finished */ 1359 1360 if ((instance->site_survey == ONCORE_SS_HW) && !(instance->Ea[37] & 0x20)) { 1361 instance->site_survey = ONCORE_SS_DONE; 1362 record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode"); 1363 } 1364 1365 if (!instance->printed && instance->site_survey == ONCORE_SS_DONE) { /* will print to clockstat when all */ 1366 instance->printed = 1; /* three messages respond */ 1367 /* Read back Position Hold Params */ 1368 oncore_sendmsg(instance->ttyfd, oncore_cmd_Asx, sizeof oncore_cmd_Asx); 1369 /* Read back PPS Offset for Output */ 1370 /* Nb. This will fail silently for early UT (no plus) model */ 1371 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ayx, sizeof oncore_cmd_Ayx); 1372 /* Read back Cable Delay for Output */ 1373 oncore_sendmsg(instance->ttyfd, oncore_cmd_Azx, sizeof oncore_cmd_Azx); 1374 } 1375 1376 /* Check the leap second status once per day */ 1377 1378 /* 1379 * The following additional check, checking for June/December, is a 1380 * workaround for incorrect ONCORE firmware. The oncore starts 1381 * reporting the leap second when the GPS satellite data message 1382 * (page 18, subframe 4) is updated to a date in the future, which 1383 * which can be several months before the leap second. WWV and other 1384 * services seem to wait until the month of the event to turn 1385 * on their indicators (which are usually a single bit). 1386 */ 1387 1388 if ((buf[4] == 6) || (buf[4] == 12)) { 1389 if (instance->Bj_day != buf[5]) { /* do this 1/day */ 1390 instance->Bj_day = buf[5]; 1391 oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof oncore_cmd_Bj); 1392 } 1393 } 1394 instance->pp->year = buf[6]*256+buf[7]; 1395 instance->pp->day = ymd2yd(buf[6]*256+buf[7], buf[4], buf[5]); 1396 instance->pp->hour = buf[8]; 1397 instance->pp->minute = buf[9]; 1398 instance->pp->second = buf[10]; 1399 1400 if (instance->site_survey != ONCORE_SS_SW) 1401 return; 1402 1403 /* 1404 * We have to average our own position for the Position Hold Mode 1405 */ 1406 1407 /* We only take PDOP/3D fixes */ 1408 1409 if (instance->Ea[37] & 1) 1410 return; 1411 1412 /* Not if poor geometry or less than 3 sats */ 1413 1414 if (instance->Ea[72] & 0x52) 1415 return; 1416 1417 /* Only 3D fix */ 1418 1419 if (!(instance->Ea[72] & 0x20)) 1420 return; 1421 1422 instance->ss_lat += buf_w32(&instance->Ea[15]); 1423 instance->ss_long += buf_w32(&instance->Ea[19]); 1424 instance->ss_ht += buf_w32(&instance->Ea[23]); /* GPS ellipse */ 1425 instance->ss_count++; 1426 1427 if (instance->ss_count != POS_HOLD_AVERAGE) 1428 return; 1429 1430 instance->ss_lat /= POS_HOLD_AVERAGE; 1431 instance->ss_long /= POS_HOLD_AVERAGE; 1432 instance->ss_ht /= POS_HOLD_AVERAGE; 1433 1434 sprintf(Msg, "Surveyed posn: lat %.3f long %.3f ht %.3f", 1435 instance->ss_lat, instance->ss_long, instance->ss_ht); 1436 record_clock_stats(&(instance->peer->srcadr), Msg); 1437 1438 w32_buf(&oncore_cmd_As[2], (int) instance->ss_lat); 1439 w32_buf(&oncore_cmd_As[6], (int) instance->ss_long); 1440 w32_buf(&oncore_cmd_As[10], (int) instance->ss_ht); 1441 oncore_cmd_As[14] = 0; 1442 oncore_sendmsg(instance->ttyfd, oncore_cmd_As, sizeof oncore_cmd_As); 1443 1444 oncore_cmd_At[2] = 1; 1445 oncore_sendmsg(instance->ttyfd, oncore_cmd_At, sizeof oncore_cmd_At); 1446 record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode"); 1447 instance->site_survey = ONCORE_SS_DONE; 1448 } 1449 1450 1451 1452 static void 1453 oncore_msg_En( 1454 struct instance *instance, 1455 u_char *buf, 1456 u_int len 1457 ) 1458 { 1459 int j; 1460 l_fp ts, ts_tmp; 1461 double dmy; 1462 #ifdef HAVE_TIMESPEC 1463 struct timespec *tsp = 0; 1464 #else 1465 struct timeval *tsp = 0; 1466 #endif 1467 #ifdef HAVE_PPSAPI 1468 struct timespec timeout; 1469 pps_info_t pps_i; 1470 #else /* ! HAVE_PPSAPI */ 1471 #ifdef HAVE_CIOGETEV 1472 struct ppsclockev ev; 1473 int r = CIOGETEV; 1474 #endif 1475 #ifdef HAVE_TIOCGPPSEV 1476 struct ppsclockev ev; 1477 int r = TIOCGPPSEV; 1478 #endif 1479 #if TIOCDCDTIMESTAMP 1480 struct timeval tv; 1481 #endif 1482 #endif /* ! HAVE_PPS_API */ 1483 1484 if (instance->o_state != ONCORE_RUN) 1485 return; 1486 1487 memcpy(instance->En, buf, len); 1488 1489 /* Don't do anything without an almanac to define the GPS->UTC delta */ 1490 1491 if (instance->Ea[72] & 1) 1492 return; 1493 1494 /* If Time RAIM doesn't like it, don't trust it */ 1495 1496 if (instance->En[21]) 1497 return; 1498 1499 #ifdef HAVE_PPSAPI 1500 j = instance->ev_serial; 1501 timeout.tv_sec = 0; 1502 timeout.tv_nsec = 0; 1503 if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i, 1504 &timeout) < 0) { 1505 printf("ONCORE: time_pps_fetch failed\n"); 1506 return; 1507 } 1508 1509 if (instance->assert) { 1510 tsp = &pps_i.assert_timestamp; 1511 1512 if (debug > 2) 1513 printf("ONCORE: serial/j (%d, %d) %ld.%09ld\n", 1514 pps_i.assert_sequence, j, tsp->tv_sec, tsp->tv_nsec); 1515 1516 if (pps_i.assert_sequence == j) { 1517 printf("ONCORE: oncore_msg_En, error serial pps\n"); 1518 return; 1519 } 1520 instance->ev_serial = pps_i.assert_sequence; 1521 } else { 1522 tsp = &pps_i.clear_timestamp; 1523 1524 if (debug > 2) 1525 printf("ONCORE: serial/j (%d, %d) %ld.%09ld\n", 1526 pps_i.clear_sequence, j, tsp->tv_sec, tsp->tv_nsec); 1527 1528 if (pps_i.clear_sequence == j) { 1529 printf("ONCORE: oncore_msg_En, error serial pps\n"); 1530 return; 1531 } 1532 instance->ev_serial = pps_i.clear_sequence; 1533 } 1534 1535 /* convert timespec -> ntp l_fp */ 1536 1537 dmy = tsp->tv_nsec; 1538 dmy /= 1e9; 1539 ts.l_uf = dmy * 4294967296.0; 1540 ts.l_ui = tsp->tv_sec; 1541 #if 0 1542 alternate code for previous 4 lines is 1543 dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */ 1544 DTOLFP(dmy, &ts); 1545 dmy = tsp->tv_sec; /* integer part */ 1546 DTOLFP(dmy, &ts_tmp); 1547 L_ADD(&ts, &ts_tmp); 1548 or more simply 1549 dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */ 1550 DTOLFP(dmy, &ts); 1551 ts.l_ui = tsp->tv_sec; 1552 #endif /* 0 */ 1553 #else 1554 # if defined(HAVE_TIOCGPPSEV) || defined(HAVE_CIOGETEV) 1555 j = instance->ev_serial; 1556 if (ioctl(instance->ppsfd, r, (caddr_t) &ev) < 0) { 1557 perror("ONCORE: IOCTL:"); 1558 return; 1559 } 1560 1561 tsp = &ev.tv; 1562 1563 if (debug > 2) 1564 printf("ONCORE: serial/j (%d, %d) %ld.%06ld\n", 1565 ev.serial, j, tsp->tv_sec, tsp->tv_usec); 1566 1567 if (ev.serial == j) { 1568 printf("ONCORE: oncore_msg_En, error serial pps\n"); 1569 return; 1570 } 1571 instance->ev_serial = ev.serial; 1572 1573 /* convert timeval -> ntp l_fp */ 1574 1575 TVTOTS(tsp, &ts); 1576 # else 1577 # if defined(TIOCDCDTIMESTAMP) 1578 if(ioctl(instance->ppsfd, TIOCDCDTIMESTAMP, &tv) < 0) { 1579 perror("ONCORE: ioctl(TIOCDCDTIMESTAMP)"); 1580 return; 1581 } 1582 tsp = &tv; 1583 TVTOTS(tsp, &ts); 1584 # else 1585 #error "Cannot compile -- no PPS mechanism configured!" 1586 # endif 1587 # endif 1588 #endif 1589 /* now have timestamp in ts */ 1590 /* add in saw_tooth and offset */ 1591 1592 /* saw_tooth not really necessary if using TIMEVAL */ 1593 /* since its only precise to us, but do it anyway. */ 1594 1595 /* offset in ns, and is positive (late), we subtract */ 1596 /* to put the PPS time transition back where it belongs */ 1597 1598 j = instance->saw_tooth + instance->offset; 1599 instance->saw_tooth = (s_char) buf[25]; /* update for next time */ 1600 #ifdef HAVE_PPSAPI 1601 /* must hand this offset off to the Kernel to do the addition */ 1602 /* so that the Kernel PLL sees the offset too */ 1603 1604 if (instance->assert) { 1605 instance->pps_p.assert_offset.tv_nsec = 1606 -(instance->saw_tooth + instance->offset); 1607 } else { 1608 instance->pps_p.clear_offset.tv_nsec = 1609 -(instance->saw_tooth + instance->offset); 1610 } 1611 1612 if (time_pps_setparams(instance->pps_h, &instance->pps_p)) 1613 perror("time_pps_setparams"); 1614 #else 1615 /* if not PPSAPI, no way to inform kernel of OFFSET, just do it */ 1616 1617 dmy = -1.0e-9*j; 1618 DTOLFP(dmy, &ts_tmp); 1619 L_ADD(&ts, &ts_tmp); 1620 #endif 1621 /* have time from UNIX origin, convert to NTP origin. */ 1622 1623 ts.l_ui += JAN_1970; 1624 instance->pp->lastrec = ts; 1625 instance->pp->msec = 0; 1626 1627 ts_tmp = ts; 1628 ts_tmp.l_ui = 0; /* zero integer part */ 1629 LFPTOD(&ts_tmp, dmy); /* convert fractional part to a double */ 1630 j = 1.0e9*dmy; /* then to integer ns */ 1631 sprintf(instance->pp->a_lastcode, 1632 "%u.%09u %d %d %2d %2d %2d %2ld rstat %02x dop %d nsat %2d,%d raim %d sigma %d neg-sawtooth %3d sat %d%d%d%d%d%d%d%d", 1633 ts.l_ui, j, 1634 instance->pp->year, instance->pp->day, 1635 instance->pp->hour, instance->pp->minute, instance->pp->second, 1636 (long) tsp->tv_sec % 60, 1637 1638 instance->Ea[72], instance->Ea[37], instance->Ea[38], instance->Ea[39], instance->En[21], 1639 /*rstat dop nsat visible, nsat tracked, raim */ 1640 instance->En[23]*256+instance->En[24], (s_char) buf[25], 1641 /* sigma neg-sawtooth */ 1642 /*sat*/ instance->Ea[41], instance->Ea[45], instance->Ea[49], instance->Ea[53], 1643 instance->Ea[57], instance->Ea[61], instance->Ea[65], instance->Ea[69] 1644 ); 1645 1646 if (debug > 2) { 1647 int i; 1648 i = strlen(instance->pp->a_lastcode); 1649 printf("ONCORE: len = %d %s\n", i, instance->pp->a_lastcode); 1650 } 1651 1652 if (!refclock_process(instance->pp)) { 1653 refclock_report(instance->peer, CEVNT_BADTIME); 1654 return; 1655 } 1656 1657 record_clock_stats(&(instance->peer->srcadr), instance->pp->a_lastcode); 1658 instance->pollcnt = 2; 1659 1660 if (instance->polled) { 1661 instance->polled = 0; 1662 /* 1663 instance->pp->dispersion = instance->pp->skew = 0; 1664 */ 1665 refclock_receive(instance->peer); 1666 } 1667 } 1668 1669 1670 1671 /* 1672 * Try to use Oncore UT+ Auto Survey Feature 1673 * If its not there (VP), set flag to do it ourselves. 1674 */ 1675 static void 1676 oncore_msg_At( 1677 struct instance *instance, 1678 u_char *buf, 1679 u_int len 1680 ) 1681 { 1682 if (instance->site_survey != ONCORE_SS_UNKNOWN) 1683 return; 1684 1685 if (buf[4] == 2) { 1686 record_clock_stats(&(instance->peer->srcadr), 1687 "Initiating hardware 3D site survey"); 1688 instance->site_survey = ONCORE_SS_HW; 1689 } else { 1690 char Msg[160]; 1691 /* 1692 * Probably a VP or an older UT which can't do site-survey. 1693 * We will have to do it ourselves 1694 */ 1695 1696 sprintf(Msg, "Initiating software 3D site survey (%d samples)", 1697 POS_HOLD_AVERAGE); 1698 record_clock_stats(&(instance->peer->srcadr), Msg); 1699 instance->site_survey = ONCORE_SS_SW; 1700 1701 oncore_cmd_At[2] = 0; 1702 instance->ss_lat = instance->ss_long = instance->ss_ht = 0; 1703 oncore_sendmsg(instance->ttyfd, oncore_cmd_At, sizeof oncore_cmd_At); 1704 } 1705 } 1706 1707 1708 1709 /* get leap-second warning message */ 1710 1711 /* 1712 * @@Bj does NOT behave as documented in current Oncore firmware. 1713 * It turns on the LEAP indicator when the data is set, and does not, 1714 * as documented, wait until the beginning of the month when the 1715 * leap second will occur. 1716 * Until this firmware bug is fixed, @@Bj is only called in June/December. 1717 */ 1718 1719 static void 1720 oncore_msg_Bj( 1721 struct instance *instance, 1722 u_char *buf, 1723 u_int len 1724 ) 1725 { 1726 const char *cp; 1727 1728 switch(buf[4]) { 1729 case 1: 1730 instance->peer->leap = LEAP_ADDSECOND; 1731 cp = "Set peer.leap to LEAP_ADDSECOND"; 1732 break; 1733 case 2: 1734 instance->peer->leap = LEAP_DELSECOND; 1735 cp = "Set peer.leap to LEAP_DELSECOND"; 1736 break; 1737 case 0: 1738 default: 1739 instance->peer->leap = LEAP_NOWARNING; 1740 cp = "Set peer.leap to LEAP_NOWARNING"; 1741 break; 1742 } 1743 record_clock_stats(&(instance->peer->srcadr), cp); 1744 } 1745 1746 1747 1748 /* 1749 * get Position hold position 1750 */ 1751 static void 1752 oncore_msg_As( 1753 struct instance *instance, 1754 u_char *buf, 1755 u_int len 1756 ) 1757 { 1758 char Msg[120], ew, ns; 1759 const char *Ht; 1760 double xd, xm, xs, yd, ym, ys, hm, hft; 1761 int idx, idy, is, imx, imy; 1762 long lat, lon, ht; 1763 1764 if (!instance->printed || instance->As) 1765 return; 1766 1767 instance->As = 1; 1768 1769 lat = buf_w32(&buf[4]); 1770 instance->ss_lat = lat; 1771 1772 lon = buf_w32(&buf[8]); 1773 instance->ss_long = lon; 1774 1775 ht = buf_w32(&buf[12]); 1776 instance->ss_ht = ht; 1777 1778 instance->ss_ht_type = buf[16]; 1779 1780 /* Print out Position */ 1781 1782 record_clock_stats(&(instance->peer->srcadr), "Posn:"); 1783 ew = 'E'; 1784 lon = instance->ss_long; 1785 if (lon < 0) { 1786 ew = 'W'; 1787 lon = -lon; 1788 } 1789 1790 ns = 'N'; 1791 lat = instance->ss_lat; 1792 if (lat < 0) { 1793 ns = 'S'; 1794 lat = -lat; 1795 } 1796 1797 hm = instance->ss_ht/100.; 1798 hft= hm/0.3048; 1799 Ht = instance->ss_ht_type ? "MSL" : "GPS"; 1800 1801 xd = lat/3600000.; /* lat, lon in int msec arc, ht in cm. */ 1802 yd = lon/3600000.; 1803 sprintf(Msg, "Lat = %c %11.7fdeg, Long = %c %11.7fdeg, Alt = %5.2fm (%5.2fft) %s", ns, xd, ew, yd, hm, hft, Ht); 1804 record_clock_stats(&(instance->peer->srcadr), Msg); 1805 1806 idx = xd; 1807 idy = yd; 1808 imx = lat%3600000; 1809 imy = lon%3600000; 1810 xm = imx/60000.; 1811 ym = imy/60000.; 1812 sprintf(Msg, "Lat = %c %3ddeg %7.4fm, Long = %c %3ddeg %8.5fm, Alt = %5.2fm (%5.2fft) %s", ns, idx, xm, ew, idy, ym, hm, hft, Ht); 1813 record_clock_stats(&(instance->peer->srcadr), Msg); 1814 1815 imx = xm; 1816 imy = ym; 1817 is = lat%60000; 1818 xs = is/1000.; 1819 is = lon%60000; 1820 ys = is/1000.; 1821 sprintf(Msg, "Lat = %c %3ddeg %2dm %5.2fs, Long = %c %3ddeg %2dm %5.2fs, Alt = %5.2fm (%5.2fft) %s", ns, idx, imx, xs, ew, idy, imy, ys, hm, hft, Ht); 1822 record_clock_stats(&(instance->peer->srcadr), Msg); 1823 } 1824 1825 1826 1827 /* 1828 * get PPS Offset 1829 * Nb. @@Ay is not supported for early UT (no plus) model 1830 */ 1831 static void 1832 oncore_msg_Ay( 1833 struct instance *instance, 1834 u_char *buf, 1835 u_int len 1836 ) 1837 { 1838 char Msg[120]; 1839 1840 if (!instance->printed || instance->Ay) 1841 return; 1842 1843 instance->Ay = 1; 1844 1845 instance->offset = buf_w32(&buf[4]); 1846 1847 sprintf(Msg, "PPS Offset is set to %ld ns", instance->offset); 1848 record_clock_stats(&(instance->peer->srcadr), Msg); 1849 } 1850 1851 1852 1853 /* 1854 * get Cable Delay 1855 */ 1856 static void 1857 oncore_msg_Az( 1858 struct instance *instance, 1859 u_char *buf, 1860 u_int len 1861 ) 1862 { 1863 char Msg[120]; 1864 1865 if (!instance->printed || instance->Az) 1866 return; 1867 1868 instance->Az = 1; 1869 1870 instance->delay = buf_w32(&buf[4]); 1871 1872 sprintf(Msg, "Cable delay is set to %ld ns", instance->delay); 1873 record_clock_stats(&(instance->peer->srcadr), Msg); 1874 } 1875 #else 1876 int refclock_oncore_bs; 1877 #endif /* REFCLOCK */ 1878