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 * should work with Basic, PVT6, VP, UT, UT+, GT, GT+, SL, M12. 13 * The receivers with TRAIM (VP, UT, UT+), will be more accurate than the others. 14 * The receivers without position hold (GT, GT+) will be less accurate. 15 * 16 * Tested with: 17 * 18 * (UT) (VP) 19 * COPYRIGHT 1991-1997 MOTOROLA INC. COPYRIGHT 1991-1996 MOTOROLA INC. 20 * SFTW P/N # 98-P36848P SFTW P/N # 98-P36830P 21 * SOFTWARE VER # 2 SOFTWARE VER # 8 22 * SOFTWARE REV # 2 SOFTWARE REV # 8 23 * SOFTWARE DATE APR 24 1998 SOFTWARE DATE 06 Aug 1996 24 * MODEL # R1121N1114 MODEL # B4121P1155 25 * HWDR P/N # 1 HDWR P/N # _ 26 * SERIAL # R0010A SERIAL # SSG0226478 27 * MANUFACTUR DATE 6H07 MANUFACTUR DATE 7E02 28 * OPTIONS LIST IB 29 * 30 * (Basic) (M12) 31 * COPYRIGHT 1991-1996 MOTOROLA INC. COPYRIGHT 1991-2000 MOTOROLA INC. 32 * SFTW P/N # 98-P36830P SFTW P/N # 61-G10002A 33 * SOFTWARE VER # 8 SOFTWARE VER # 1 34 * SOFTWARE REV # 8 SOFTWARE REV # 3 35 * SOFTWARE DATE 06 Aug 1996 SOFTWARE DATE Mar 13 2000 36 * MODEL # B4121P1155 MODEL # P143T12NR1 37 * HDWR P/N # _ HWDR P/N # 1 38 * SERIAL # SSG0226478 SERIAL # P003UD 39 * MANUFACTUR DATE 7E02 MANUFACTUR DATE 0C27 40 * OPTIONS LIST IB 41 * 42 * -------------------------------------------------------------------------- 43 * This code uses the two devices 44 * /dev/oncore.serial.n 45 * /dev/oncore.pps.n 46 * which may be linked to the same device. 47 * and can read initialization data from the file 48 * /etc/ntp.oncoreN, /etc/ntp.oncore.N, or /etc/ntp.oncore, where 49 * n or N are the unit number, viz 127.127.30.N. 50 * -------------------------------------------------------------------------- 51 * Reg.Clemens <reg@dwf.com> Sep98. 52 * Original code written for FreeBSD. 53 * With these mods it works on FreeBSD, SunOS, Solaris and Linux 54 * (SunOS 4.1.3 + ppsclock) 55 * (Solaris7 + MU4) 56 * (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + or later). 57 * 58 * Lat,Long,Ht, cable-delay, offset, and the ReceiverID (along with the 59 * state machine state) are printed to CLOCKSTATS if that file is enabled 60 * in /etc/ntp.conf. 61 * 62 * -------------------------------------------------------------------------- 63 * 64 * According to the ONCORE manual (TRM0003, Rev 3.2, June 1998, page 3.13) 65 * doing an average of 10000 valid 2D and 3D fixes is what the automatic 66 * site survey mode does. Looking at the output from the receiver 67 * it seems like it is only using 3D fixes. 68 * When we do it ourselves, take 10000 3D fixes. 69 */ 70 71 #define POS_HOLD_AVERAGE 10000 /* nb, 10000s ~= 2h45m */ 72 73 /* 74 * ONCORE_SHMEM_STATUS will create a mmap(2)'ed file named according to a 75 * "STATUS" line in the oncore config file, which contains the most recent 76 * copy of all types of messages we recognize. This file can be mmap(2)'ed 77 * by monitoring and statistics programs. 78 * 79 * See separate HTML documentation for this option. 80 */ 81 82 #ifdef HAVE_CONFIG_H 83 #include <config.h> 84 #endif 85 86 #if defined(REFCLOCK) && defined(CLOCK_ONCORE) && defined(HAVE_PPSAPI) 87 88 #include "ntpd.h" 89 #include "ntp_io.h" 90 #include "ntp_unixtime.h" 91 #include "ntp_refclock.h" 92 #include "ntp_stdlib.h" 93 94 #include <stdio.h> 95 #include <ctype.h> 96 #include <sys/stat.h> 97 #ifdef ONCORE_SHMEM_STATUS 98 # ifdef HAVE_SYS_MMAN_H 99 # include <sys/mman.h> 100 # ifndef MAP_FAILED 101 # define MAP_FAILED ((u_char *) -1) 102 # endif /* not MAP_FAILED */ 103 # endif /* HAVE_SYS_MMAN_H */ 104 #endif /* ONCORE_SHMEM_STATUS */ 105 106 #ifdef HAVE_PPSAPI 107 # ifdef HAVE_TIMEPPS_H 108 # include <timepps.h> 109 # else 110 # ifdef HAVE_SYS_TIMEPPS_H 111 # include <sys/timepps.h> 112 # endif 113 # endif 114 #endif 115 116 #ifdef HAVE_SYS_SIO_H 117 # include <sys/sio.h> 118 #endif 119 120 #ifdef HAVE_SYS_TERMIOS_H 121 # include <sys/termios.h> 122 #endif 123 124 #ifdef HAVE_SYS_PPSCLOCK_H 125 # include <sys/ppsclock.h> 126 #endif 127 128 #ifndef HAVE_STRUCT_PPSCLOCKEV 129 struct ppsclockev { 130 # ifdef HAVE_STRUCT_TIMESPEC 131 struct timespec tv; 132 # else 133 struct timeval tv; 134 # endif 135 u_int serial; 136 }; 137 #endif /* not HAVE_STRUCT_PPSCLOCKEV */ 138 139 enum receive_state { 140 ONCORE_NO_IDEA, 141 ONCORE_ID_SENT, 142 ONCORE_RESET_SENT, 143 ONCORE_TEST_SENT, 144 ONCORE_INIT, 145 ONCORE_ALMANAC, 146 ONCORE_RUN 147 }; 148 149 enum site_survey_state { 150 ONCORE_SS_UNKNOWN, 151 ONCORE_SS_TESTING, 152 ONCORE_SS_HW, 153 ONCORE_SS_SW, 154 ONCORE_SS_DONE 155 }; 156 157 /* Model Name, derived from the @@Cj message. 158 * Used to initialize some variables. 159 */ 160 161 enum oncore_model { 162 ONCORE_BASIC, 163 ONCORE_PVT6, 164 ONCORE_VP, 165 ONCORE_UT, 166 ONCORE_UTPLUS, 167 ONCORE_GT, 168 ONCORE_GTPLUS, 169 ONCORE_SL, 170 ONCORE_M12, 171 ONCORE_UNKNOWN 172 }; 173 174 /* the bits that describe these properties are in the same place 175 * on the VP/UT, but have moved on the M12. As such we extract 176 * them, and use them from this struct. 177 * 178 */ 179 180 struct RSM { 181 u_char posn0D; 182 u_char posn2D; 183 u_char posn3D; 184 u_char bad_almanac; 185 u_char bad_fix; 186 }; 187 188 /* It is possible to test the VP/UT each cycle (@@Ea or equivalent) to 189 * see what mode it is in. The bits on the M12 are multiplexed with 190 * other messages, so we have to 'keep' the last known mode here. 191 */ 192 193 enum posn_mode { 194 MODE_UNKNOWN, 195 MODE_0D, 196 MODE_2D, 197 MODE_3D 198 }; 199 200 struct instance { 201 int unit; /* 127.127.30.unit */ 202 struct refclockproc *pp; 203 struct peer *peer; 204 205 int ttyfd; /* TTY file descriptor */ 206 int ppsfd; /* PPS file descriptor */ 207 int statusfd; /* Status shm descriptor */ 208 #ifdef HAVE_PPSAPI 209 pps_handle_t pps_h; 210 pps_params_t pps_p; 211 #endif 212 enum receive_state o_state; /* Receive state */ 213 enum posn_mode mode; /* 0D, 2D, 3D */ 214 enum site_survey_state site_survey; /* Site Survey state */ 215 216 int Bj_day; 217 218 u_long delay; /* ns */ 219 long offset; /* ns */ 220 221 u_char *shmem; 222 char *shmem_fname; 223 u_int shmem_Cb; 224 u_int shmem_Ba; 225 u_int shmem_Ea; 226 u_int shmem_Ha; 227 u_char shmem_first; 228 u_char shmem_reset; 229 u_char shmem_Posn; 230 231 double ss_lat; 232 double ss_long; 233 double ss_ht; 234 double dH; 235 int ss_count; 236 u_char posn_set; 237 238 enum oncore_model model; 239 u_int version; 240 u_int revision; 241 242 u_char chan; /* 6 for PVT6 or BASIC, 8 for UT/VP, 12 for m12, 0 if unknown */ 243 s_char traim; /* do we have traim? yes UT/VP, no BASIC, GT, -1 unknown, 0 no, +1 yes */ 244 u_char traim_delay; /* seconds counter, waiting for reply */ 245 246 struct RSM rsm; /* bits extracted from Receiver Status Msg in @@Ea */ 247 u_char printed; 248 u_char polled; 249 int pollcnt; 250 u_int ev_serial; 251 int Rcvptr; 252 u_char Rcvbuf[500]; 253 u_char Ea[160]; /* Ba, Ea or Ha */ 254 u_char En[70]; /* Bn or En */ 255 u_char Cj[300]; 256 u_char As; 257 u_char Ay; 258 u_char Az; 259 u_char have_dH; 260 u_char init_type; 261 s_char saw_tooth; 262 u_int timeout; /* count to retry Cj after Fa self-test */ 263 u_char count; /* cycles thru Ea before starting */ 264 s_char assert; 265 u_int saw_At; 266 }; 267 268 #define rcvbuf instance->Rcvbuf 269 #define rcvptr instance->Rcvptr 270 271 static void oncore_consume P((struct instance *)); 272 static void oncore_poll P((int, struct peer *)); 273 static void oncore_read_config P((struct instance *)); 274 static void oncore_receive P((struct recvbuf *)); 275 static void oncore_sendmsg P((int fd, u_char *, size_t)); 276 static void oncore_shutdown P((int, struct peer *)); 277 static int oncore_start P((int, struct peer *)); 278 static void oncore_get_timestamp P((struct instance *, long, long)); 279 static void oncore_init_shmem P((struct instance *)); 280 static void oncore_print_As P((struct instance *)); 281 282 static void oncore_msg_any P((struct instance *, u_char *, size_t, int)); 283 static void oncore_msg_As P((struct instance *, u_char *, size_t)); 284 static void oncore_msg_At P((struct instance *, u_char *, size_t)); 285 static void oncore_msg_Ay P((struct instance *, u_char *, size_t)); 286 static void oncore_msg_Az P((struct instance *, u_char *, size_t)); 287 static void oncore_msg_BaEaHa P((struct instance *, u_char *, size_t)); 288 static void oncore_msg_Bj P((struct instance *, u_char *, size_t)); 289 static void oncore_msg_BnEn P((struct instance *, u_char *, size_t)); 290 static void oncore_msg_CaFaIa P((struct instance *, u_char *, size_t)); 291 static void oncore_msg_Cb P((struct instance *, u_char *, size_t)); 292 static void oncore_msg_Cf P((struct instance *, u_char *, size_t)); 293 static void oncore_msg_Cj P((struct instance *, u_char *, size_t)); 294 static void oncore_msg_Cj_id P((struct instance *, u_char *, size_t)); 295 static void oncore_msg_Cj_init P((struct instance *, u_char *, size_t)); 296 static void oncore_msg_Gj P((struct instance *, u_char *, size_t)); 297 static void oncore_msg_Sz P((struct instance *, u_char *, size_t)); 298 299 struct refclock refclock_oncore = { 300 oncore_start, /* start up driver */ 301 oncore_shutdown, /* shut down driver */ 302 oncore_poll, /* transmit poll message */ 303 noentry, /* not used */ 304 noentry, /* not used */ 305 noentry, /* not used */ 306 NOFLAGS /* not used */ 307 }; 308 309 /* 310 * Understanding the next bit here is not easy unless you have a manual 311 * for the the various Oncore Models. 312 */ 313 314 static struct msg_desc { 315 const char flag[3]; 316 const int len; 317 void (*handler) P((struct instance *, u_char *, size_t)); 318 const char *fmt; 319 int shmem; 320 } oncore_messages[] = { 321 /* Ea and En first since they're most common */ 322 { "Ea", 76, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" }, 323 { "Ba", 68, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC" }, 324 { "Ha", 154, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC" }, 325 { "En", 69, oncore_msg_BnEn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" }, 326 { "Bn", 59, oncore_msg_BnEn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC" }, 327 { "Ab", 10, 0, "" }, 328 { "Ac", 11, 0, "" }, 329 { "Ad", 11, 0, "" }, 330 { "Ae", 11, 0, "" }, 331 { "Af", 15, 0, "" }, 332 { "As", 20, oncore_msg_As, "" }, 333 { "At", 8, oncore_msg_At, "" }, 334 { "Au", 12, 0, "" }, 335 { "Av", 8, 0, "" }, 336 { "Aw", 8, 0, "" }, 337 { "Ay", 11, oncore_msg_Ay, "" }, 338 { "Az", 11, oncore_msg_Az, "" }, 339 { "AB", 8, 0, "" }, 340 { "Bb", 92, 0, "" }, 341 { "Bj", 8, oncore_msg_Bj, "" }, 342 { "Ca", 9, oncore_msg_CaFaIa, "" }, 343 { "Cb", 33, oncore_msg_Cb, "" }, 344 { "Cf", 7, oncore_msg_Cf, "" }, 345 { "Cg", 8, 0, "" }, 346 { "Ch", 9, 0, "" }, 347 { "Cj", 294, oncore_msg_Cj, "" }, 348 { "Ek", 71, 0, "" }, 349 { "Fa", 9, oncore_msg_CaFaIa, "" }, 350 { "Gd", 8, 0, "" }, 351 { "Gj", 21, oncore_msg_Gj, "" }, 352 { "Ia", 10, oncore_msg_CaFaIa, "" }, 353 { "Sz", 8, oncore_msg_Sz, "" }, 354 { {0}, 7, 0, "" } 355 }; 356 357 /* 358 * Position Set. 359 */ 360 u_char oncore_cmd_Ad[] = { 'A', 'd', 0,0,0,0 }; 361 u_char oncore_cmd_Ae[] = { 'A', 'e', 0,0,0,0 }; 362 u_char oncore_cmd_Af[] = { 'A', 'f', 0,0,0,0, 0 }; 363 u_char oncore_cmd_Ga[] = { 'G', 'a', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; 364 365 /* 366 * Position-Hold Mode 367 * Start automatic site survey 368 */ 369 static u_char oncore_cmd_At0[] = { 'A', 't', 0 }; /* Posn Hold off */ 370 static u_char oncore_cmd_At1[] = { 'A', 't', 1 }; /* Posn Hold on */ 371 static u_char oncore_cmd_At2[] = { 'A', 't', 2 }; /* Start Site Survey */ 372 373 /* 374 * 0D/2D Position and Set. 375 */ 376 u_char oncore_cmd_As[] = { 'A', 's', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; 377 u_char oncore_cmd_Asx[]= { 'A', 's', 0x7f, 0xff, 0xff, 0xff, 378 0x7f, 0xff, 0xff, 0xff, 379 0x7f, 0xff, 0xff, 0xff, 0xff }; 380 u_char oncore_cmd_Au[] = { 'A', 'u', 0,0,0,0,0 }; 381 382 u_char oncore_cmd_Av0[] = { 'A', 'v', 0 }; 383 u_char oncore_cmd_Av1[] = { 'A', 'v', 1 }; 384 385 u_char oncore_cmd_Gd0[] = { 'G', 'd', 0 }; /* 3D */ 386 u_char oncore_cmd_Gd1[] = { 'G', 'd', 1 }; /* 0D */ 387 u_char oncore_cmd_Gd2[] = { 'G', 'd', 2 }; /* 2D */ 388 389 /* 390 * Set to UTC time (not GPS). 391 */ 392 u_char oncore_cmd_Aw[] = { 'A', 'w', 1 }; 393 394 /* 395 * Output Almanac when it changes 396 */ 397 u_char oncore_cmd_Be[] = { 'B', 'e', 1 }; 398 399 /* 400 * Read back PPS Offset for Output 401 */ 402 u_char oncore_cmd_Ay[] = { 'A', 'y', 0, 0, 0, 0 }; 403 u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff }; 404 405 /* 406 * Read back Cable Delay for Output 407 */ 408 u_char oncore_cmd_Az[] = { 'A', 'z', 0, 0, 0, 0 }; 409 u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff }; 410 411 /* 412 * Application type = static. 413 */ 414 u_char oncore_cmd_AB[] = { 'A', 'B', 4 }; 415 416 /* 417 * Visible Satellite Status Msg. 418 */ 419 u_char oncore_cmd_Bb[] = { 'B', 'b', 1 }; 420 421 /* 422 * Leap Second Pending Message 423 * Request message once 424 */ 425 u_char oncore_cmd_Bj[] = { 'B', 'j', 0 }; 426 u_char oncore_cmd_Gj[] = { 'G', 'j' }; 427 428 /* 429 * Set to Defaults 430 */ 431 static u_char oncore_cmd_Cf[] = { 'C', 'f' }; 432 433 /* 434 * Set to Position Fix mode (only needed on VP). 435 */ 436 u_char oncore_cmd_Cg[] = { 'C', 'g', 1 }; 437 438 /* 439 * Receiver Id 440 */ 441 static u_char oncore_cmd_Cj[] = { 'C', 'j' }; 442 443 /* 444 * Position/Status/Data message 445 * Send once per second 446 */ 447 static u_char oncore_cmd_Ea[] = { 'E', 'a', 1 }; 448 static u_char oncore_cmd_Ba[] = { 'B', 'a', 1 }; 449 static u_char oncore_cmd_Ha[] = { 'H', 'a', 1 }; 450 static u_char oncore_cmd_Ea0[] = { 'E', 'a', 0 }; 451 static u_char oncore_cmd_Ba0[] = { 'B', 'a', 0 }; 452 453 /* 454 * Position/Status Extension Msg 455 */ 456 u_char oncore_cmd_Ek[] = { 'E', 'k', 0 }; /* just turn off */ 457 458 /* 459 * Time Raim Setup & Status Message 460 * Send once per second 461 * Time-RAIM on 462 * Alarm limit 1us 463 * PPS on when we have the first sat 464 */ 465 static u_char oncore_cmd_En[] = { 'E', 'n', 1, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 466 static u_char oncore_cmd_En0[] = { 'E', 'n', 0, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 467 static u_char oncore_cmd_Bn[] = { 'B', 'n', 1, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 468 static u_char oncore_cmd_Bn0[] = { 'B', 'n', 0, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 469 470 /* 471 * Self-test 472 */ 473 static u_char oncore_cmd_Ca[] = { 'C', 'a' }; /* 6 Chan */ 474 static u_char oncore_cmd_Fa[] = { 'F', 'a' }; /* 8 Chan */ 475 static u_char oncore_cmd_Ia[] = { 'I', 'a' }; /* 12 Chan */ 476 477 #define DEVICE1 "/dev/oncore.serial.%d" /* name of serial device */ 478 #define DEVICE2 "/dev/oncore.pps.%d" /* name of pps device */ 479 #define INIT_FILE "/etc/ntp.oncore" /* optional init file */ 480 481 #define SPEED B9600 /* Oncore Binary speed (9600 bps) */ 482 483 /* 484 * Assemble and disassemble 32bit signed quantities from a buffer. 485 * 486 */ 487 488 /* to buffer, int w, u_char *buf */ 489 #define w32_buf(buf,w) { u_int i_tmp; \ 490 i_tmp = (w<0) ? (~(-w)+1) : (w); \ 491 (buf)[0] = (i_tmp >> 24) & 0xff; \ 492 (buf)[1] = (i_tmp >> 16) & 0xff; \ 493 (buf)[2] = (i_tmp >> 8) & 0xff; \ 494 (buf)[3] = (i_tmp ) & 0xff; \ 495 } 496 497 #define w32(buf) (((buf)[0]&0xff) << 24 | \ 498 ((buf)[1]&0xff) << 16 | \ 499 ((buf)[2]&0xff) << 8 | \ 500 ((buf)[3]&0xff) ) 501 502 /* from buffer, char *buf, result to an int */ 503 #define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf)) 504 505 extern int pps_assert; 506 extern int pps_hardpps; 507 508 509 510 /* 511 * oncore_start - initialize data for processing 512 */ 513 514 static int 515 oncore_start( 516 int unit, 517 struct peer *peer 518 ) 519 { 520 register struct instance *instance; 521 struct refclockproc *pp; 522 int fd1, fd2, mode; 523 char device1[30], device2[30]; 524 const char *cp; 525 struct stat stat1, stat2; 526 527 /* OPEN DEVICES */ 528 /* opening different devices for fd1 and fd2 presents no problems */ 529 /* opening the SAME device twice, seems to be OS dependent. 530 (a) on Linux (no streams) no problem 531 (b) on SunOS (and possibly Solaris, untested), (streams) 532 never see the line discipline. 533 Since things ALWAYS work if we only open the device once, we check 534 to see if the two devices are in fact the same, then proceed to 535 do one open or two. 536 */ 537 538 (void)sprintf(device1, DEVICE1, unit); 539 (void)sprintf(device2, DEVICE2, unit); 540 541 if (stat(device1, &stat1)) { 542 perror("ONCORE: stat fd1"); 543 exit(1); 544 } 545 546 if (stat(device2, &stat2)) { 547 perror("ONCORE: stat fd2"); 548 exit(1); 549 } 550 551 if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino)) { 552 /* same device here */ 553 if (!(fd1 = refclock_open(device1, SPEED, LDISC_RAW 554 #if !defined(HAVE_PPSAPI) && !defined(TIOCDCDTIMESTAMP) 555 | LDISC_PPS 556 #endif 557 ))) { 558 perror("ONCORE: fd1"); 559 exit(1); 560 } 561 fd2 = fd1; 562 } else { /* different devices here */ 563 if (!(fd1=refclock_open(device1, SPEED, LDISC_RAW))) { 564 perror("ONCORE: fd1"); 565 exit(1); 566 } 567 if ((fd2=open(device2, O_RDWR)) < 0) { 568 perror("ONCORE: fd2"); 569 exit(1); 570 } 571 } 572 573 /* Devices now open, create instance structure for this unit */ 574 575 if (!(instance = (struct instance *) malloc(sizeof *instance))) { 576 perror("malloc"); 577 close(fd1); 578 return (0); 579 } 580 memset((char *) instance, 0, sizeof *instance); 581 582 /* link instance up and down */ 583 584 pp = peer->procptr; 585 pp->unitptr = (caddr_t) instance; 586 instance->pp = pp; 587 instance->unit = unit; 588 instance->peer = peer; 589 590 /* initialize miscellaneous variables */ 591 592 instance->o_state = ONCORE_NO_IDEA; 593 cp = "state = ONCORE_NO_IDEA"; 594 record_clock_stats(&(instance->peer->srcadr), cp); 595 596 instance->ttyfd = fd1; 597 instance->ppsfd = fd2; 598 599 instance->Bj_day = -1; 600 instance->assert = pps_assert; 601 instance->traim = -1; 602 instance->model = ONCORE_UNKNOWN; 603 instance->mode = MODE_UNKNOWN; 604 instance->site_survey = ONCORE_SS_UNKNOWN; 605 606 peer->precision = -26; 607 peer->minpoll = 4; 608 peer->maxpoll = 4; 609 pp->clockdesc = "Motorola Oncore GPS Receiver"; 610 memcpy((char *)&pp->refid, "GPS\0", (size_t) 4); 611 612 /* go read any input data in /etc/ntp.oncoreX */ 613 614 oncore_read_config(instance); 615 616 #ifdef HAVE_PPSAPI 617 if (time_pps_create(fd2, &instance->pps_h) < 0) { 618 perror("time_pps_create"); 619 return(0); 620 } 621 622 if (time_pps_getcap(instance->pps_h, &mode) < 0) { 623 msyslog(LOG_ERR, 624 "refclock_ioctl: time_pps_getcap failed: %m"); 625 return (0); 626 } 627 628 if (time_pps_getparams(instance->pps_h, &instance->pps_p) < 0) { 629 msyslog(LOG_ERR, 630 "refclock_ioctl: time_pps_getparams failed: %m"); 631 return (0); 632 } 633 634 /* nb. only turn things on, if someone else has turned something 635 * on before we get here, leave it alone! 636 */ 637 638 if (instance->assert) { /* nb, default or ON */ 639 instance->pps_p.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT; 640 instance->pps_p.assert_offset.tv_sec = 0; 641 instance->pps_p.assert_offset.tv_nsec = 0; 642 } else { 643 instance->pps_p.mode = PPS_CAPTURECLEAR | PPS_OFFSETCLEAR; 644 instance->pps_p.clear_offset.tv_sec = 0; 645 instance->pps_p.clear_offset.tv_nsec = 0; 646 } 647 instance->pps_p.mode |= PPS_TSFMT_TSPEC; 648 instance->pps_p.mode &= mode; /* only set what is legal */ 649 650 if (time_pps_setparams(instance->pps_h, &instance->pps_p) < 0) { 651 perror("time_pps_setparams"); 652 exit(1); 653 } 654 655 if (pps_device) { 656 if (stat(pps_device, &stat1)) { 657 perror("ONCORE: stat pps_device"); 658 return(0); 659 } 660 661 /* must have hardpps ON, and fd2 must be the same device as on the pps line */ 662 663 if (pps_hardpps && ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino))) { 664 int i; 665 666 if (instance->assert) 667 i = PPS_CAPTUREASSERT; 668 else 669 i = PPS_CAPTURECLEAR; 670 671 if (i&mode) { 672 if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i, 673 PPS_TSFMT_TSPEC) < 0) { 674 msyslog(LOG_ERR, 675 "refclock_ioctl: time_pps_kcbind failed: %m"); 676 return (0); 677 } 678 pps_enable = 1; 679 } 680 } 681 } 682 #endif 683 684 pp->io.clock_recv = oncore_receive; 685 pp->io.srcclock = (caddr_t)peer; 686 pp->io.datalen = 0; 687 pp->io.fd = fd1; 688 if (!io_addclock(&pp->io)) { 689 perror("io_addclock"); 690 (void) close(fd1); 691 free(instance); 692 return (0); 693 } 694 695 /* 696 * This will return the Model Number of the Oncore receiver. 697 */ 698 699 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 700 instance->o_state = ONCORE_ID_SENT; 701 cp = "state = ONCORE_ID SENT"; 702 record_clock_stats(&(instance->peer->srcadr), cp); 703 instance->timeout = 4; 704 705 instance->pollcnt = 2; 706 return (1); 707 } 708 709 710 711 /* 712 * Read Input file if it exists. 713 */ 714 715 static void 716 oncore_read_config( 717 struct instance *instance 718 ) 719 { 720 /* 721 * First we try to open the configuration file 722 * /etc/oncoreN 723 * where N is the unit number viz 127.127.30.N. 724 * If we don't find it we try 725 * /etc/ntp.oncore.N 726 * and then 727 * /etc/ntp.oncore 728 * 729 * If we don't find any then we don't have the cable delay or PPS offset 730 * and we choose MODE (4) below. 731 * 732 * Five Choices for MODE 733 * (0) ONCORE is preinitialized, don't do anything to change it. 734 * nb, DON'T set 0D mode, DON'T set Delay, position... 735 * (1) NO RESET, Read Position, delays from data file, lock it in, go to 0D mode. 736 * (2) NO RESET, Read Delays from data file, do SITE SURVEY to get position, 737 * lock this in, go to 0D mode. 738 * (3) HARD RESET, Read Position, delays from data file, lock it in, go to 0D mode. 739 * (4) HARD RESET, Read Delays from data file, do SITE SURVEY to get position, 740 * lock this in, go to 0D mode. 741 * NB. If a POSITION is specified in the config file with mode=(2,4) [SITE SURVEY] 742 * then this position is set as the INITIAL position of the ONCORE. 743 * This can reduce the time to first fix. 744 * ------------------------------------------------------------------------------- 745 * Note that an Oncore UT without a battery backup retains NO information if it is 746 * power cycled, with a Battery Backup it remembers the almanac, etc. 747 * For an Oncore VP, there is an eeprom that will contain this data, along with the 748 * option of Battery Backup. 749 * So a UT without Battery Backup is equivalent to doing a HARD RESET on each 750 * power cycle, since there is nowhere to store the data. 751 * ------------------------------------------------------------------------------- 752 * 753 * If we open one or the other of the files, we read it looking for 754 * MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET, ASSERT, CLEAR, STATUS, 755 * POSN3D, POSN2D, CHAN, TRAIM 756 * then initialize using method MODE. For Mode = (1,3) all of (LAT, LON, HT) must 757 * be present or mode reverts to (2,4). 758 * 759 * Read input file. 760 * 761 * # is comment to end of line 762 * = allowed between 1st and 2nd fields. 763 * 764 * Expect to see one line with 'MODE' as first field, followed by an integer 765 * in the range 0-4 (default = 4). 766 * 767 * Expect to see two lines with 'LONG', 'LAT' followed by 1-3 fields. 768 * All numbers are floating point. 769 * DDD.ddd 770 * DDD MMM.mmm 771 * DDD MMM SSS.sss 772 * 773 * Expect to see one line with 'HT' as first field, 774 * followed by 1-2 fields. First is a number, the second is 'FT' or 'M' 775 * for feet or meters. HT is the height above the GPS ellipsoid. 776 * If the reciever reports height in both GPS and MSL, then we will report 777 * the difference GPS-MSL on the clockstats file. 778 * 779 * There is an optional line, starting with DELAY, followed 780 * by 1 or two fields. The first is a number (a time) the second is 781 * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds. 782 * DELAY is cable delay, typically a few tens of ns. 783 * 784 * There is an optional line, starting with OFFSET, followed 785 * by 1 or two fields. The first is a number (a time) the second is 786 * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds. 787 * OFFSET is the offset of the PPS pulse from 0. (only fully implemented 788 * with the PPSAPI, we need to be able to tell the Kernel about this 789 * offset if the Kernel PLL is in use, but can only do this presently 790 * when using the PPSAPI interface. If not using the Kernel PLL, 791 * then there is no problem. 792 * 793 * There is an optional line, with either ASSERT or CLEAR on it, which 794 * determine which transition of the PPS signal is used for timing by the 795 * PPSAPI. If neither is present, then ASSERT is assumed. 796 * 797 * There are three options that have to do with using the shared memory opition. 798 * First, to enable the option there must be an ASSERT line with a file name. 799 * The file name is the file associated with the shared memory. 800 * 801 * In the shared memory there are three 'records' containing the @@Ea (or equivalent) 802 * data, and this contains the position data. There will always be data in the 803 * record cooresponding to the '0D' @@Ea record, and the user has a choice of 804 * filling the '3D' @@Ea record by specifying POSN3D, or the '2D' record by 805 * specifying POSN2D. In either case the '2D' or '3D' record is filled once 806 * every 15s. 807 * 808 * Two additional variables that can be set are CHAN and TRAIM. These should be 809 * set correctly by the code examining the @@Cj record, but we bring them out here 810 * to allow the user to override either the # of channels, or the existance of TRAIM. 811 * CHAN expects to be followed by in integer: 6, 8, or 12. TRAIM expects to be 812 * followed by YES or NO. 813 * 814 * So acceptable input would be 815 * # these are my coordinates (RWC) 816 * LON -106 34.610 817 * LAT 35 08.999 818 * HT 1589 # could equally well say HT 5215 FT 819 * DELAY 60 ns 820 */ 821 822 FILE *fd; 823 char *cp, *cc, *ca, line[100], units[2], device[20], Msg[160]; 824 int i, sign, lat_flg, long_flg, ht_flg, mode; 825 double f1, f2, f3; 826 827 sprintf(device, "%s%d", INIT_FILE, instance->unit); /* try "ntp.oncore0" first */ 828 if ((fd=fopen(device, "r")) == NULL) { /* it was in the original documentation */ 829 sprintf(device, "%s.%d", INIT_FILE, instance->unit); /* then try "ntp.oncore.0 */ 830 if ((fd=fopen(device, "r")) == NULL) { 831 if ((fd=fopen(INIT_FILE, "r")) == NULL) { /* and finally "ntp.oncore" */ 832 instance->init_type = 4; 833 return; 834 } 835 } 836 } 837 838 mode = 0; 839 lat_flg = long_flg = ht_flg = 0; 840 while (fgets(line, 100, fd)) { 841 842 /* Remove comments */ 843 if ((cp = strchr(line, '#'))) 844 *cp = '\0'; 845 846 /* Remove trailing space */ 847 for (i = strlen(line); 848 i > 0 && isascii((int)line[i - 1]) && isspace((int)line[i - 1]); 849 ) 850 line[--i] = '\0'; 851 852 /* Remove leading space */ 853 for (cc = line; *cc && isascii((int)*cc) && isspace((int)*cc); cc++) 854 continue; 855 856 /* Stop if nothing left */ 857 if (!*cc) 858 continue; 859 860 /* Uppercase the command and find the arg */ 861 for (ca = cc; *ca; ca++) { 862 if (isascii((int)*ca)) { 863 if (islower((int)*ca)) { 864 *ca = toupper(*ca); 865 } else if (isspace((int)*ca) || (*ca == '=')) 866 break; 867 } 868 } 869 870 /* Remove space (and possible =) leading the arg */ 871 for (; *ca && isascii((int)*ca) && (isspace((int)*ca) || (*ca == '=')); ca++) 872 continue; 873 874 /* 875 * move call to oncore_shmem_init() from here to after 876 * we have determined Oncore Model, so we can ignore 877 * request if model doesnt 'support' it 878 */ 879 880 if (!strncmp(cc, "STATUS", (size_t) 6) || !strncmp(cc, "SHMEM", (size_t) 5)) { 881 i = strlen(ca); 882 instance->shmem_fname = (char *) malloc((unsigned) (i+1)); 883 strcpy(instance->shmem_fname, ca); 884 continue; 885 } 886 887 /* Uppercase argument as well */ 888 for (cp = ca; *cp; cp++) 889 if (isascii((int)*cp) && islower((int)*cp)) 890 *cp = toupper(*cp); 891 892 if (!strncmp(cc, "LAT", (size_t) 3)) { 893 f1 = f2 = f3 = 0; 894 sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3); 895 sign = 1; 896 if (f1 < 0) { 897 f1 = -f1; 898 sign = -1; 899 } 900 instance->ss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/ 901 lat_flg++; 902 } else if (!strncmp(cc, "LON", (size_t) 3)) { 903 f1 = f2 = f3 = 0; 904 sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3); 905 sign = 1; 906 if (f1 < 0) { 907 f1 = -f1; 908 sign = -1; 909 } 910 instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/ 911 long_flg++; 912 } else if (!strncmp(cc, "HT", (size_t) 2)) { 913 f1 = 0; 914 units[0] = '\0'; 915 sscanf(ca, "%lf %1s", &f1, units); 916 if (units[0] == 'F') 917 f1 = 0.3048 * f1; 918 instance->ss_ht = 100 * f1; /* cm */ 919 ht_flg++; 920 } else if (!strncmp(cc, "DELAY", (size_t) 5)) { 921 f1 = 0; 922 units[0] = '\0'; 923 sscanf(ca, "%lf %1s", &f1, units); 924 if (units[0] == 'N') 925 ; 926 else if (units[0] == 'U') 927 f1 = 1000 * f1; 928 else if (units[0] == 'M') 929 f1 = 1000000 * f1; 930 else 931 f1 = 1000000000 * f1; 932 if (f1 < 0 || f1 > 1.e9) 933 f1 = 0; 934 if (f1 < 0 || f1 > 999999) { 935 sprintf(Msg, "PPS Cable delay of %fns out of Range, ignored", f1); 936 record_clock_stats(&(instance->peer->srcadr), Msg); 937 } else 938 instance->delay = f1; /* delay in ns */ 939 } else if (!strncmp(cc, "OFFSET", (size_t) 6)) { 940 f1 = 0; 941 units[0] = '\0'; 942 sscanf(ca, "%lf %1s", &f1, units); 943 if (units[0] == 'N') 944 ; 945 else if (units[0] == 'U') 946 f1 = 1000 * f1; 947 else if (units[0] == 'M') 948 f1 = 1000000 * f1; 949 else 950 f1 = 1000000000 * f1; 951 if (f1 < 0 || f1 > 1.e9) 952 f1 = 0; 953 if (f1 < 0 || f1 > 999999999.) { 954 sprintf(Msg, "PPS Offset of %fns out of Range, ignored", f1); 955 record_clock_stats(&(instance->peer->srcadr), Msg); 956 } else 957 instance->offset = f1; /* offset in ns */ 958 } else if (!strncmp(cc, "MODE", (size_t) 4)) { 959 sscanf(ca, "%d", &mode); 960 if (mode < 0 || mode > 4) 961 mode = 4; 962 } else if (!strncmp(cc, "ASSERT", (size_t) 6)) { 963 instance->assert = 1; 964 } else if (!strncmp(cc, "CLEAR", (size_t) 5)) { 965 instance->assert = 0; 966 } else if (!strncmp(cc, "POSN2D", (size_t) 6)) { 967 instance->shmem_Posn = 2; 968 } else if (!strncmp(cc, "POSN3D", (size_t) 6)) { 969 instance->shmem_Posn = 3; 970 } else if (!strncmp(cc, "CHAN", (size_t) 4)) { 971 sscanf(ca, "%d", &i); 972 if ((i == 6) || (i == 8) || (i == 12)) 973 instance->chan = i; 974 } else if (!strncmp(cc, "TRAIM", (size_t) 5)) { 975 instance->traim = 1; /* so TRAIM alone is YES */ 976 if (!strcmp(ca, "NO") || !strcmp(ca, "OFF")) /* Yes/No, On/Off */ 977 instance->traim = 0; 978 } 979 } 980 fclose(fd); 981 982 /* 983 * OK, have read all of data file, and extracted the good stuff. 984 * If lat/long/ht specified they ALL must be specified for mode = (1,3). 985 */ 986 987 instance->posn_set = 1; 988 if ((lat_flg || long_flg || ht_flg) && !(lat_flg * long_flg * ht_flg)) { 989 printf("ONCORE: incomplete data on %s\n", INIT_FILE); 990 instance->posn_set = 0; 991 if (mode == 1 || mode == 3) { 992 sprintf(Msg, "Input Mode = %d, but no/incomplete position, mode set to %d", mode, mode+1); 993 record_clock_stats(&(instance->peer->srcadr), Msg); 994 mode++; 995 } 996 } 997 instance->init_type = mode; 998 999 sprintf(Msg, "Input mode = %d", mode); 1000 record_clock_stats(&(instance->peer->srcadr), Msg); 1001 } 1002 1003 1004 1005 static void 1006 oncore_init_shmem( 1007 struct instance *instance 1008 ) 1009 { 1010 #ifdef ONCORE_SHMEM_STATUS 1011 int i, l, n; 1012 char *buf; 1013 struct msg_desc *mp; 1014 size_t oncore_shmem_length; 1015 1016 if (instance->shmem_first) 1017 return; 1018 1019 instance->shmem_first++; 1020 1021 if ((instance->statusfd = open(instance->shmem_fname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) { 1022 perror(instance->shmem_fname); 1023 return; 1024 } 1025 1026 n = 1; 1027 for (mp = oncore_messages; mp->flag[0]; mp++) { 1028 mp->shmem = n; 1029 /* Allocate space for multiplexed almanac, and 0D/2D/3D @@Ea records */ 1030 if (!strcmp(mp->flag, "Cb")) { 1031 instance->shmem_Cb = n; 1032 n += (mp->len + 3) * 34; 1033 } 1034 if (!strcmp(mp->flag, "Ba")) { 1035 instance->shmem_Ba = n; 1036 n += (mp->len + 3) * 3; 1037 } 1038 if (!strcmp(mp->flag, "Ea")) { 1039 instance->shmem_Ea = n; 1040 n += (mp->len + 3) * 3; 1041 } 1042 if (!strcmp(mp->flag, "Ha")) { 1043 instance->shmem_Ha = n; 1044 n += (mp->len + 3) * 3; 1045 } 1046 n += (mp->len + 3); 1047 } 1048 oncore_shmem_length = n + 2; 1049 fprintf(stderr, "ONCORE: SHMEM length: %d bytes\n", (int) oncore_shmem_length); 1050 1051 buf = malloc(oncore_shmem_length); 1052 if (buf == NULL) { 1053 perror("malloc"); 1054 return; 1055 } 1056 memset(buf, 0, sizeof(buf)); 1057 i = write(instance->statusfd, buf, oncore_shmem_length); 1058 if (i != oncore_shmem_length) { 1059 perror(instance->shmem_fname); 1060 return; 1061 } 1062 free(buf); 1063 instance->shmem = (u_char *) mmap(0, oncore_shmem_length, 1064 PROT_READ | PROT_WRITE, 1065 #ifdef MAP_HASSEMAPHORE 1066 MAP_HASSEMAPHORE | 1067 #endif 1068 MAP_SHARED, 1069 instance->statusfd, (off_t)0); 1070 if (instance->shmem == (u_char *)MAP_FAILED) { 1071 instance->shmem = 0; 1072 close (instance->statusfd); 1073 return; 1074 } 1075 for (mp = oncore_messages; mp->flag[0]; mp++) { 1076 l = mp->shmem; 1077 instance->shmem[l + 0] = mp->len >> 8; 1078 instance->shmem[l + 1] = mp->len & 0xff; 1079 instance->shmem[l + 2] = 0; 1080 instance->shmem[l + 3] = '@'; 1081 instance->shmem[l + 4] = '@'; 1082 instance->shmem[l + 5] = mp->flag[0]; 1083 instance->shmem[l + 6] = mp->flag[1]; 1084 if (!strcmp(mp->flag, "Cb") || !strcmp(mp->flag, "Ba") || !strcmp(mp->flag, "Ea") || !strcmp(mp->flag, "Ha")) { 1085 if (!strcmp(mp->flag, "Cb")) 1086 n = 35; 1087 else 1088 n = 4; 1089 for (i = 1; i < n; i++) { 1090 instance->shmem[l + i * (mp->len+3) + 0] = mp->len >> 8; 1091 instance->shmem[l + i * (mp->len+3) + 1] = mp->len & 0xff; 1092 instance->shmem[l + i * (mp->len+3) + 2] = 0; 1093 instance->shmem[l + i * (mp->len+3) + 3] = '@'; 1094 instance->shmem[l + i * (mp->len+3) + 4] = '@'; 1095 instance->shmem[l + i * (mp->len+3) + 5] = mp->flag[0]; 1096 instance->shmem[l + i * (mp->len+3) + 6] = mp->flag[1]; 1097 } 1098 } 1099 } 1100 #endif /* ONCORE_SHMEM_STATUS */ 1101 } 1102 1103 1104 1105 /* 1106 * oncore_shutdown - shut down the clock 1107 */ 1108 1109 static void 1110 oncore_shutdown( 1111 int unit, 1112 struct peer *peer 1113 ) 1114 { 1115 register struct instance *instance; 1116 struct refclockproc *pp; 1117 1118 pp = peer->procptr; 1119 instance = (struct instance *) pp->unitptr; 1120 1121 io_closeclock(&pp->io); 1122 1123 free(instance); 1124 } 1125 1126 1127 1128 /* 1129 * oncore_poll - called by the transmit procedure 1130 */ 1131 1132 static void 1133 oncore_poll( 1134 int unit, 1135 struct peer *peer 1136 ) 1137 { 1138 struct instance *instance; 1139 1140 instance = (struct instance *) peer->procptr->unitptr; 1141 if (instance->timeout) { 1142 char *cp; 1143 1144 instance->timeout--; 1145 if (instance->timeout == 0) { 1146 cp = "Oncore: No response from @@Cj, shutting down driver"; 1147 record_clock_stats(&(instance->peer->srcadr), cp); 1148 oncore_shutdown(unit, peer); 1149 } else { 1150 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 1151 cp = "Oncore: Resend @@Cj"; 1152 record_clock_stats(&(instance->peer->srcadr), cp); 1153 } 1154 return; 1155 } 1156 1157 if (!instance->pollcnt) 1158 refclock_report(peer, CEVNT_TIMEOUT); 1159 else 1160 instance->pollcnt--; 1161 peer->procptr->polls++; 1162 instance->polled = 1; 1163 } 1164 1165 1166 1167 /* 1168 * move data from NTP to buffer (toss in unlikely case it wont fit) 1169 */ 1170 1171 static void 1172 oncore_receive( 1173 struct recvbuf *rbufp 1174 ) 1175 { 1176 size_t i; 1177 u_char *p; 1178 struct peer *peer; 1179 struct instance *instance; 1180 1181 peer = (struct peer *)rbufp->recv_srcclock; 1182 instance = (struct instance *) peer->procptr->unitptr; 1183 p = (u_char *) &rbufp->recv_space; 1184 1185 #if 0 1186 if (debug > 4) { 1187 int i; 1188 printf("ONCORE: >>>"); 1189 for(i=0; i<rbufp->recv_length; i++) 1190 printf("%02x ", p[i]); 1191 printf("\n"); 1192 printf("ONCORE: >>>"); 1193 for(i=0; i<rbufp->recv_length; i++) 1194 printf("%03o ", p[i]); 1195 printf("\n"); 1196 } 1197 #endif 1198 1199 i = rbufp->recv_length; 1200 if (rcvbuf+rcvptr+i > &rcvbuf[sizeof rcvbuf]) 1201 i = sizeof(rcvbuf) - rcvptr; /* and some char will be lost */ 1202 memcpy(rcvbuf+rcvptr, p, i); 1203 rcvptr += i; 1204 oncore_consume(instance); 1205 } 1206 1207 1208 1209 /* 1210 * Deal with any complete messages 1211 */ 1212 1213 static void 1214 oncore_consume( 1215 struct instance *instance 1216 ) 1217 { 1218 int i, j, m; 1219 unsigned l; 1220 1221 while (rcvptr >= 7) { 1222 if (rcvbuf[0] != '@' || rcvbuf[1] != '@') { 1223 /* We're not in sync, lets try to get there */ 1224 for (i=1; i < rcvptr-1; i++) 1225 if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@') 1226 break; 1227 if (debug > 4) 1228 printf("ONCORE[%d]: >>> skipping %d chars\n", instance->unit, i); 1229 if (i != rcvptr) 1230 memcpy(rcvbuf, rcvbuf+i, (size_t)(rcvptr-i)); 1231 rcvptr -= i; 1232 continue; 1233 } 1234 1235 /* Ok, we have a header now */ 1236 l = sizeof(oncore_messages)/sizeof(oncore_messages[0]) -1; 1237 for(m=0; m<l; m++) 1238 if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), (size_t) 2)) 1239 break; 1240 if (m == l) { 1241 if (debug > 4) 1242 printf("ONCORE[%d]: >>> Unknown MSG, skipping 4 (%c%c)\n", instance->unit, rcvbuf[2], rcvbuf[3]); 1243 memcpy(rcvbuf, rcvbuf+4, (size_t) 4); 1244 rcvptr -= 4; 1245 continue; 1246 } 1247 1248 l = oncore_messages[m].len; 1249 #if 0 1250 if (debug > 3) 1251 printf("ONCORE[%d]: GOT: %c%c %d of %d entry %d\n", instance->unit, rcvbuf[2], rcvbuf[3], rcvptr, l, m); 1252 #endif 1253 /* Got the entire message ? */ 1254 1255 if (rcvptr < l) 1256 return; 1257 1258 /* are we at the end of message? should be <Cksum><CR><LF> */ 1259 1260 if (rcvbuf[l-2] != '\r' || rcvbuf[l-1] != '\n') { 1261 if (debug) 1262 printf("ONCORE[%d]: NO <CR><LF> at end of message\n", instance->unit); 1263 } else { /* check the CheckSum */ 1264 j = 0; 1265 for (i = 2; i < l-3; i++) 1266 j ^= rcvbuf[i]; 1267 if (j == rcvbuf[l-3]) { 1268 if (instance->shmem != NULL) { 1269 instance->shmem[oncore_messages[m].shmem + 2]++; 1270 memcpy(instance->shmem + oncore_messages[m].shmem + 3, 1271 rcvbuf, (size_t) l); 1272 } 1273 oncore_msg_any(instance, rcvbuf, (size_t) (l-3), m); 1274 if (oncore_messages[m].handler) 1275 oncore_messages[m].handler(instance, rcvbuf, (size_t) (l-3)); 1276 } else if (debug) { 1277 printf("ONCORE[%d]: Checksum mismatch! calc %o is %o\n", instance->unit, j, rcvbuf[l-3]); 1278 printf("ONCORE[%d]: @@%c%c ", instance->unit, rcvbuf[2], rcvbuf[3]); 1279 for (i=4; i<l; i++) 1280 printf("%03o ", rcvbuf[i]); 1281 printf("\n"); 1282 } 1283 } 1284 1285 if (l != rcvptr) 1286 memcpy(rcvbuf, rcvbuf+l, (size_t) (rcvptr-l)); 1287 rcvptr -= l; 1288 } 1289 } 1290 1291 1292 1293 /* 1294 * write message to Oncore. 1295 */ 1296 1297 static void 1298 oncore_sendmsg( 1299 int fd, 1300 u_char *ptr, 1301 size_t len 1302 ) 1303 { 1304 u_char cs = 0; 1305 1306 printf("ONCORE: Send @@%c%c %d\n", ptr[0], ptr[1], (int) len); 1307 write(fd, "@@", (size_t) 2); 1308 write(fd, ptr, len); 1309 while (len--) 1310 cs ^= *ptr++; 1311 write(fd, &cs, (size_t) 1); 1312 write(fd, "\r\n", (size_t) 2); 1313 } 1314 1315 1316 1317 /* 1318 * print Oncore response message. 1319 */ 1320 1321 static void 1322 oncore_msg_any( 1323 struct instance *instance, 1324 u_char *buf, 1325 size_t len, 1326 int idx 1327 ) 1328 { 1329 int i; 1330 const char *fmt = oncore_messages[idx].fmt; 1331 const char *p; 1332 #ifdef HAVE_GETCLOCK 1333 struct timespec ts; 1334 #endif 1335 struct timeval tv; 1336 1337 if (debug > 3) { 1338 #ifdef HAVE_GETCLOCK 1339 (void) getclock(TIMEOFDAY, &ts); 1340 tv.tv_sec = ts.tv_sec; 1341 tv.tv_usec = ts.tv_nsec / 1000; 1342 #else 1343 GETTIMEOFDAY(&tv, 0); 1344 #endif 1345 printf("ONCORE[%d]: %ld.%06ld\n", instance->unit, (long) tv.tv_sec, (long) tv.tv_usec); 1346 1347 if (!*fmt) { 1348 printf(">>@@%c%c ", buf[2], buf[3]); 1349 for(i=2; i < len && i < 2400 ; i++) 1350 printf("%02x", buf[i]); 1351 printf("\n"); 1352 return; 1353 } else { 1354 printf("##"); 1355 for (p = fmt; *p; p++) { 1356 putchar(*p); 1357 putchar('_'); 1358 } 1359 printf("\n%c%c", buf[2], buf[3]); 1360 i = 4; 1361 for (p = fmt; *p; p++) { 1362 printf("%02x", buf[i++]); 1363 } 1364 printf("\n"); 1365 } 1366 } 1367 } 1368 1369 1370 1371 /* 1372 * Demultiplex the almanac into shmem 1373 */ 1374 1375 static void 1376 oncore_msg_Cb( 1377 struct instance *instance, 1378 u_char *buf, 1379 size_t len 1380 ) 1381 { 1382 int i; 1383 1384 if (instance->shmem == NULL) 1385 return; 1386 1387 if (buf[4] == 5) 1388 i = buf[5]; 1389 else if (buf[4] == 4 && buf[5] <= 5) 1390 i = buf[5] + 24; 1391 else if (buf[4] == 4 && buf[5] <= 10) 1392 i = buf[5] + 23; 1393 else 1394 i = 34; 1395 i *= 36; 1396 instance->shmem[instance->shmem_Cb + i + 2]++; 1397 memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3)); 1398 } 1399 1400 1401 1402 /* 1403 * We do an @@Cj twice in the initialization sequence. 1404 * o Once at the very beginning to get the Model number so we know what commands 1405 * we can issue, 1406 * o And once later after we have done a reset and test, (which may hang), 1407 * as we are about to initialize the Oncore and start it running. 1408 * o We have one routine below for each case. 1409 */ 1410 1411 1412 /* 1413 * Determine the Type from the Model #, this determines #chan and if TRAIM is 1414 * available. We use ONLY the #chans, and determint TRAIM by trying it. 1415 */ 1416 1417 static void 1418 oncore_msg_Cj( 1419 struct instance *instance, 1420 u_char *buf, 1421 size_t len 1422 ) 1423 { 1424 memcpy(instance->Cj, buf, len); 1425 1426 instance->timeout = 0; 1427 if (instance->o_state == ONCORE_ID_SENT) 1428 oncore_msg_Cj_id(instance, buf, len); 1429 else if (instance->o_state == ONCORE_INIT) 1430 oncore_msg_Cj_init(instance, buf, len); 1431 } 1432 1433 1434 1435 /* The information on determing a Oncore 'Model', viz VP, UT, etc, from 1436 * the Model Number comes from "Richard M. Hambly" <rick@cnssys.com> 1437 * and from Motorola. Until recently Rick was the only source of 1438 * this information as Motorola didnt give the information out. 1439 */ 1440 1441 static void 1442 oncore_msg_Cj_id( 1443 struct instance *instance, 1444 u_char *buf, 1445 size_t len 1446 ) 1447 { 1448 char *cp, *cp1, *cp2, Model[21], Msg[160]; 1449 int mode; 1450 1451 /* Write Receiver ID message to clockstats file */ 1452 1453 instance->Cj[294] = '\0'; 1454 for (cp=(char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) { 1455 cp1 = strchr(cp, '\r'); 1456 if (!cp1) 1457 cp1 = (char *)&instance->Cj[294]; 1458 *cp1 = '\0'; 1459 record_clock_stats(&(instance->peer->srcadr), cp); 1460 *cp1 = '\r'; 1461 cp = cp1+2; 1462 } 1463 1464 /* next, the Firmware Version and Revision numbers */ 1465 1466 instance->version = atoi(&instance->Cj[83]); 1467 instance->revision = atoi(&instance->Cj[111]); 1468 1469 /* from model number decide which Oncore this is, 1470 and then the number of channels */ 1471 1472 for (cp=&instance->Cj[160]; *cp == ' '; cp++) /* start right after 'Model #' */ 1473 ; 1474 cp1 = cp; 1475 cp2 = Model; 1476 for (; !isspace((int)*cp) && cp-cp1 < 20; cp++, cp2++) 1477 *cp2 = *cp; 1478 *cp2 = '\0'; 1479 1480 cp = 0; 1481 if (!strncmp(Model, "PVT6", (size_t) 4)) { 1482 cp = "PVT6"; 1483 instance->model = ONCORE_PVT6; 1484 } else if (Model[0] == 'A') { 1485 cp = "Basic"; 1486 instance->model = ONCORE_BASIC; 1487 } else if (Model[0] == 'B' || !strncmp(Model, "T8", (size_t) 2)) { 1488 cp = "VP"; 1489 instance->model = ONCORE_VP; 1490 } else if (!strncmp(Model, "P1", (size_t) 2)) { 1491 cp = "M12"; 1492 instance->model = ONCORE_M12; 1493 } else if (Model[0] == 'R') { 1494 if (Model[5] == 'N') { 1495 cp = "GT"; 1496 instance->model = ONCORE_GT; 1497 } else if ((Model[1] == '3' || Model[1] == '4') && Model[5] == 'G') { 1498 cp = "GT+"; 1499 instance->model = ONCORE_GTPLUS; 1500 } else if ((Model[1] == '5' && Model[5] == 'U') || (Model[1] == '1' && Model[5] == 'A')) { 1501 cp = "UT"; 1502 instance->model = ONCORE_UT; 1503 } else if (Model[1] == '5' && Model[5] == 'G') { 1504 cp = "UT+"; 1505 instance->model = ONCORE_UTPLUS; 1506 } else if (Model[1] == '6' && Model[5] == 'G') { 1507 cp = "SL"; 1508 instance->model = ONCORE_SL; 1509 } else { 1510 cp = "Unknown"; 1511 instance->model = ONCORE_UNKNOWN; 1512 } 1513 } else { 1514 cp = "Unknown"; 1515 instance->model = ONCORE_UNKNOWN; 1516 } 1517 1518 sprintf(Msg, "This looks like an Oncore %s with version %d.%d firmware.", cp, instance->version, instance->revision); 1519 record_clock_stats(&(instance->peer->srcadr), Msg); 1520 1521 if (instance->chan == 0) { /* dont reset if set in input data */ 1522 instance->chan = 8; /* default */ 1523 if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6) 1524 instance->chan = 6; 1525 else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS) 1526 instance->chan = 8; 1527 else if (instance->model == ONCORE_M12) 1528 instance->chan = 12; 1529 } 1530 1531 if (instance->traim == -1) { /* dont reset if set in input data */ 1532 instance->traim = 0; /* default */ 1533 if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6) 1534 instance->traim = 0; 1535 else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS) 1536 instance->traim = 1; 1537 else if (instance->model == ONCORE_M12) 1538 instance->traim = 0; 1539 } 1540 1541 sprintf(Msg, "Channels = %d, TRAIM = %s", instance->chan, 1542 ((instance->traim < 0) ? "UNKNOWN" : ((instance->traim > 0) ? "ON" : "OFF"))); 1543 record_clock_stats(&(instance->peer->srcadr), Msg); 1544 1545 /* The M12 with 1.3 Firmware, looses track of all Satellites and has to 1546 * start again if we go from 0D -> 3D, then looses them again when we 1547 * go from 3D -> 0D. We do this to get a @@Ea message for SHMEM. 1548 * For NOW we have SHMEM turned off for the M12, v1.3 1549 */ 1550 1551 /*BAD M12*/ if (instance->model == ONCORE_M12 && instance->version == 1 && instance->revision <= 3) { 1552 instance->shmem_fname = 0; 1553 cp = "*** SHMEM turned off for ONCORE M12 ***"; 1554 record_clock_stats(&(instance->peer->srcadr), cp); 1555 } 1556 1557 /* 1558 * we now know model number and have zeroed 1559 * instance->shmem_fname if SHMEM is not supported 1560 */ 1561 1562 if (instance->shmem_fname); 1563 oncore_init_shmem(instance); 1564 1565 if (instance->shmem) 1566 cp = "SHMEM is available"; 1567 else 1568 cp = "SHMEM is NOT available"; 1569 record_clock_stats(&(instance->peer->srcadr), cp); 1570 1571 #ifdef HAVE_PPSAPI 1572 if (instance->assert) 1573 cp = "Timing on Assert."; 1574 else 1575 cp = "Timing on Clear."; 1576 record_clock_stats(&(instance->peer->srcadr), cp); 1577 #endif 1578 1579 mode = instance->init_type; 1580 if (mode == 3 || mode == 4) { /* Cf will call Fa */ 1581 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cf, sizeof(oncore_cmd_Cf)); 1582 instance->o_state = ONCORE_RESET_SENT; 1583 cp = "state = ONCORE_RESET_SENT"; 1584 record_clock_stats(&(instance->peer->srcadr), cp); 1585 } else { 1586 if (instance->chan == 6) 1587 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ca, sizeof(oncore_cmd_Ca)); 1588 else if (instance->chan == 8) 1589 oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof(oncore_cmd_Fa)); 1590 else if (instance->chan == 12) 1591 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ia, sizeof(oncore_cmd_Ia)); 1592 1593 instance->o_state = ONCORE_TEST_SENT; 1594 cp = "state = ONCORE_TEST_SENT"; 1595 record_clock_stats(&(instance->peer->srcadr), cp); 1596 instance->timeout = 4; 1597 } 1598 } 1599 1600 1601 1602 static void 1603 oncore_msg_Cj_init( 1604 struct instance *instance, 1605 u_char *buf, 1606 size_t len 1607 ) 1608 { 1609 char *cp, Cmd[20], Msg[160]; 1610 int mode; 1611 1612 /* OK, know type of Oncore, have possibly reset, and have tested. 1613 * If we have or don't have TRAIM and position hold may still be unknown. 1614 * Now initialize. 1615 */ 1616 1617 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Set Posn Fix mode (not Idle (VP)) */ 1618 oncore_sendmsg(instance->ttyfd, oncore_cmd_Bb, sizeof(oncore_cmd_Bb)); /* turn on for shmem */ 1619 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ek, sizeof(oncore_cmd_Ek)); /* turn off */ 1620 oncore_sendmsg(instance->ttyfd, oncore_cmd_Aw, sizeof(oncore_cmd_Aw)); /* UTC time */ 1621 oncore_sendmsg(instance->ttyfd, oncore_cmd_AB, sizeof(oncore_cmd_AB)); /* Appl type static */ 1622 oncore_sendmsg(instance->ttyfd, oncore_cmd_Be, sizeof(oncore_cmd_Be)); /* Tell us the Almanac for shmem */ 1623 1624 /* Turn OFF position hold, it needs to be off to set position (for some units), 1625 will get set ON in @@Ea later */ 1626 1627 if (instance->chan == 12) 1628 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); 1629 else { 1630 oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); 1631 oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); 1632 } 1633 1634 mode = instance->init_type; 1635 if (debug) { 1636 printf("ONCORE[%d]: INIT mode = %d\n", instance->unit, mode); 1637 printf("ONCORE[%d]: chan = %d\n", instance->unit, instance->chan); 1638 } 1639 1640 /* If there is Position input in the Config file 1641 * and mode = (1,3) set it as posn hold posn, goto 0D mode. 1642 * or mode = (2,4) set it as INITIAL position, and do Site Survey. 1643 */ 1644 1645 1646 if (instance->posn_set) { 1647 switch (mode) { /* if we have a position, put it in as posn and posn-hold posn */ 1648 case 0: 1649 break; 1650 case 1: 1651 case 2: 1652 case 3: 1653 case 4: 1654 memcpy(Cmd, oncore_cmd_As, sizeof(oncore_cmd_As)); /* dont modify static variables */ 1655 w32_buf(&Cmd[2], (int) instance->ss_lat); 1656 w32_buf(&Cmd[6], (int) instance->ss_long); 1657 w32_buf(&Cmd[10], (int) instance->ss_ht); 1658 Cmd[14] = 0; 1659 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_As)); 1660 1661 memcpy(Cmd, oncore_cmd_Au, sizeof(oncore_cmd_Au)); 1662 w32_buf(&Cmd[2], (int) instance->ss_ht); 1663 Cmd[6] = 0; 1664 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Au)); 1665 1666 if (instance->chan == 12) { 1667 memcpy(Cmd, oncore_cmd_Ga, sizeof(oncore_cmd_Ga)); 1668 w32_buf(&Cmd[2], (int) instance->ss_lat); 1669 w32_buf(&Cmd[6], (int) instance->ss_long); 1670 w32_buf(&Cmd[10], (int) instance->ss_ht); 1671 Cmd[14] = 0; 1672 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ga)); 1673 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); 1674 } else { 1675 memcpy(Cmd, oncore_cmd_Ad, sizeof(oncore_cmd_Ad)); 1676 w32_buf(&Cmd[2], (int) instance->ss_lat); 1677 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ad)); 1678 1679 memcpy(Cmd, oncore_cmd_Ae, sizeof(oncore_cmd_Ae)); 1680 w32_buf(&Cmd[2], (int) instance->ss_long); 1681 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ae)); 1682 1683 memcpy(Cmd, oncore_cmd_Af, sizeof(oncore_cmd_Af)); 1684 w32_buf(&Cmd[2], (int) instance->ss_ht); 1685 Cmd[6] = 0; 1686 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Af)); 1687 oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1)); 1688 } 1689 break; 1690 } 1691 } 1692 1693 1694 switch (mode) { 1695 case 0: /* NO initialization, don't change anything */ 1696 instance->site_survey = ONCORE_SS_DONE; 1697 break; 1698 1699 case 1: 1700 case 3: /* Use given Position */ 1701 instance->site_survey = ONCORE_SS_DONE; 1702 break; 1703 1704 case 2: 1705 case 4: /* Site Survey */ 1706 if (instance->chan == 12) { /* no 12chan site survey command */ 1707 instance->site_survey = ONCORE_SS_SW; 1708 sprintf(Msg, "Initiating software 3D site survey (%d samples)", POS_HOLD_AVERAGE); 1709 record_clock_stats(&(instance->peer->srcadr), Msg); 1710 } else { 1711 instance->site_survey = ONCORE_SS_TESTING; 1712 oncore_sendmsg(instance->ttyfd, oncore_cmd_At2, sizeof(oncore_cmd_At2)); 1713 } 1714 break; 1715 } 1716 1717 if (mode != 0) { 1718 /* cable delay in ns */ 1719 memcpy(Cmd, oncore_cmd_Az, sizeof(oncore_cmd_Az)); 1720 w32_buf(&Cmd[2], instance->delay); 1721 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Az)); 1722 1723 /* PPS offset in ns */ 1724 if (instance->offset) { 1725 if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || 1726 instance->model == ONCORE_UTPLUS) { 1727 memcpy(Cmd, oncore_cmd_Ay, sizeof(oncore_cmd_Ay)); 1728 w32_buf(&Cmd[2], instance->offset); 1729 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ay)); 1730 } else { 1731 cp = "Can only set PPS OFFSET for VP/UT/UT+, offset ignored"; 1732 record_clock_stats(&(instance->peer->srcadr), cp); 1733 instance->offset = 0; 1734 } 1735 } 1736 } 1737 1738 /* 6, 8 12 chan - Position/Status/Data Output Message, 1/s */ 1739 /* now we're really running */ 1740 1741 if (instance->chan == 6) { /* kill 8 chan commands, possibly testing VP in 6chan mode */ 1742 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba, sizeof(oncore_cmd_Ba)); 1743 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0)); 1744 oncore_sendmsg(instance->ttyfd, oncore_cmd_En0, sizeof(oncore_cmd_En0)); 1745 } else if (instance->chan == 8) { /* kill 6chan commands */ 1746 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea, sizeof(oncore_cmd_Ea)); 1747 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0)); 1748 oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0)); 1749 } else if (instance->chan == 12) 1750 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha, sizeof(oncore_cmd_Ha)); 1751 1752 instance->count = 1; 1753 instance->o_state = ONCORE_ALMANAC; 1754 cp = "state = ONCORE_ALMANAC"; 1755 record_clock_stats(&(instance->peer->srcadr), cp); 1756 } 1757 1758 1759 1760 /* 1761 * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup 1762 * not so for VP (eeprom) or any unit with a battery 1763 */ 1764 1765 static void 1766 oncore_msg_Cf( 1767 struct instance *instance, 1768 u_char *buf, 1769 size_t len 1770 ) 1771 { 1772 const char *cp; 1773 1774 if (instance->o_state == ONCORE_RESET_SENT) { 1775 if (instance->chan == 6) 1776 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ca, sizeof(oncore_cmd_Ca)); 1777 else if (instance->chan == 8) 1778 oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof(oncore_cmd_Fa)); 1779 else if (instance->chan == 12) 1780 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ia, sizeof(oncore_cmd_Ia)); 1781 1782 instance->o_state = ONCORE_TEST_SENT; 1783 cp = "state = ONCORE_TEST_SENT"; 1784 record_clock_stats(&(instance->peer->srcadr), cp); 1785 } 1786 } 1787 1788 1789 1790 /* Here for @@Ca, @@Fa and @@Ia messages */ 1791 1792 /* There are good reasons NOT to do a @@Ca or @@Fa command with the ONCORE. 1793 * Doing it, it was found that under some circumstances the following 1794 * command would fail if issued immediately after the return from the 1795 * @@Fa, but a 2sec delay seemed to fix things. Since simply calling 1796 * sleep(2) is wastefull, and may cause trouble for some OS's, repeating 1797 * itimer, we set a flag, and test it at the next POLL. If it hasnt 1798 * been cleared, we reissue the @@Cj that is issued below. 1799 * Note that we do a @@Cj at the beginning, and again here. 1800 * The first is to get the info, the 2nd is just used as a safe command 1801 * after the @@Fa for all Oncores (and it was in this posn in the 1802 * original code). 1803 */ 1804 1805 static void 1806 oncore_msg_CaFaIa( 1807 struct instance *instance, 1808 u_char *buf, 1809 size_t len 1810 ) 1811 { 1812 char *cp; 1813 1814 if (instance->o_state == ONCORE_TEST_SENT) { 1815 int antenna; 1816 1817 instance->timeout = 0; 1818 1819 if (debug > 2) { 1820 if (buf[2] == 'I') 1821 printf("ONCORE[%d]: >>@@%ca %x %x %x\n", instance->unit, buf[2], buf[4], buf[5], buf[6]); 1822 else 1823 printf("ONCORE[%d]: >>@@%ca %x %x\n", instance->unit, buf[2], buf[4], buf[5]); 1824 } 1825 1826 antenna = buf[4] & 0xc0; 1827 antenna >>= 6; 1828 buf[4] &= ~0xc0; 1829 1830 if (buf[4] || buf[5] || ((buf[2] == 'I') && buf[6])) { 1831 cp = "ONCORE: Self Test Failed, shutting down driver"; 1832 record_clock_stats(&(instance->peer->srcadr), cp); 1833 oncore_shutdown(instance->unit, instance->peer); 1834 return; 1835 } 1836 if (antenna) { 1837 char *cp1, Msg[160]; 1838 1839 cp1 = (antenna == 0x1) ? "(Over Current)" : 1840 ((antenna == 0x2) ? "(Under Current)" : "(No Voltage)"); 1841 1842 cp = "ONCORE: Self Test, NonFatal Antenna Problems "; 1843 strcpy(Msg, cp); 1844 strcat(Msg, cp1); 1845 record_clock_stats(&(instance->peer->srcadr), Msg); 1846 } 1847 1848 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 1849 instance->o_state = ONCORE_INIT; 1850 cp = "state = ONCORE_INIT"; 1851 record_clock_stats(&(instance->peer->srcadr), cp); 1852 } 1853 } 1854 1855 1856 1857 /* Ba, Ea and Ha come here */ 1858 1859 static void 1860 oncore_msg_BaEaHa( 1861 struct instance *instance, 1862 u_char *buf, 1863 size_t len 1864 ) 1865 { 1866 const char *cp; 1867 char Msg[160], Cmd[20]; 1868 u_char *vp; /* pointer to start of shared mem for Ba/Ea/Ha */ 1869 size_t Len; 1870 1871 /* At the beginning of Ea here there are various 'timers'. 1872 * We enter Ea 1/sec, and since the upper levels of NTP have usurped 1873 * the use of timers, we use the 1/sec entry to Ea to do things that 1874 * we would normally do with timers... 1875 */ 1876 1877 if (instance->count) { 1878 if (instance->count++ < 5) /* make sure results are stable, using position */ 1879 return; 1880 instance->count = 0; 1881 } 1882 1883 if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN) 1884 return; 1885 1886 Len = len+3; /* message length @@ -> CR,LF */ 1887 memcpy(instance->Ea, buf, Len); /* Ba, Ea or Ha */ 1888 1889 if (buf[2] == 'B') { /* 6chan */ 1890 if (instance->Ea[64]&0x8) 1891 instance->mode = MODE_0D; 1892 else if (instance->Ea[64]&0x10) 1893 instance->mode = MODE_2D; 1894 else if (instance->Ea[64]&0x20) 1895 instance->mode = MODE_3D; 1896 } else if (buf[2] == 'E') { /* 8chan */ 1897 if (instance->Ea[72]&0x8) 1898 instance->mode = MODE_0D; 1899 else if (instance->Ea[72]&0x10) 1900 instance->mode = MODE_2D; 1901 else if (instance->Ea[72]&0x20) 1902 instance->mode = MODE_3D; 1903 } else if (buf[2] == 'H') { /* 12chan */ 1904 int bits; 1905 1906 bits = (instance->Ea[129]>>5) & 0x7; /* actually Ha */ 1907 if (bits == 0x4) 1908 instance->mode = MODE_0D; 1909 else if (bits == 0x6) 1910 instance->mode = MODE_2D; 1911 else if (bits == 0x7) 1912 instance->mode = MODE_3D; 1913 } 1914 1915 vp = (u_char) 0; /* just to keep compiler happy */ 1916 if (instance->chan == 6) { 1917 instance->rsm.bad_almanac = instance->Ea[64]&0x1; 1918 instance->rsm.bad_fix = instance->Ea[64]&0x52; 1919 vp = &instance->shmem[instance->shmem_Ba]; 1920 } else if (instance->chan == 8) { 1921 instance->rsm.bad_almanac = instance->Ea[72]&0x1; 1922 instance->rsm.bad_fix = instance->Ea[72]&0x52; 1923 vp = &instance->shmem[instance->shmem_Ea]; 1924 } else if (instance->chan == 12) { 1925 int bits1, bits2; 1926 1927 bits1 = (instance->Ea[129]>>5) & 0x7; /* actually Ha */ 1928 bits2 = instance->Ea[130]; 1929 instance->rsm.bad_almanac = (bits2 & 0x80); 1930 instance->rsm.bad_fix = (bits2 & 0x8) || (bits1 == 0x2); 1931 /* too few sat Bad Geom */ 1932 vp = &instance->shmem[instance->shmem_Ha]; 1933 #if 0 1934 fprintf(stderr, "ONCORE: DEBUG BITS: (%x %x), (%x %x), %x %x %x %x %x\n", 1935 instance->Ea[129], instance->Ea[130], bits1, bits2, instance->mode == MODE_0D, instance->mode == MODE_2D, 1936 instance->mode == MODE_3D, instance->rsm.bad_almanac, instance->rsm.bad_fix); 1937 #endif 1938 } 1939 1940 /* Here calculate dH = GPS - MSL for output message */ 1941 /* also set Altitude Hold mode if GT */ 1942 1943 if (!instance->have_dH) { 1944 int GPS, MSL; 1945 1946 instance->have_dH++; 1947 if (instance->chan == 12) { 1948 GPS = buf_w32(&instance->Ea[39]); 1949 MSL = buf_w32(&instance->Ea[43]); 1950 } else { 1951 GPS = buf_w32(&instance->Ea[23]); 1952 MSL = buf_w32(&instance->Ea[27]); 1953 } 1954 instance->dH = GPS - MSL; 1955 instance->dH /= 100.; 1956 1957 if (MSL) { /* not set ! */ 1958 sprintf(Msg, "dH = (GPS - MSL) = %.2fm", instance->dH); 1959 record_clock_stats(&(instance->peer->srcadr), Msg); 1960 } 1961 1962 /* stuck in here as it only gets done once */ 1963 1964 if (instance->chan != 12 && !instance->saw_At) { 1965 cp = "Not Good, no @@At command, must be a GT/GT+"; 1966 record_clock_stats(&(instance->peer->srcadr), cp); 1967 oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); 1968 } 1969 } 1970 1971 /* 1972 * For instance->site_survey to be ONCORE_SS_TESTING, this must be the first 1973 * time thru @@Ea. There are two choices 1974 * (a) We did not get a response to the @@At0 or @@At2 commands, 1975 * must be a GT/GT+/SL with no position hold mode. 1976 * (b) Saw the @@At0, @@At2 commands, but @@At2 failed, 1977 * must be a VP or older UT which doesnt have Site Survey mode. 1978 * We will have to do it ourselves. 1979 */ 1980 1981 if (instance->site_survey == ONCORE_SS_TESTING) { /* first time thru Ea */ 1982 sprintf(Msg, "Initiating software 3D site survey (%d samples)", 1983 POS_HOLD_AVERAGE); 1984 record_clock_stats(&(instance->peer->srcadr), Msg); 1985 instance->site_survey = ONCORE_SS_SW; 1986 1987 instance->ss_lat = instance->ss_long = instance->ss_ht = 0; 1988 oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* disable */ 1989 } 1990 1991 if (instance->shmem) { 1992 int i; 1993 1994 i = 0; 1995 if (instance->mode == MODE_0D) /* 0D, Position Hold */ 1996 i = 1; 1997 else if (instance->mode == MODE_2D) /* 2D, Altitude Hold */ 1998 i = 2; 1999 else if (instance->mode == MODE_3D) /* 3D fix */ 2000 i = 3; 2001 if (i) { 2002 i *= (Len+3); 2003 vp[i + 2]++; 2004 memcpy(&vp[i+3], buf, Len); 2005 } 2006 } 2007 2008 /* Almanac mode, waiting for Almanac, cant do anything till we have it */ 2009 /* When we have an almanac, start the En/Bn messages */ 2010 2011 if (instance->o_state == ONCORE_ALMANAC) { 2012 if (instance->rsm.bad_almanac) { 2013 if (debug) 2014 printf("ONCORE: waiting for almanac\n"); 2015 return; 2016 } else { /* Here we have almanac. 2017 Start TRAIM (@@En/@@Bn) dependant on TRAIM flag. 2018 If flag == -1, then we dont know if this unit supports 2019 traim, and we issue the command and then wait up to 2020 5sec to see if we get a reply */ 2021 2022 if (instance->traim != 0) { /* either yes or unknown */ 2023 if (instance->chan == 6) 2024 oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn, sizeof(oncore_cmd_Bn)); 2025 else if (instance->chan == 8) 2026 oncore_sendmsg(instance->ttyfd, oncore_cmd_En, sizeof(oncore_cmd_En)); 2027 2028 if (instance->traim == -1) 2029 instance->traim_delay = 1; 2030 } 2031 instance->o_state = ONCORE_RUN; 2032 cp = "state = ONCORE_RUN"; 2033 record_clock_stats(&(instance->peer->srcadr), cp); 2034 } 2035 } 2036 2037 /* 2038 * check if timer active 2039 * if it hasnt been cleared, then @@En/@@Bn did not respond 2040 */ 2041 2042 if (instance->traim_delay) { 2043 if (instance->traim_delay++ > 5) { 2044 instance->traim = 0; 2045 instance->traim_delay = 0; 2046 cp = "ONCORE: Did not detect TRAIM response, TRAIM = OFF"; 2047 record_clock_stats(&(instance->peer->srcadr), cp); 2048 } 2049 } 2050 2051 /* 2052 * must be ONCORE_RUN if we are here. 2053 */ 2054 2055 instance->pp->year = buf[6]*256+buf[7]; 2056 instance->pp->day = ymd2yd(buf[6]*256+buf[7], buf[4], buf[5]); 2057 instance->pp->hour = buf[8]; 2058 instance->pp->minute = buf[9]; 2059 instance->pp->second = buf[10]; 2060 2061 /* 2062 * Check to see if Hardware SiteSurvey has Finished. 2063 */ 2064 2065 if ((instance->site_survey == ONCORE_SS_HW) && !(instance->Ea[37] & 0x20)) { 2066 record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode"); 2067 instance->site_survey = ONCORE_SS_DONE; 2068 } 2069 2070 if (!instance->printed && instance->site_survey == ONCORE_SS_DONE) { 2071 instance->printed = 1; 2072 /* Read back Position Hold Params (cant for GT) */ 2073 if (instance->saw_At) 2074 oncore_sendmsg(instance->ttyfd, oncore_cmd_Asx, sizeof(oncore_cmd_Asx)); 2075 else 2076 oncore_print_As(instance); 2077 2078 /* Read back PPS Offset for Output */ 2079 /* Nb. This will fail silently for early UT (no plus) and M12 models */ 2080 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ayx, sizeof(oncore_cmd_Ayx)); 2081 2082 /* Read back Cable Delay for Output */ 2083 oncore_sendmsg(instance->ttyfd, oncore_cmd_Azx, sizeof(oncore_cmd_Azx)); 2084 } 2085 2086 /* 2087 * Check the leap second status once per day. 2088 */ 2089 2090 if (instance->Bj_day != buf[5]) { /* do this 1/day */ 2091 instance->Bj_day = buf[5]; 2092 2093 if (instance->chan == 12) 2094 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gj, sizeof(oncore_cmd_Gj)); 2095 else { 2096 /* 2097 * The following additional check, checking for June/December, is a 2098 * workaround for incorrect ONCORE firmware. The oncore starts 2099 * reporting the leap second when the GPS satellite data message 2100 * (page 18, subframe 4) is updated to a date in the future, which 2101 * can be several months before the leap second. WWV and other 2102 * services seem to wait until the month of the event to turn 2103 * on their indicators (which is usually a single bit). 2104 */ 2105 2106 if ((buf[4] == 6) || (buf[4] == 12)) 2107 oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof(oncore_cmd_Bj)); 2108 } 2109 } 2110 2111 /* 2112 * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn. 2113 */ 2114 2115 if (instance->shmem && instance->shmem_Posn && (instance->site_survey == ONCORE_SS_DONE)) { /* dont screw up the SS by changing mode */ 2116 if (instance->pp->second%15 == 3) { /* start the sequence */ 2117 instance->shmem_reset = 1; 2118 if (instance->chan == 12) { 2119 if (instance->shmem_Posn == 2) 2120 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd2, sizeof(oncore_cmd_Gd2)); /* 2D */ 2121 else 2122 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* 3D */ 2123 } else { 2124 if (instance->saw_At) { 2125 oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* out of 0D to 3D mode */ 2126 if (instance->shmem_Posn == 2) 2127 oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); /* 3D to 2D mode */ 2128 } else 2129 oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); 2130 } 2131 } else if (instance->shmem_reset || (instance->mode != MODE_0D)) { 2132 instance->shmem_reset = 0; 2133 if (instance->chan == 12) 2134 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); /* 0D */ 2135 else { 2136 if (instance->saw_At) { 2137 if (instance->mode == MODE_2D) 2138 oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* 2D -> 3D or 0D */ 2139 oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1)); /* to 0D mode */ 2140 } else 2141 oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); 2142 } 2143 } 2144 } 2145 2146 if (instance->traim == 0) /* NO traim, go get tick */ 2147 oncore_get_timestamp(instance, instance->offset, instance->offset); 2148 2149 if (instance->site_survey != ONCORE_SS_SW) 2150 return; 2151 2152 /* 2153 * We have to average our own position for the Position Hold Mode 2154 * We use Heights from the GPS ellipsoid. 2155 */ 2156 2157 if (instance->rsm.bad_fix) /* Not if poor geometry or less than 3 sats */ 2158 return; 2159 2160 if (instance->mode != MODE_3D) /* Only 3D Fix */ 2161 return; 2162 2163 instance->ss_lat += buf_w32(&instance->Ea[15]); 2164 instance->ss_long += buf_w32(&instance->Ea[19]); 2165 instance->ss_ht += buf_w32(&instance->Ea[23]); /* GPS ellipsoid */ 2166 instance->ss_count++; 2167 2168 if (instance->ss_count != POS_HOLD_AVERAGE) 2169 return; 2170 2171 instance->ss_lat /= POS_HOLD_AVERAGE; 2172 instance->ss_long /= POS_HOLD_AVERAGE; 2173 instance->ss_ht /= POS_HOLD_AVERAGE; 2174 2175 sprintf(Msg, "Surveyed posn: lat %.3f long %.3f ht %.3f", 2176 instance->ss_lat, instance->ss_long, instance->ss_ht); 2177 record_clock_stats(&(instance->peer->srcadr), Msg); 2178 2179 /* set newly determined position as 3D Position hold position */ 2180 2181 memcpy(Cmd, oncore_cmd_As, sizeof(oncore_cmd_As)); 2182 w32_buf(&Cmd[2], (int) instance->ss_lat); 2183 w32_buf(&Cmd[6], (int) instance->ss_long); 2184 w32_buf(&Cmd[10], (int) instance->ss_ht); 2185 Cmd[14] = 0; 2186 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_As)); 2187 2188 /* set height seperately for 2D */ 2189 2190 memcpy(Cmd, oncore_cmd_Au, sizeof(oncore_cmd_Au)); 2191 w32_buf(&Cmd[2], (int) instance->ss_ht); 2192 Cmd[6] = 0; 2193 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Au)); 2194 2195 /* and set Position Hold */ 2196 2197 if (instance->chan == 12) 2198 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); 2199 else { 2200 if (instance->saw_At) 2201 oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1)); 2202 else 2203 oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); 2204 } 2205 2206 record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode"); 2207 instance->site_survey = ONCORE_SS_DONE; 2208 } 2209 2210 2211 2212 static void 2213 oncore_msg_BnEn( 2214 struct instance *instance, 2215 u_char *buf, 2216 size_t len 2217 ) 2218 { 2219 long dt1, dt2; 2220 char *cp; 2221 2222 if (instance->o_state != ONCORE_RUN) 2223 return; 2224 2225 if (instance->traim_delay) { /* flag that @@En/@@Bn returned */ 2226 instance->traim = 1; 2227 instance->traim_delay = 0; 2228 cp = "ONCORE: Detected TRAIM, TRAIM = ON"; 2229 record_clock_stats(&(instance->peer->srcadr), cp); 2230 } 2231 2232 memcpy(instance->En, buf, len); /* En or Bn */ 2233 2234 /* If Time RAIM doesn't like it, don't trust it */ 2235 2236 if (instance->En[21]) 2237 return; 2238 2239 dt1 = instance->saw_tooth + instance->offset; /* dt this time step */ 2240 instance->saw_tooth = (s_char) instance->En[25]; /* update for next time */ 2241 dt2 = instance->saw_tooth + instance->offset; /* dt next time step */ 2242 2243 oncore_get_timestamp(instance, dt1, dt2); 2244 } 2245 2246 2247 2248 static void 2249 oncore_get_timestamp( 2250 struct instance *instance, 2251 long dt1, /* tick offset THIS time step */ 2252 long dt2 /* tick offset NEXT time step */ 2253 ) 2254 { 2255 int Rsm; 2256 u_long i, j; 2257 l_fp ts, ts_tmp; 2258 double dmy; 2259 #ifdef HAVE_STRUCT_TIMESPEC 2260 struct timespec *tsp = 0; 2261 #else 2262 struct timeval *tsp = 0; 2263 #endif 2264 #ifdef HAVE_PPSAPI 2265 int current_mode; 2266 pps_params_t current_params; 2267 struct timespec timeout; 2268 pps_info_t pps_i; 2269 #else /* ! HAVE_PPSAPI */ 2270 #ifdef HAVE_CIOGETEV 2271 struct ppsclockev ev; 2272 int r = CIOGETEV; 2273 #endif 2274 #ifdef HAVE_TIOCGPPSEV 2275 struct ppsclockev ev; 2276 int r = TIOCGPPSEV; 2277 #endif 2278 #if TIOCDCDTIMESTAMP 2279 struct timeval tv; 2280 #endif 2281 #endif /* ! HAVE_PPS_API */ 2282 2283 if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D)) 2284 return; 2285 2286 /* Don't do anything without an almanac to define the GPS->UTC delta */ 2287 2288 if (instance->rsm.bad_almanac) 2289 return; 2290 2291 #ifdef HAVE_PPSAPI 2292 j = instance->ev_serial; 2293 timeout.tv_sec = 0; 2294 timeout.tv_nsec = 0; 2295 if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i, 2296 &timeout) < 0) { 2297 printf("ONCORE: time_pps_fetch failed\n"); 2298 return; 2299 } 2300 2301 if (instance->assert) { 2302 tsp = &pps_i.assert_timestamp; 2303 2304 if (debug > 2) { 2305 i = (u_long) pps_i.assert_sequence; 2306 #ifdef HAVE_STRUCT_TIMESPEC 2307 printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n", 2308 instance->unit, i, j, 2309 (long)tsp->tv_sec, (long)tsp->tv_nsec); 2310 #else 2311 printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n", 2312 instance->unit, i, j, 2313 (long)tsp->tv_sec, (long)tsp->tv_usec); 2314 #endif 2315 } 2316 2317 if (pps_i.assert_sequence == j) { 2318 printf("ONCORE: oncore_get_timestamp, error serial pps\n"); 2319 return; 2320 } 2321 instance->ev_serial = pps_i.assert_sequence; 2322 } else { 2323 tsp = &pps_i.clear_timestamp; 2324 2325 if (debug > 2) { 2326 i = (u_long) pps_i.clear_sequence; 2327 #ifdef HAVE_STRUCT_TIMESPEC 2328 printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n", 2329 instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_nsec); 2330 #else 2331 printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n", 2332 instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_usec); 2333 #endif 2334 } 2335 2336 if (pps_i.clear_sequence == j) { 2337 printf("ONCORE: oncore_get_timestamp, error serial pps\n"); 2338 return; 2339 } 2340 instance->ev_serial = pps_i.clear_sequence; 2341 } 2342 2343 /* convert timespec -> ntp l_fp */ 2344 2345 dmy = tsp->tv_nsec; 2346 dmy /= 1e9; 2347 ts.l_uf = dmy * 4294967296.0; 2348 ts.l_ui = tsp->tv_sec; 2349 #if 0 2350 alternate code for previous 4 lines is 2351 dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */ 2352 DTOLFP(dmy, &ts); 2353 dmy = tsp->tv_sec; /* integer part */ 2354 DTOLFP(dmy, &ts_tmp); 2355 L_ADD(&ts, &ts_tmp); 2356 or more simply 2357 dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */ 2358 DTOLFP(dmy, &ts); 2359 ts.l_ui = tsp->tv_sec; 2360 #endif /* 0 */ 2361 #else 2362 # if defined(HAVE_TIOCGPPSEV) || defined(HAVE_CIOGETEV) 2363 j = instance->ev_serial; 2364 if (ioctl(instance->ppsfd, r, (caddr_t) &ev) < 0) { 2365 perror("ONCORE: IOCTL:"); 2366 return; 2367 } 2368 2369 tsp = &ev.tv; 2370 2371 if (debug > 2) 2372 #ifdef HAVE_STRUCT_TIMESPEC 2373 printf("ONCORE: serial/j (%d, %d) %ld.%09ld\n", 2374 ev.serial, j, tsp->tv_sec, tsp->tv_nsec); 2375 #else 2376 printf("ONCORE: serial/j (%d, %d) %ld.%06ld\n", 2377 ev.serial, j, tsp->tv_sec, tsp->tv_usec); 2378 #endif 2379 2380 if (ev.serial == j) { 2381 printf("ONCORE: oncore_get_timestamp, error serial pps\n"); 2382 return; 2383 } 2384 instance->ev_serial = ev.serial; 2385 2386 /* convert timeval -> ntp l_fp */ 2387 2388 TVTOTS(tsp, &ts); 2389 # else 2390 # if defined(TIOCDCDTIMESTAMP) 2391 if(ioctl(instance->ppsfd, TIOCDCDTIMESTAMP, &tv) < 0) { 2392 perror("ONCORE: ioctl(TIOCDCDTIMESTAMP)"); 2393 return; 2394 } 2395 tsp = &tv; 2396 TVTOTS(tsp, &ts); 2397 # else 2398 #error "Cannot compile -- no PPS mechanism configured!" 2399 # endif 2400 # endif 2401 #endif 2402 /* now have timestamp in ts */ 2403 /* add in saw_tooth and offset, these will be ZERO if no TRAIM */ 2404 2405 /* saw_tooth not really necessary if using TIMEVAL */ 2406 /* since its only precise to us, but do it anyway. */ 2407 2408 /* offset in ns, and is positive (late), we subtract */ 2409 /* to put the PPS time transition back where it belongs */ 2410 2411 #ifdef HAVE_PPSAPI 2412 /* must hand the offset for the NEXT sec off to the Kernel to do */ 2413 /* the addition, so that the Kernel PLL sees the offset too */ 2414 2415 if (instance->assert) 2416 instance->pps_p.assert_offset.tv_nsec = -dt2; 2417 else 2418 instance->pps_p.clear_offset.tv_nsec = -dt2; 2419 2420 /* The following code is necessary, and not just a time_pps_setparams, 2421 * using the saved instance->pps_p, since some other process on the 2422 * machine may have diddled with the mode bits (say adding something 2423 * that it needs). We take what is there and ADD what we need. 2424 * [[ The results from the time_pps_getcap is unlikely to change so 2425 * we could probably just save it, but I choose to do the call ]] 2426 * Unfortunately, there is only ONE set of mode bits in the kernel per 2427 * interface, and not one set for each open handle. 2428 * 2429 * There is still a race condition here where we might mess up someone 2430 * elses mode, but if he is being careful too, he should survive. 2431 */ 2432 2433 if (time_pps_getcap(instance->pps_h, ¤t_mode) < 0) { 2434 msyslog(LOG_ERR, 2435 "refclock_ioctl: time_pps_getcap failed: %m"); 2436 return; 2437 } 2438 2439 if (time_pps_getparams(instance->pps_h, ¤t_params) < 0) { 2440 msyslog(LOG_ERR, 2441 "refclock_ioctl: time_pps_getparams failed: %m"); 2442 return; 2443 } 2444 2445 /* or current and mine */ 2446 current_params.mode |= instance->pps_p.mode; 2447 /* but only set whats legal */ 2448 current_params.mode &= current_mode; 2449 2450 current_params.assert_offset.tv_sec = 0; 2451 current_params.assert_offset.tv_nsec = -dt2; 2452 current_params.clear_offset.tv_sec = 0; 2453 current_params.clear_offset.tv_nsec = -dt2; 2454 2455 if (time_pps_setparams(instance->pps_h, ¤t_params)) 2456 perror("time_pps_setparams"); 2457 #else 2458 /* if not PPSAPI, no way to inform kernel of OFFSET, just add the */ 2459 /* offset for THIS second */ 2460 2461 dmy = -1.0e-9*dt1; 2462 DTOLFP(dmy, &ts_tmp); 2463 L_ADD(&ts, &ts_tmp); 2464 #endif 2465 /* have time from UNIX origin, convert to NTP origin. */ 2466 2467 ts.l_ui += JAN_1970; 2468 instance->pp->lastrec = ts; 2469 instance->pp->msec = 0; 2470 2471 ts_tmp = ts; 2472 ts_tmp.l_ui = 0; /* zero integer part */ 2473 LFPTOD(&ts_tmp, dmy); /* convert fractional part to a double */ 2474 j = 1.0e9*dmy; /* then to integer ns */ 2475 2476 Rsm = 0; 2477 if (instance->chan == 6) 2478 Rsm = instance->Ea[64]; 2479 else if (instance->chan == 8) 2480 Rsm = instance->Ea[72]; 2481 else if (instance->chan == 12) 2482 Rsm = ((instance->Ea[129]<<8) | instance->Ea[130]); 2483 2484 if (instance->chan == 6 || instance->chan == 8) { 2485 sprintf(instance->pp->a_lastcode, /* MAX length 128, currently at 117 */ 2486 "%u.%09lu %d %d %2d %2d %2d %2ld rstat %02x dop %4.1f nsat %2d,%d traim %d sigma %d neg-sawtooth %3d sat %d%d%d%d%d%d%d%d", 2487 ts.l_ui, j, 2488 instance->pp->year, instance->pp->day, 2489 instance->pp->hour, instance->pp->minute, instance->pp->second, 2490 (long) tsp->tv_sec % 60, 2491 Rsm, 0.1*(256*instance->Ea[35]+instance->Ea[36]), 2492 /*rsat dop */ 2493 instance->Ea[38], instance->Ea[39], instance->En[21], 2494 /* nsat visible, nsat tracked, traim */ 2495 instance->En[23]*256+instance->En[24], (s_char) instance->En[25], 2496 /* sigma neg-sawtooth */ 2497 /*sat*/ instance->Ea[41], instance->Ea[45], instance->Ea[49], instance->Ea[53], 2498 instance->Ea[57], instance->Ea[61], instance->Ea[65], instance->Ea[69] 2499 ); /* will be 0 for 6 chan */ 2500 } else if (instance->chan == 12) { 2501 sprintf(instance->pp->a_lastcode, 2502 "%u.%09lu %d %d %2d %2d %2d %2ld rstat %02x dop %4.1f nsat %2d,%d sat %d%d%d%d%d%d%d%d%d%d%d%d", 2503 ts.l_ui, j, 2504 instance->pp->year, instance->pp->day, 2505 instance->pp->hour, instance->pp->minute, instance->pp->second, 2506 (long) tsp->tv_sec % 60, 2507 Rsm, 0.1*(256*instance->Ea[53]+instance->Ea[54]), 2508 /*rsat dop */ 2509 instance->Ea[55], instance->Ea[56], 2510 /* nsat visible, nsat tracked */ 2511 /*sat*/ instance->Ea[58], instance->Ea[64], instance->Ea[70], instance->Ea[76], 2512 instance->Ea[82], instance->Ea[88], instance->Ea[94], instance->Ea[100], 2513 instance->Ea[106], instance->Ea[112], instance->Ea[118], instance->Ea[124] 2514 ); 2515 } 2516 2517 if (debug > 2) { 2518 int n; 2519 n = strlen(instance->pp->a_lastcode); 2520 printf("ONCORE[%d]: len = %d %s\n", instance->unit, n, instance->pp->a_lastcode); 2521 } 2522 2523 if (!refclock_process(instance->pp)) { 2524 refclock_report(instance->peer, CEVNT_BADTIME); 2525 return; 2526 } 2527 2528 record_clock_stats(&(instance->peer->srcadr), instance->pp->a_lastcode); 2529 instance->pollcnt = 2; 2530 2531 if (instance->polled) { 2532 instance->polled = 0; 2533 /* 2534 instance->pp->dispersion = instance->pp->skew = 0; 2535 */ 2536 refclock_receive(instance->peer); 2537 } 2538 } 2539 2540 2541 2542 /* 2543 * Try to use Oncore UT+ Auto Survey Feature 2544 * If its not there (VP), set flag to do it ourselves. 2545 */ 2546 2547 static void 2548 oncore_msg_At( 2549 struct instance *instance, 2550 u_char *buf, 2551 size_t len 2552 ) 2553 { 2554 instance->saw_At = 1; 2555 if (instance->site_survey == ONCORE_SS_TESTING) { 2556 if (buf[4] == 2) { 2557 record_clock_stats(&(instance->peer->srcadr), 2558 "Initiating hardware 3D site survey"); 2559 instance->site_survey = ONCORE_SS_HW; 2560 } 2561 } 2562 } 2563 2564 2565 2566 /* get leap-second warning message */ 2567 2568 /* 2569 * @@Bj does NOT behave as documented in current Oncore firmware. 2570 * It turns on the LEAP indicator when the data is set, and does not, 2571 * as documented, wait until the beginning of the month when the 2572 * leap second will occur. 2573 * Until this firmware bug is fixed, @@Bj is only called in June/December. 2574 */ 2575 2576 static void 2577 oncore_msg_Bj( 2578 struct instance *instance, 2579 u_char *buf, 2580 size_t len 2581 ) 2582 { 2583 const char *cp; 2584 2585 switch(buf[4]) { 2586 case 1: 2587 instance->peer->leap = LEAP_ADDSECOND; 2588 cp = "Set peer.leap to LEAP_ADDSECOND"; 2589 break; 2590 case 2: 2591 instance->peer->leap = LEAP_DELSECOND; 2592 cp = "Set peer.leap to LEAP_DELSECOND"; 2593 break; 2594 case 0: 2595 default: 2596 instance->peer->leap = LEAP_NOWARNING; 2597 cp = "Set peer.leap to LEAP_NOWARNING"; 2598 break; 2599 } 2600 record_clock_stats(&(instance->peer->srcadr), cp); 2601 } 2602 2603 /* Leap Second for M12, gives all info from satellite message */ 2604 2605 static void 2606 oncore_msg_Gj( 2607 struct instance *instance, 2608 u_char *buf, 2609 size_t len 2610 ) 2611 { 2612 int dt; 2613 char Msg[160], *cp; 2614 static char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jly", 2615 "Aug", "Sep", "Oct", "Nov", "Dec" }; 2616 2617 /* print the message to verify whats there */ 2618 2619 dt = buf[5] - buf[4]; 2620 2621 #if 1 2622 sprintf(Msg, "ONCORE[%d]: Leap Sec Msg: %d %d %d %d %d %d %d %d %d %d", 2623 instance->unit, 2624 buf[4], buf[5], 256*buf[6]+buf[7], buf[8], buf[9], buf[10], 2625 (buf[14]+256*(buf[13]+256*(buf[12]+256*buf[11]))), 2626 buf[15], buf[16], buf[17]); 2627 record_clock_stats(&(instance->peer->srcadr), Msg); 2628 #endif 2629 if (dt) { 2630 sprintf(Msg, "ONCORE[%d]: Leap second (%d) scheduled for %d%s%d at %d:%d:%d", 2631 instance->unit, 2632 dt, buf[9], Month[buf[8]], 256*buf[6]+buf[7], 2633 buf[15], buf[16], buf[17]); 2634 record_clock_stats(&(instance->peer->srcadr), Msg); 2635 } 2636 2637 /* Only raise warning within a month of the leap second */ 2638 2639 instance->peer->leap = LEAP_NOWARNING; 2640 cp = "Set peer.leap to LEAP_NOWARNING"; 2641 2642 if (buf[6] == instance->Ea[6] && buf[7] == instance->Ea[7] && /* year */ 2643 buf[8] == instance->Ea[4]) { /* month */ 2644 if (dt) { 2645 if (dt < 0) { 2646 instance->peer->leap = LEAP_DELSECOND; 2647 cp = "Set peer.leap to LEAP_DELSECOND"; 2648 } else { 2649 instance->peer->leap = LEAP_ADDSECOND; 2650 cp = "Set peer.leap to LEAP_ADDSECOND"; 2651 } 2652 } 2653 } 2654 record_clock_stats(&(instance->peer->srcadr), cp); 2655 } 2656 2657 2658 2659 /* 2660 * get Position hold position 2661 */ 2662 2663 static void 2664 oncore_msg_As( 2665 struct instance *instance, 2666 u_char *buf, 2667 size_t len 2668 ) 2669 { 2670 if (!instance->printed || instance->As) 2671 return; 2672 2673 instance->As = 1; 2674 2675 instance->ss_lat = buf_w32(&buf[4]); 2676 instance->ss_long = buf_w32(&buf[8]); 2677 instance->ss_ht = buf_w32(&buf[12]); 2678 2679 /* Print out Position */ 2680 oncore_print_As(instance); 2681 } 2682 2683 2684 2685 static void 2686 oncore_print_As( 2687 struct instance *instance 2688 ) 2689 { 2690 char Msg[120], ew, ns; 2691 double xd, xm, xs, yd, ym, ys, hm, hft; 2692 int idx, idy, is, imx, imy; 2693 long lat, lon; 2694 2695 record_clock_stats(&(instance->peer->srcadr), "Posn:"); 2696 ew = 'E'; 2697 lon = instance->ss_long; 2698 if (lon < 0) { 2699 ew = 'W'; 2700 lon = -lon; 2701 } 2702 2703 ns = 'N'; 2704 lat = instance->ss_lat; 2705 if (lat < 0) { 2706 ns = 'S'; 2707 lat = -lat; 2708 } 2709 2710 hm = instance->ss_ht/100.; 2711 hft= hm/0.3048; 2712 2713 xd = lat/3600000.; /* lat, lon in int msec arc, ht in cm. */ 2714 yd = lon/3600000.; 2715 sprintf(Msg, "Lat = %c %11.7fdeg, Long = %c %11.7fdeg, Alt = %5.2fm (%5.2fft) GPS", ns, xd, ew, yd, hm, hft); 2716 record_clock_stats(&(instance->peer->srcadr), Msg); 2717 2718 idx = xd; 2719 idy = yd; 2720 imx = lat%3600000; 2721 imy = lon%3600000; 2722 xm = imx/60000.; 2723 ym = imy/60000.; 2724 sprintf(Msg, "Lat = %c %3ddeg %7.4fm, Long = %c %3ddeg %8.5fm, Alt = %7.2fm (%7.2fft) GPS", ns, idx, xm, ew, idy, ym, hm, hft); 2725 record_clock_stats(&(instance->peer->srcadr), Msg); 2726 2727 imx = xm; 2728 imy = ym; 2729 is = lat%60000; 2730 xs = is/1000.; 2731 is = lon%60000; 2732 ys = is/1000.; 2733 sprintf(Msg, "Lat = %c %3ddeg %2dm %5.2fs, Long = %c %3ddeg %2dm %5.2fs, Alt = %7.2fm (%7.2fft) GPS", ns, idx, imx, xs, ew, idy, imy, ys, hm, hft); 2734 record_clock_stats(&(instance->peer->srcadr), Msg); 2735 } 2736 2737 2738 2739 /* 2740 * get PPS Offset 2741 * Nb. @@Ay is not supported for early UT (no plus) model 2742 */ 2743 2744 static void 2745 oncore_msg_Ay( 2746 struct instance *instance, 2747 u_char *buf, 2748 size_t len 2749 ) 2750 { 2751 char Msg[120]; 2752 2753 if (!instance->printed || instance->Ay) 2754 return; 2755 2756 instance->Ay = 1; 2757 2758 instance->offset = buf_w32(&buf[4]); 2759 2760 sprintf(Msg, "PPS Offset is set to %ld ns", instance->offset); 2761 record_clock_stats(&(instance->peer->srcadr), Msg); 2762 } 2763 2764 2765 2766 /* 2767 * get Cable Delay 2768 */ 2769 2770 static void 2771 oncore_msg_Az( 2772 struct instance *instance, 2773 u_char *buf, 2774 size_t len 2775 ) 2776 { 2777 char Msg[120]; 2778 2779 if (!instance->printed || instance->Az) 2780 return; 2781 2782 instance->Az = 1; 2783 2784 instance->delay = buf_w32(&buf[4]); 2785 2786 sprintf(Msg, "Cable delay is set to %ld ns", instance->delay); 2787 record_clock_stats(&(instance->peer->srcadr), Msg); 2788 } 2789 2790 static void 2791 oncore_msg_Sz( 2792 struct instance *instance, 2793 u_char *buf, 2794 size_t len 2795 ) 2796 { 2797 const char *cp; 2798 2799 cp = "Oncore: System Failure at Power On"; 2800 if (instance && instance->peer) { 2801 record_clock_stats(&(instance->peer->srcadr), cp); 2802 oncore_shutdown(instance->unit, instance->peer); 2803 } 2804 } 2805 2806 #else 2807 int refclock_oncore_bs; 2808 #endif /* REFCLOCK */ 2809