1 /* $NetBSD: refclock_oncore.c,v 1.18 2024/08/18 20:47:18 christos Exp $ */ 2 3 /* 4 * ---------------------------------------------------------------------------- 5 * "THE BEER-WARE LICENSE" (Revision 42): 6 * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you 7 * can do whatever you want with this stuff. If we meet some day, and you think 8 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 9 * ---------------------------------------------------------------------------- 10 * 11 * refclock_oncore.c 12 * 13 * Driver for some of the various the Motorola Oncore GPS receivers. 14 * should work with Basic, PVT6, VP, UT, UT+, GT, GT+, SL, M12, M12+T 15 * The receivers with TRAIM (VP, UT, UT+, M12+T), will be more accurate 16 * than the others. 17 * The receivers without position hold (GT, GT+) will be less accurate. 18 * 19 * Tested with: 20 * 21 * (UT) (VP) 22 * COPYRIGHT 1991-1997 MOTOROLA INC. COPYRIGHT 1991-1996 MOTOROLA INC. 23 * SFTW P/N # 98-P36848P SFTW P/N # 98-P36830P 24 * SOFTWARE VER # 2 SOFTWARE VER # 8 25 * SOFTWARE REV # 2 SOFTWARE REV # 8 26 * SOFTWARE DATE APR 24 1998 SOFTWARE DATE 06 Aug 1996 27 * MODEL # R1121N1114 MODEL # B4121P1155 28 * HWDR P/N # 1 HDWR P/N # _ 29 * SERIAL # R0010A SERIAL # SSG0226478 30 * MANUFACTUR DATE 6H07 MANUFACTUR DATE 7E02 31 * OPTIONS LIST IB 32 * 33 * (Basic) (M12) 34 * COPYRIGHT 1991-1994 MOTOROLA INC. COPYRIGHT 1991-2000 MOTOROLA INC. 35 * SFTW P/N # 98-P39949M SFTW P/N # 61-G10002A 36 * SOFTWARE VER # 5 SOFTWARE VER # 1 37 * SOFTWARE REV # 0 SOFTWARE REV # 3 38 * SOFTWARE DATE 20 JAN 1994 SOFTWARE DATE Mar 13 2000 39 * MODEL # A11121P116 MODEL # P143T12NR1 40 * HDWR P/N # _ HWDR P/N # 1 41 * SERIAL # SSG0049809 SERIAL # P003UD 42 * MANUFACTUR DATE 417AMA199 MANUFACTUR DATE 0C27 43 * OPTIONS LIST AB 44 * 45 * (M12+T) (M12+T later version) 46 * COPYRIGHT 1991-2002 MOTOROLA INC. COPYRIGHT 1991-2003 MOTOROLA INC. 47 * SFTW P/N # 61-G10268A SFTW P/N # 61-G10268A 48 * SOFTWARE VER # 2 SOFTWARE VER # 2 49 * SOFTWARE REV # 0 SOFTWARE REV # 1 50 * SOFTWARE DATE AUG 14 2002 SOFTWARE DATE APR 16 2003 51 * MODEL # P283T12T11 MODEL # P273T12T12 52 * HWDR P/N # 2 HWDR P/N # 2 53 * SERIAL # P04DC2 SERIAL # P05Z7Z 54 * MANUFACTUR DATE 2J17 MANUFACTUR DATE 3G15 55 * 56 * -------------------------------------------------------------------------- 57 * Reg Clemens (June 2009) 58 * BUG[1220] OK, big patch, but mostly done mechanically. Change direct calls to write 59 * to clockstats to a call to oncore_log, which now calls the old routine plus msyslog. 60 * Have to set the LOG_LEVELS of the calls for msyslog, and this was done by hand. New 61 * routine oncore_log. 62 * -------------------------------------------------------------------------- 63 * Reg Clemens (June 2009) 64 * BUG[1218] The comment on where the oncore driver gets its input file does not 65 * agree with the code. Change the comment. 66 * -------------------------------------------------------------------------- 67 * Reg Clemens (June 2009) 68 * change exit statements to return(0) in main program. I had assumed that if the 69 * PPS driver did not start for some reason, we shuould stop NTPD itelf. Others 70 * disagree. We now give an ERR log message and stop this driver. 71 * -------------------------------------------------------------------------- 72 * Reg Clemens (June 2009) 73 * A bytes available message for the input subsystem (Debug message). 74 * -------------------------------------------------------------------------- 75 * Reg Clemens (Nov 2008) 76 * This code adds a message for TRAIM messages. Users often worry about the 77 * driver not starting up, and it is often because of signal strength being low. 78 * Low signal strength will give TRAIM messages. 79 * -------------------------------------------------------------------------- 80 * Reg Clemens (Nov 2008) 81 * Add waiting on Almanac Message. 82 * -------------------------------------------------------------------------- 83 * Reg Clemens (Nov 2008) 84 * Add back in @@Bl code to do the @@Bj/@@Gj that is in later ONCOREs 85 * LEAP SECONDS: All of the ONCORE receivers, VP -> M12T have the @@Bj command 86 * that says 'Leap Pending'. As documented it only becomes true in the month 87 * before the leap second is to be applied, but in practice at least some of 88 * the receivers turn this indicator on as soon as the message is posted, which 89 * can be 6months early. As such, we use the Bj command to turn on the 90 * instance->pp->leap indicator but only run this test in December and June for 91 * updates on 1Jan and 1July. 92 * 93 * The @@Gj command exists in later ONCOREs, and it gives the exact date 94 * and size of the Leap Update. It can be emulated in the VP using the @@Bl 95 * command which reads the raw Satellite Broadcast Messages. 96 * We use these two commands to print informative messages in the clockstats 97 * file once per day as soon as the message appears on the satellites. 98 * -------------------------------------------------------------------------- 99 * Reg Clemens (Feb 2006) 100 * Fix some gcc4 compiler complaints 101 * Fix possible segfault in oncore_init_shmem 102 * change all (possible) fprintf(stderr, to record_clock_stats 103 * Apply patch from Russell J. Yount <rjy@cmu.edu> Fixed (new) MT12+T UTC not correct 104 * immediately after new Almanac Read. 105 * Apply patch for new PPS implementation by Rodolfo Giometti <giometti@linux.it> 106 * now code can use old Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de> or 107 * the new one. Compiles depending on timepps.h seen. 108 * -------------------------------------------------------------------------- 109 * Luis Batanero Guerrero <luisba@rao.es> (Dec 2005) Patch for leap seconds 110 * (the oncore driver was setting the wrong ntpd variable) 111 * -------------------------------------------------------------------------- 112 * Reg.Clemens (Mar 2004) 113 * Support for interfaces other than PPSAPI removed, for Solaris, SunOS, 114 * SCO, you now need to use one of the timepps.h files in the root dir. 115 * this driver will 'grab' it for you if you dont have one in /usr/include 116 * -------------------------------------------------------------------------- 117 * This code uses the two devices 118 * /dev/oncore.serial.n 119 * /dev/oncore.pps.n 120 * which may be linked to the same device. 121 * and can read initialization data from the file 122 * /etc/ntp.oncoreN, /etc/ntp.oncore.N, or /etc/ntp.oncore, where 123 * n or N are the unit number, viz 127.127.30.N. 124 * -------------------------------------------------------------------------- 125 * Reg.Clemens <reg@dwf.com> Sep98. 126 * Original code written for FreeBSD. 127 * With these mods it works on FreeBSD, SunOS, Solaris and Linux 128 * (SunOS 4.1.3 + ppsclock) 129 * (Solaris7 + MU4) 130 * (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + or later). 131 * 132 * Lat,Long,Ht, cable-delay, offset, and the ReceiverID (along with the 133 * state machine state) are printed to CLOCKSTATS if that file is enabled 134 * in /etc/ntp.conf. 135 * 136 * -------------------------------------------------------------------------- 137 * 138 * According to the ONCORE manual (TRM0003, Rev 3.2, June 1998, page 3.13) 139 * doing an average of 10000 valid 2D and 3D fixes is what the automatic 140 * site survey mode does. Looking at the output from the receiver 141 * it seems like it is only using 3D fixes. 142 * When we do it ourselves, take 10000 3D fixes. 143 */ 144 145 #define POS_HOLD_AVERAGE 10000 /* nb, 10000s ~= 2h45m */ 146 147 /* 148 * ONCORE_SHMEM_STATUS will create a mmap(2)'ed file named according to a 149 * "STATUS" line in the oncore config file, which contains the most recent 150 * copy of all types of messages we recognize. This file can be mmap(2)'ed 151 * by monitoring and statistics programs. 152 * 153 * See separate HTML documentation for this option. 154 */ 155 156 #ifdef HAVE_CONFIG_H 157 #include <config.h> 158 #endif 159 160 #if defined(REFCLOCK) && defined(CLOCK_ONCORE) 161 162 #include "ntpd.h" 163 #include "ntp_io.h" 164 #include "ntp_unixtime.h" 165 #include "ntp_refclock.h" 166 #include "ntp_calendar.h" 167 #include "ntp_calgps.h" 168 #include "ntp_stdlib.h" 169 170 #include <stdio.h> 171 #include <stdarg.h> 172 #include <ctype.h> 173 #include <sys/stat.h> 174 #ifdef ONCORE_SHMEM_STATUS 175 # ifdef HAVE_SYS_MMAN_H 176 # include <sys/mman.h> 177 # ifndef MAP_FAILED 178 # define MAP_FAILED ((u_char *) -1) 179 # endif /* MAP_FAILED */ 180 # endif /* HAVE_SYS_MMAN_H */ 181 #endif /* ONCORE_SHMEM_STATUS */ 182 183 #ifdef HAVE_PPSAPI 184 # include "ppsapi_timepps.h" 185 #endif 186 187 struct Bl { 188 int dt_ls; 189 int dt_lsf; 190 int WN; 191 int DN; 192 int WN_lsf; 193 int DN_lsf; 194 int wn_flg; 195 int lsf_flg; 196 int Bl_day; 197 } Bl; 198 199 enum receive_state { 200 ONCORE_NO_IDEA, 201 ONCORE_CHECK_ID, 202 ONCORE_CHECK_CHAN, 203 ONCORE_HAVE_CHAN, 204 ONCORE_RESET_SENT, 205 ONCORE_TEST_SENT, 206 ONCORE_INIT, 207 ONCORE_ALMANAC, 208 ONCORE_RUN 209 }; 210 211 enum site_survey_state { 212 ONCORE_SS_UNKNOWN, 213 ONCORE_SS_TESTING, 214 ONCORE_SS_HW, 215 ONCORE_SS_SW, 216 ONCORE_SS_DONE 217 }; 218 219 enum antenna_state { 220 ONCORE_ANTENNA_UNKNOWN = -1, 221 ONCORE_ANTENNA_OK = 0, 222 ONCORE_ANTENNA_OC = 1, 223 ONCORE_ANTENNA_UC = 2, 224 ONCORE_ANTENNA_NV = 3 225 }; 226 227 /* Model Name, derived from the @@Cj message. 228 * Used to initialize some variables. 229 */ 230 231 enum oncore_model { 232 ONCORE_BASIC, 233 ONCORE_PVT6, 234 ONCORE_VP, 235 ONCORE_UT, 236 ONCORE_UTPLUS, 237 ONCORE_GT, 238 ONCORE_GTPLUS, 239 ONCORE_SL, 240 ONCORE_M12, 241 ONCORE_UNKNOWN 242 }; 243 244 /* the bits that describe these properties are in the same place 245 * on the VP/UT, but have moved on the M12. As such we extract 246 * them, and use them from this struct. 247 * 248 */ 249 250 struct RSM { 251 u_char posn0D; 252 u_char posn2D; 253 u_char posn3D; 254 u_char bad_almanac; 255 u_char bad_fix; 256 }; 257 258 /* It is possible to test the VP/UT each cycle (@@Ea or equivalent) to 259 * see what mode it is in. The bits on the M12 are multiplexed with 260 * other messages, so we have to 'keep' the last known mode here. 261 */ 262 263 enum posn_mode { 264 MODE_UNKNOWN, 265 MODE_0D, 266 MODE_2D, 267 MODE_3D 268 }; 269 270 struct instance { 271 int unit; /* 127.127.30.unit */ 272 struct refclockproc *pp; 273 struct peer *peer; 274 275 int ttyfd; /* TTY file descriptor */ 276 int ppsfd; /* PPS file descriptor */ 277 int shmemfd; /* Status shm descriptor */ 278 pps_handle_t pps_h; 279 pps_params_t pps_p; 280 enum receive_state o_state; /* Receive state */ 281 enum posn_mode mode; /* 0D, 2D, 3D */ 282 enum site_survey_state site_survey; /* Site Survey state */ 283 enum antenna_state ant_state; /* antenna state */ 284 285 int Bj_day; 286 287 u_long delay; /* ns */ 288 long offset; /* ns */ 289 290 u_char *shmem; 291 char *shmem_fname; 292 u_int shmem_Cb; 293 u_int shmem_Ba; 294 u_int shmem_Ea; 295 u_int shmem_Ha; 296 u_char shmem_reset; 297 u_char shmem_Posn; 298 u_char shmem_bad_Ea; 299 u_char almanac_from_shmem; 300 301 double ss_lat; 302 double ss_long; 303 double ss_ht; 304 double dH; 305 int ss_count; 306 u_char posn_set; 307 308 enum oncore_model model; 309 u_int version; 310 u_int revision; 311 312 u_char chan; /* 6 for PVT6 or BASIC, 8 for UT/VP, 12 for m12, 0 if unknown */ 313 s_char traim; /* do we have traim? yes UT/VP, M12+T, no BASIC, GT, M12, -1 unknown, 0 no, +1 yes */ 314 /* the following 7 are all timing counters */ 315 u_char traim_delay; /* seconds counter, waiting for reply */ 316 u_char count; /* cycles thru Ea before starting */ 317 u_char count1; /* cycles thru Ea after SS_TESTING, waiting for SS_HW */ 318 u_char count2; /* cycles thru Ea after count, to check for @@Ea */ 319 u_char count3; /* cycles thru Ea checking for # channels */ 320 u_char count4; /* cycles thru leap after Gj to issue Bj */ 321 u_char count5; /* cycles thru get_timestamp waiting for valid UTC correction */ 322 u_char count5_set; /* only set count5 once */ 323 u_char counta; /* count for waiting on almanac message */ 324 u_char pollcnt; 325 u_char timeout; /* count to retry Cj after Fa self-test */ 326 u_char max_len; /* max length message seen by oncore_log, for debugging */ 327 u_char max_count; /* count for message statistics */ 328 329 struct RSM rsm; /* bits extracted from Receiver Status Msg in @@Ea */ 330 struct Bl Bl; /* Satellite Broadcast Data Message */ 331 u_char printed; 332 u_char polled; 333 u_long ev_serial; 334 unsigned Rcvptr; 335 u_char Rcvbuf[500]; 336 u_char BEHa[160]; /* Ba, Ea or Ha */ 337 u_char BEHn[80]; /* Bn , En , or Hn */ 338 u_char Cj[300]; 339 u_char Ag; /* Satellite mask angle */ 340 u_char saw_At; 341 u_char saw_Ay; 342 u_char saw_Az; 343 s_char saw_Bj; 344 s_char saw_Gj; 345 u_char have_dH; 346 u_char init_type; 347 s_char saw_tooth; 348 s_char chan_in; /* chan number from INPUT, will always use it */ 349 u_char chan_id; /* chan number determined from part number */ 350 u_char chan_ck; /* chan number determined by sending commands to hardware */ 351 s_char traim_in; /* TRAIM from INPUT, will always use ON/OFF specified */ 352 s_char traim_id; /* TRAIM determined from part number */ 353 u_char traim_ck; /* TRAIM determined by sending commands to hardware */ 354 u_char once; /* one pass code at top of BaEaHa */ 355 s_char assert; 356 u_char hardpps; 357 s_char pps_control; /* PPS control, M12 only */ 358 s_char pps_control_msg_seen; 359 }; 360 361 #define rcvbuf instance->Rcvbuf 362 #define rcvptr instance->Rcvptr 363 364 static int oncore_start (int, struct peer *); 365 static void oncore_poll (int, struct peer *); 366 static void oncore_shutdown (int, struct peer *); 367 static void oncore_consume (struct instance *); 368 static void oncore_read_config (struct instance *); 369 static void oncore_receive (struct recvbuf *); 370 static int oncore_ppsapi (struct instance *); 371 static void oncore_get_timestamp (struct instance *, long, long); 372 static void oncore_init_shmem (struct instance *); 373 374 static void oncore_antenna_report (struct instance *, enum antenna_state); 375 static void oncore_chan_test (struct instance *); 376 static void oncore_check_almanac (struct instance *); 377 static void oncore_check_antenna (struct instance *); 378 static void oncore_check_leap_sec (struct instance *); 379 static int oncore_checksum_ok (u_char *, int); 380 static void oncore_compute_dH (struct instance *); 381 static void oncore_load_almanac (struct instance *); 382 static void oncore_log (struct instance *, int, const char *); 383 static int oncore_log_f (struct instance *, int, const char *, ...) 384 NTP_SYSLOG(3, 4); 385 static void oncore_print_Cb (struct instance *, u_char *); 386 /* static void oncore_print_array (u_char *, int); */ 387 static void oncore_print_posn (struct instance *); 388 static void oncore_sendmsg (struct instance *, u_char *, size_t); 389 static void oncore_set_posn (struct instance *); 390 static void oncore_set_traim (struct instance *); 391 static void oncore_shmem_get_3D (struct instance *); 392 static void oncore_ss (struct instance *); 393 static int oncore_wait_almanac (struct instance *); 394 static void oncore_feed_clockproc (struct instance *); 395 396 static void oncore_msg_any (struct instance *, u_char *, size_t, int); 397 static void oncore_msg_Adef (struct instance *, u_char *, size_t); 398 static void oncore_msg_Ag (struct instance *, u_char *, size_t); 399 static void oncore_msg_As (struct instance *, u_char *, size_t); 400 static void oncore_msg_At (struct instance *, u_char *, size_t); 401 static void oncore_msg_Ay (struct instance *, u_char *, size_t); 402 static void oncore_msg_Az (struct instance *, u_char *, size_t); 403 static void oncore_msg_BaEaHa (struct instance *, u_char *, size_t); 404 static void oncore_msg_Bd (struct instance *, u_char *, size_t); 405 static void oncore_msg_Bj (struct instance *, u_char *, size_t); 406 static void oncore_msg_Bl (struct instance *, u_char *, size_t); 407 static void oncore_msg_BnEnHn (struct instance *, u_char *, size_t); 408 static void oncore_msg_CaFaIa (struct instance *, u_char *, size_t); 409 static void oncore_msg_Cb (struct instance *, u_char *, size_t); 410 static void oncore_msg_Cf (struct instance *, u_char *, size_t); 411 static void oncore_msg_Cj (struct instance *, u_char *, size_t); 412 static void oncore_msg_Cj_id (struct instance *, u_char *, size_t); 413 static void oncore_msg_Cj_init (struct instance *, u_char *, size_t); 414 static void oncore_msg_Ga (struct instance *, u_char *, size_t); 415 static void oncore_msg_Gb (struct instance *, u_char *, size_t); 416 static void oncore_msg_Gc (struct instance *, u_char *, size_t); 417 static void oncore_msg_Gj (struct instance *, u_char *, size_t); 418 static void oncore_msg_Sz (struct instance *, u_char *, size_t); 419 420 struct refclock refclock_oncore = { 421 oncore_start, /* start up driver */ 422 oncore_shutdown, /* shut down driver */ 423 oncore_poll, /* transmit poll message */ 424 noentry, /* not used */ 425 noentry, /* not used */ 426 noentry, /* not used */ 427 NOFLAGS /* not used */ 428 }; 429 430 /* 431 * Understanding the next bit here is not easy unless you have a manual 432 * for the the various Oncore Models. 433 */ 434 435 static struct msg_desc { 436 const char flag[3]; 437 const int len; 438 void (*handler) (struct instance *, u_char *, size_t); 439 const char *fmt; 440 int shmem; 441 } oncore_messages[] = { 442 /* Ea and En first since they're most common */ 443 { "Ea", 76, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC", 0 }, 444 { "Ba", 68, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC", 0 }, 445 { "Ha", 154, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC", 0 }, 446 { "Bn", 59, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC", 0 }, 447 { "En", 69, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC", 0 }, 448 { "Hn", 78, oncore_msg_BnEnHn, "", 0 }, 449 { "Ab", 10, 0, "", 0 }, 450 { "Ac", 11, 0, "", 0 }, 451 { "Ad", 11, oncore_msg_Adef, "", 0 }, 452 { "Ae", 11, oncore_msg_Adef, "", 0 }, 453 { "Af", 15, oncore_msg_Adef, "", 0 }, 454 { "Ag", 8, oncore_msg_Ag, "", 0 }, /* Satellite mask angle */ 455 { "As", 20, oncore_msg_As, "", 0 }, 456 { "At", 8, oncore_msg_At, "", 0 }, 457 { "Au", 12, 0, "", 0 }, 458 { "Av", 8, 0, "", 0 }, 459 { "Aw", 8, 0, "", 0 }, 460 { "Ay", 11, oncore_msg_Ay, "", 0 }, 461 { "Az", 11, oncore_msg_Az, "", 0 }, 462 { "AB", 8, 0, "", 0 }, 463 { "Bb", 92, 0, "", 0 }, 464 { "Bd", 23, oncore_msg_Bd, "", 0 }, 465 { "Bj", 8, oncore_msg_Bj, "", 0 }, 466 { "Bl", 41, oncore_msg_Bl, "", 0 }, 467 { "Ca", 9, oncore_msg_CaFaIa, "", 0 }, 468 { "Cb", 33, oncore_msg_Cb, "", 0 }, 469 { "Cf", 7, oncore_msg_Cf, "", 0 }, 470 { "Cg", 8, 0, "", 0 }, 471 { "Ch", 9, 0, "", 0 }, 472 { "Cj", 294, oncore_msg_Cj, "", 0 }, 473 { "Ek", 71, 0, "", 0 }, 474 { "Fa", 9, oncore_msg_CaFaIa, "", 0 }, 475 { "Ga", 20, oncore_msg_Ga, "", 0 }, 476 { "Gb", 17, oncore_msg_Gb, "", 0 }, 477 { "Gc", 8, oncore_msg_Gc, "", 0 }, 478 { "Gd", 8, 0, "", 0 }, 479 { "Ge", 8, 0, "", 0 }, 480 { "Gj", 21, oncore_msg_Gj, "", 0 }, 481 { "Ia", 10, oncore_msg_CaFaIa, "", 0 }, 482 { "Sz", 8, oncore_msg_Sz, "", 0 }, 483 { {0}, 7, 0, "", 0 } 484 }; 485 486 487 static u_char oncore_cmd_Aa[] = { 'A', 'a', 0, 0, 0 }; /* 6/8 Time of Day */ 488 static u_char oncore_cmd_Ab[] = { 'A', 'b', 0, 0, 0 }; /* 6/8 GMT Correction */ 489 static u_char oncore_cmd_AB[] = { 'A', 'B', 4 }; /* VP Application Type: Static */ 490 static u_char oncore_cmd_Ac[] = { 'A', 'c', 0, 0, 0, 0 }; /* 6/8 Date */ 491 static u_char oncore_cmd_Ad[] = { 'A', 'd', 0,0,0,0 }; /* 6/8 Latitude */ 492 static u_char oncore_cmd_Ae[] = { 'A', 'e', 0,0,0,0 }; /* 6/8 Longitude */ 493 static u_char oncore_cmd_Af[] = { 'A', 'f', 0,0,0,0, 0 }; /* 6/8 Height */ 494 static u_char oncore_cmd_Ag[] = { 'A', 'g', 0 }; /* 6/8/12 Satellite Mask Angle */ 495 static u_char oncore_cmd_Agx[] = { 'A', 'g', 0xff }; /* 6/8/12 Satellite Mask Angle: read */ 496 static u_char oncore_cmd_As[] = { 'A', 's', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; /* 6/8/12 Posn Hold Parameters */ 497 static u_char oncore_cmd_Asx[] = { 'A', 's', 0x7f,0xff,0xff,0xff, /* 6/8/12 Posn Hold Readback */ 498 0x7f,0xff,0xff,0xff, /* on UT+ this doesnt work with 0xff */ 499 0x7f,0xff,0xff,0xff, 0xff }; /* but does work with 0x7f (sigh). */ 500 static u_char oncore_cmd_At0[] = { 'A', 't', 0 }; /* 6/8 Posn Hold: off */ 501 static u_char oncore_cmd_At1[] = { 'A', 't', 1 }; /* 6/8 Posn Hold: on */ 502 static u_char oncore_cmd_At2[] = { 'A', 't', 2 }; /* 6/8 Posn Hold: Start Site Survey */ 503 static u_char oncore_cmd_Atx[] = { 'A', 't', 0xff }; /* 6/8 Posn Hold: Read Back */ 504 static u_char oncore_cmd_Au[] = { 'A', 'u', 0,0,0,0, 0 }; /* GT/M12 Altitude Hold Ht. */ 505 static u_char oncore_cmd_Av0[] = { 'A', 'v', 0 }; /* VP/GT Altitude Hold: off */ 506 static u_char oncore_cmd_Av1[] = { 'A', 'v', 1 }; /* VP/GT Altitude Hold: on */ 507 static u_char oncore_cmd_Aw[] = { 'A', 'w', 1 }; /* 6/8/12 UTC/GPS time selection */ 508 static u_char oncore_cmd_Ay[] = { 'A', 'y', 0, 0, 0, 0 }; /* Timing 1PPS time offset: set */ 509 static u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff }; /* Timing 1PPS time offset: Read */ 510 static u_char oncore_cmd_Az[] = { 'A', 'z', 0, 0, 0, 0 }; /* 6/8UT/12 1PPS Cable Delay: set */ 511 static u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff }; /* 6/8UT/12 1PPS Cable Delay: Read */ 512 static u_char oncore_cmd_Ba0[] = { 'B', 'a', 0 }; /* 6 Position/Data/Status: off */ 513 static u_char oncore_cmd_Ba[] = { 'B', 'a', 1 }; /* 6 Position/Data/Status: on */ 514 static u_char oncore_cmd_Bb[] = { 'B', 'b', 1 }; /* 6/8/12 Visible Satellites */ 515 static u_char oncore_cmd_Bd[] = { 'B', 'd', 1 }; /* 6/8/12? Almanac Status Msg. */ 516 static u_char oncore_cmd_Be[] = { 'B', 'e', 1 }; /* 6/8/12 Request Almanac Data */ 517 static u_char oncore_cmd_Bj[] = { 'B', 'j', 0 }; /* 6/8 Leap Second Pending */ 518 static u_char oncore_cmd_Bl[] = { 'B', 'l', 1 }; /* VP Satellite Broadcast Data Msg */ 519 static u_char oncore_cmd_Bn0[] = { 'B', 'n', 0, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6 TRAIM setup/status: msg off, traim on */ 520 static u_char oncore_cmd_Bn[] = { 'B', 'n', 1, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6 TRAIM setup/status: msg on, traim on */ 521 static u_char oncore_cmd_Bnx[] = { 'B', 'n', 0, 0, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6 TRAIM setup/status: msg off, traim off */ 522 static u_char oncore_cmd_Ca[] = { 'C', 'a' }; /* 6 Self Test */ 523 static u_char oncore_cmd_Cf[] = { 'C', 'f' }; /* 6/8/12 Set to Defaults */ 524 static u_char oncore_cmd_Cg[] = { 'C', 'g', 1 }; /* VP Posn Fix/Idle Mode */ 525 static u_char oncore_cmd_Cj[] = { 'C', 'j' }; /* 6/8/12 Receiver ID */ 526 static u_char oncore_cmd_Ea0[] = { 'E', 'a', 0 }; /* 8 Position/Data/Status: off */ 527 static u_char oncore_cmd_Ea[] = { 'E', 'a', 1 }; /* 8 Position/Data/Status: on */ 528 static u_char oncore_cmd_Ek[] = { 'E', 'k', 0 }; /* just turn off */ /* 8 Posn/Status/Data - extension */ 529 static u_char oncore_cmd_En0[] = { 'E', 'n', 0, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT TRAIM setup/status: msg off, traim on */ 530 static u_char oncore_cmd_En[] = { 'E', 'n', 1, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT TRAIM setup/status: msg on, traim on */ 531 static u_char oncore_cmd_Enx[] = { 'E', 'n', 0, 0, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT TRAIM setup/status: msg off, traim off */ 532 static u_char oncore_cmd_Fa[] = { 'F', 'a' }; /* 8 Self Test */ 533 static u_char oncore_cmd_Ga[] = { 'G', 'a', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; /* 12 Position Set */ 534 static u_char oncore_cmd_Gax[] = { 'G', 'a', 0xff, 0xff, 0xff, 0xff, /* 12 Position Set: Read */ 535 0xff, 0xff, 0xff, 0xff, /* */ 536 0xff, 0xff, 0xff, 0xff, 0xff }; /* */ 537 static u_char oncore_cmd_Gb[] = { 'G', 'b', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* 12 set Date/Time */ 538 static u_char oncore_cmd_Gc[] = { 'G', 'c', 0 }; /* 12 PPS Control: Off, On, 1+satellite,TRAIM */ 539 static u_char oncore_cmd_Gd0[] = { 'G', 'd', 0 }; /* 12 Position Control: 3D (no hold) */ 540 static u_char oncore_cmd_Gd1[] = { 'G', 'd', 1 }; /* 12 Position Control: 0D (3D hold) */ 541 static u_char oncore_cmd_Gd2[] = { 'G', 'd', 2 }; /* 12 Position Control: 2D (Alt Hold) */ 542 static u_char oncore_cmd_Gd3[] = { 'G', 'd', 3 }; /* 12 Position Coltrol: Start Site Survey */ 543 static u_char oncore_cmd_Ge0[] = { 'G', 'e', 0 }; /* M12+T TRAIM: off */ 544 static u_char oncore_cmd_Ge[] = { 'G', 'e', 1 }; /* M12+T TRAIM: on */ 545 static u_char oncore_cmd_Gj[] = { 'G', 'j' }; /* 8?/12 Leap Second Pending */ 546 static u_char oncore_cmd_Ha0[] = { 'H', 'a', 0 }; /* 12 Position/Data/Status: off */ 547 static u_char oncore_cmd_Ha[] = { 'H', 'a', 1 }; /* 12 Position/Data/Status: on */ 548 static u_char oncore_cmd_Hn0[] = { 'H', 'n', 0 }; /* 12 TRAIM Status: off */ 549 static u_char oncore_cmd_Hn[] = { 'H', 'n', 1 }; /* 12 TRAIM Status: on */ 550 static u_char oncore_cmd_Ia[] = { 'I', 'a' }; /* 12 Self Test */ 551 552 /* it appears that as of 1997/1998, the UT had As,At, but not Au,Av 553 * the GT had Au,Av, but not As,At 554 * This was as of v2.0 of both firmware sets. possibly 1.3 for UT. 555 * Bj in UT at v1.3 556 * dont see Bd in UT/GT thru 1999 557 * Gj in UT as of 3.0, 1999 , Bj as of 1.3 558 */ 559 560 #define DEVICE1 "/dev/oncore.serial.%d" /* name of serial device */ 561 #define DEVICE2 "/dev/oncore.pps.%d" /* name of pps device */ 562 563 #define SPEED B9600 /* Oncore Binary speed (9600 bps) */ 564 565 /* 566 * Assemble and disassemble 32bit signed quantities from a buffer. 567 * 568 */ 569 570 /* to buffer, int w, u_char *buf */ 571 #define w32_buf(buf,w) { u_int i_tmp; \ 572 i_tmp = (w<0) ? (~(-w)+1) : (w); \ 573 (buf)[0] = (i_tmp >> 24) & 0xff; \ 574 (buf)[1] = (i_tmp >> 16) & 0xff; \ 575 (buf)[2] = (i_tmp >> 8) & 0xff; \ 576 (buf)[3] = (i_tmp ) & 0xff; \ 577 } 578 579 #define w32(buf) (((buf)[0]&0xff) << 24 | \ 580 ((buf)[1]&0xff) << 16 | \ 581 ((buf)[2]&0xff) << 8 | \ 582 ((buf)[3]&0xff) ) 583 584 /* from buffer, char *buf, result to an int */ 585 #define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf)) 586 587 588 /* 589 * oncore_start - initialize data for processing 590 */ 591 592 static int 593 oncore_start( 594 int unit, 595 struct peer *peer 596 ) 597 { 598 #define STRING_LEN 32 599 register struct instance *instance; 600 struct refclockproc *pp; 601 int fd1, fd2; 602 char device1[STRING_LEN], device2[STRING_LEN]; 603 #ifndef SYS_WINNT 604 struct stat stat1, stat2; 605 #endif 606 607 /* create instance structure for this unit */ 608 609 instance = emalloc(sizeof(*instance)); 610 memset(instance, 0, sizeof(*instance)); 611 612 /* initialize miscellaneous variables */ 613 614 pp = peer->procptr; 615 instance->pp = pp; 616 instance->unit = unit; 617 instance->peer = peer; 618 instance->assert = 1; 619 instance->once = 1; 620 621 instance->Bj_day = -1; 622 instance->traim = -1; 623 instance->traim_in = -1; 624 instance->chan_in = -1; 625 instance->pps_control = -1; /* PPS control, M12 only */ 626 instance->pps_control_msg_seen = -1; /* Have seen response to Gc msg */ 627 instance->model = ONCORE_UNKNOWN; 628 instance->mode = MODE_UNKNOWN; 629 instance->site_survey = ONCORE_SS_UNKNOWN; 630 instance->Ag = 0xff; /* Satellite mask angle, unset by user */ 631 instance->ant_state = ONCORE_ANTENNA_UNKNOWN; 632 633 peer->flags &= ~FLAG_PPS; /* PPS not active yet */ 634 peer->precision = -26; 635 peer->minpoll = 4; 636 peer->maxpoll = 4; 637 pp->clockdesc = "Motorola Oncore GPS Receiver"; 638 memcpy((char *)&pp->refid, "GPS\0", (size_t) 4); 639 640 oncore_log(instance, LOG_NOTICE, "ONCORE DRIVER -- CONFIGURING"); 641 instance->o_state = ONCORE_NO_IDEA; 642 oncore_log(instance, LOG_NOTICE, "state = ONCORE_NO_IDEA"); 643 644 /* Now open files. 645 * This is a bit complicated, a we dont want to open the same file twice 646 * (its a problem on some OS), and device2 may not exist for the new PPS 647 */ 648 649 (void)snprintf(device1, sizeof(device1), DEVICE1, unit); 650 (void)snprintf(device2, sizeof(device2), DEVICE2, unit); 651 652 /* OPEN DEVICES */ 653 /* opening different devices for fd1 and fd2 presents no problems */ 654 /* opening the SAME device twice, seems to be OS dependent. 655 (a) on Linux (no streams) no problem 656 (b) on SunOS (and possibly Solaris, untested), (streams) 657 never see the line discipline. 658 Since things ALWAYS work if we only open the device once, we check 659 to see if the two devices are in fact the same, then proceed to 660 do one open or two. 661 662 For use with linuxPPS we assume that the N_TTY file has been opened 663 and that the line discipline has been changed to N_PPS by another 664 program (say ppsldisc) so that the two files expected by the oncore 665 driver can be opened. 666 667 Note that the linuxPPS N_PPS file is just like a N_TTY, so we can do 668 the stat below without error even though the file has already had its 669 line discipline changed by another process. 670 671 The Windows port of ntpd arranges to return duplicate handles for 672 multiple opens of the same serial device, and doesn't have inodes 673 for serial handles, so we just open both on Windows. 674 */ 675 #ifndef SYS_WINNT 676 if (stat(device1, &stat1)) { 677 oncore_log_f(instance, LOG_ERR, "Can't stat fd1 (%s)", 678 device1); 679 return(0); /* exit, no file, can't start driver */ 680 } 681 682 if (stat(device2, &stat2)) { 683 stat2.st_dev = stat2.st_ino = -2; 684 oncore_log_f(instance, LOG_ERR, "Can't stat fd2 (%s) %d %m", 685 device2, errno); 686 } 687 #endif /* !SYS_WINNT */ 688 689 fd1 = refclock_open(&peer->srcadr, device1, SPEED, LDISC_RAW); 690 if (fd1 <= 0) { 691 oncore_log_f(instance, LOG_ERR, "Can't open fd1 (%s)", 692 device1); 693 return(0); /* exit, can't open file, can't start driver */ 694 } 695 696 /* for LINUX the PPS device is the result of a line discipline. 697 It seems simplest to let an external program create the appropriate 698 /dev/pps<n> file, and only check (carefully) for its existance here 699 */ 700 701 #ifndef SYS_WINNT 702 if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino)) /* same device here */ 703 fd2 = fd1; 704 else 705 #endif /* !SYS_WINNT */ 706 { /* different devices here */ 707 if ((fd2=tty_open(device2, O_RDWR, 0777)) < 0) { 708 oncore_log_f(instance, LOG_ERR, 709 "Can't open fd2 (%s)", device2); 710 return(0); /* exit, can't open PPS file, can't start driver */ 711 } 712 } 713 714 /* open ppsapi source */ 715 716 if (time_pps_create(fd2, &instance->pps_h) < 0) { 717 oncore_log(instance, LOG_ERR, "exit, PPSAPI not found in kernel"); 718 return(0); /* exit, don't find PPSAPI in kernel */ 719 } 720 721 /* continue initialization */ 722 723 instance->ttyfd = fd1; 724 instance->ppsfd = fd2; 725 726 /* go read any input data in /etc/ntp.oncoreX or /etc/ntp/oncore.X */ 727 728 oncore_read_config(instance); 729 730 if (!oncore_ppsapi(instance)) 731 return(0); 732 733 pp->io.clock_recv = oncore_receive; 734 pp->io.srcclock = peer; 735 pp->io.datalen = 0; 736 pp->io.fd = fd1; 737 if (!io_addclock(&pp->io)) { 738 oncore_log(instance, LOG_ERR, "can't do io_addclock"); 739 close(fd1); 740 pp->io.fd = -1; 741 free(instance); 742 return (0); 743 } 744 pp->unitptr = instance; 745 746 #ifdef ONCORE_SHMEM_STATUS 747 /* 748 * Before starting ONCORE, lets setup SHMEM 749 * This will include merging an old SHMEM into the new one if 750 * an old one is found. 751 */ 752 753 oncore_init_shmem(instance); 754 #endif 755 756 /* 757 * This will return the Model of the Oncore receiver. 758 * and start the Initialization loop in oncore_msg_Cj. 759 */ 760 761 instance->o_state = ONCORE_CHECK_ID; 762 oncore_log(instance, LOG_NOTICE, "state = ONCORE_CHECK_ID"); 763 764 instance->timeout = 4; 765 oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Set Posn Fix mode (not Idle (VP)) */ 766 oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 767 768 instance->pollcnt = 2; 769 return (1); 770 } 771 772 773 /* 774 * oncore_shutdown - shut down the clock 775 */ 776 777 static void 778 oncore_shutdown( 779 int unit, 780 struct peer *peer 781 ) 782 { 783 register struct instance *instance; 784 struct refclockproc *pp; 785 786 pp = peer->procptr; 787 instance = pp->unitptr; 788 789 if (pp->io.fd != -1) 790 io_closeclock(&pp->io); 791 792 if (instance != NULL) { 793 time_pps_destroy (instance->pps_h); 794 795 close(instance->ttyfd); 796 797 if ((instance->ppsfd != -1) && (instance->ppsfd != instance->ttyfd)) 798 close(instance->ppsfd); 799 800 if (instance->shmemfd) 801 close(instance->shmemfd); 802 803 free(instance); 804 } 805 } 806 807 808 809 /* 810 * oncore_poll - called by the transmit procedure 811 */ 812 813 static void 814 oncore_poll( 815 int unit, 816 struct peer *peer 817 ) 818 { 819 struct instance *instance; 820 821 instance = peer->procptr->unitptr; 822 if (instance->timeout) { 823 instance->timeout--; 824 if (instance->timeout == 0) { 825 oncore_log(instance, LOG_ERR, 826 "Oncore: No response from @@Cj, shutting down driver"); 827 oncore_shutdown(unit, peer); 828 } else { 829 oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 830 oncore_log(instance, LOG_WARNING, "Oncore: Resend @@Cj"); 831 } 832 return; 833 } 834 835 if (!instance->pollcnt) 836 refclock_report(peer, CEVNT_TIMEOUT); 837 else 838 instance->pollcnt--; 839 peer->procptr->polls++; 840 instance->polled = 1; 841 } 842 843 844 845 /* 846 * Initialize PPSAPI 847 */ 848 849 static int 850 oncore_ppsapi( 851 struct instance *instance 852 ) 853 { 854 int cap, mode, mode1; 855 const char *cp; 856 857 if (time_pps_getcap(instance->pps_h, &cap) < 0) { 858 oncore_log_f(instance, LOG_ERR, "time_pps_getcap failed: %m"); 859 return (0); 860 } 861 862 if (time_pps_getparams(instance->pps_h, &instance->pps_p) < 0) { 863 oncore_log_f(instance, LOG_ERR, "time_pps_getparams failed: %m"); 864 return (0); 865 } 866 867 /* nb. only turn things on, if someone else has turned something 868 * on before we get here, leave it alone! 869 */ 870 871 if (instance->assert) { 872 cp = "Assert"; 873 mode = PPS_CAPTUREASSERT; 874 mode1 = PPS_OFFSETASSERT; 875 } else { 876 cp = "Clear"; 877 mode = PPS_CAPTURECLEAR; 878 mode1 = PPS_OFFSETCLEAR; 879 } 880 oncore_log_f(instance, LOG_INFO, "Initializing timing to %s.", 881 cp); 882 883 if (!(mode & cap)) { 884 oncore_log_f(instance, LOG_ERR, 885 "Can't set timing to %s, exiting...", cp); 886 return(0); 887 } 888 889 if (!(mode1 & cap)) { 890 oncore_log_f(instance, LOG_NOTICE, 891 "Can't set %s, this will increase jitter.", 892 cp); 893 mode1 = 0; 894 } 895 896 /* only set what is legal */ 897 898 instance->pps_p.mode = (mode | mode1 | PPS_TSFMT_TSPEC) & cap; 899 900 if (time_pps_setparams(instance->pps_h, &instance->pps_p) < 0) { 901 oncore_log_f(instance, LOG_ERR, "ONCORE: time_pps_setparams fails %m"); 902 return(0); /* exit, can't do time_pps_setparans on PPS file */ 903 } 904 905 /* If HARDPPS is on, we tell kernel */ 906 907 if (instance->hardpps) { 908 int i; 909 910 oncore_log(instance, LOG_INFO, "HARDPPS Set."); 911 912 if (instance->assert) 913 i = PPS_CAPTUREASSERT; 914 else 915 i = PPS_CAPTURECLEAR; 916 917 /* we know that 'i' is legal from above */ 918 919 if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i, 920 PPS_TSFMT_TSPEC) < 0) { 921 oncore_log_f(instance, LOG_ERR, "time_pps_kcbind failed: %m"); 922 oncore_log(instance, LOG_ERR, "HARDPPS failed, abort..."); 923 return (0); 924 } 925 926 hardpps_enable = 1; 927 } 928 return(1); 929 } 930 931 932 933 #ifdef ONCORE_SHMEM_STATUS 934 static void 935 oncore_init_shmem( 936 struct instance *instance 937 ) 938 { 939 int l, fd; 940 u_char *cp, *cp1, *buf, *shmem_old; 941 struct msg_desc *mp; 942 struct stat sbuf; 943 size_t i, n, n1, shmem_length; 944 ssize_t shmem_old_size; 945 946 /* 947 * The first thing we do is see if there is an instance->shmem_fname file (still) 948 * out there from a previous run. If so, we copy it in and use it to initialize 949 * shmem (so we won't lose our almanac if we need it). 950 */ 951 952 shmem_old = 0; 953 shmem_old_size = 0; 954 if ((fd = open(instance->shmem_fname, O_RDONLY)) < 0) 955 oncore_log(instance, LOG_WARNING, "ONCORE: Can't open SHMEM file"); 956 else { 957 fstat(fd, &sbuf); 958 shmem_old_size = sbuf.st_size; 959 if (shmem_old_size != 0) { 960 shmem_old = emalloc((unsigned) sbuf.st_size); 961 if (read(fd, shmem_old, shmem_old_size) != shmem_old_size) 962 oncore_log(instance, LOG_WARNING, 963 "ONCORE: truncated/failed read of SHMEM file"); 964 } 965 close(fd); 966 } 967 968 /* OK, we now create the NEW SHMEM. */ 969 970 if ((instance->shmemfd = open(instance->shmem_fname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) { 971 oncore_log(instance, LOG_WARNING, "ONCORE: Can't open shmem"); 972 if (shmem_old) 973 free(shmem_old); 974 975 return; 976 } 977 978 /* see how big it needs to be */ 979 980 n = 1; 981 for (mp=oncore_messages; mp->flag[0]; mp++) { 982 mp->shmem = n; 983 /* Allocate space for multiplexed almanac, and 0D/2D/3D @@Ea records */ 984 if (!strcmp(mp->flag, "Cb")) { 985 instance->shmem_Cb = n; 986 n += (mp->len + 3) * 34; 987 } 988 if (!strcmp(mp->flag, "Ba")) { 989 instance->shmem_Ba = n; 990 n += (mp->len + 3) * 3; 991 } 992 if (!strcmp(mp->flag, "Ea")) { 993 instance->shmem_Ea = n; 994 n += (mp->len + 3) * 3; 995 } 996 if (!strcmp(mp->flag, "Ha")) { 997 instance->shmem_Ha = n; 998 n += (mp->len + 3) * 3; 999 } 1000 n += (mp->len + 3); 1001 } 1002 shmem_length = n + 2; 1003 1004 buf = emalloc(shmem_length); 1005 memset(buf, 0, shmem_length); 1006 1007 /* next build the new SHMEM buffer in memory */ 1008 1009 for (mp=oncore_messages; mp->flag[0]; mp++) { 1010 l = mp->shmem; 1011 buf[l + 0] = mp->len >> 8; 1012 buf[l + 1] = mp->len & 0xff; 1013 buf[l + 2] = 0; 1014 buf[l + 3] = '@'; 1015 buf[l + 4] = '@'; 1016 buf[l + 5] = mp->flag[0]; 1017 buf[l + 6] = mp->flag[1]; 1018 if (!strcmp(mp->flag, "Cb") || !strcmp(mp->flag, "Ba") || !strcmp(mp->flag, "Ea") || !strcmp(mp->flag, "Ha")) { 1019 if (!strcmp(mp->flag, "Cb")) 1020 n = 35; 1021 else 1022 n = 4; 1023 for (i=1; i<n; i++) { 1024 buf[l + i * (mp->len+3) + 0] = mp->len >> 8; 1025 buf[l + i * (mp->len+3) + 1] = mp->len & 0xff; 1026 buf[l + i * (mp->len+3) + 2] = 0; 1027 buf[l + i * (mp->len+3) + 3] = '@'; 1028 buf[l + i * (mp->len+3) + 4] = '@'; 1029 buf[l + i * (mp->len+3) + 5] = mp->flag[0]; 1030 buf[l + i * (mp->len+3) + 6] = mp->flag[1]; 1031 } 1032 } 1033 } 1034 1035 /* we now walk thru the two buffers (shmem_old and buf, soon to become shmem) 1036 * copying the data in shmem_old to buf. 1037 * When we are done we write it out and free both buffers. 1038 * If the structure sizes dont agree, I will not copy. 1039 * This could be due to an addition/deletion or a problem with the disk file. 1040 */ 1041 1042 if (shmem_old) { 1043 if ((size_t)shmem_old_size == shmem_length) { 1044 for (cp=buf+4, cp1=shmem_old+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3), cp1+=(n+3)) { 1045 n1 = 256*(*(cp1-3)) + *(cp1-2); 1046 if (n == 0 || n1 != n || strncmp((char *) cp, (char *) cp1, 4)) 1047 break; 1048 1049 memcpy(cp, cp1, (size_t) n); 1050 } 1051 } 1052 free(shmem_old); 1053 } 1054 1055 i = write(instance->shmemfd, buf, shmem_length); 1056 free(buf); 1057 1058 if (i != shmem_length) { 1059 oncore_log(instance, LOG_ERR, "ONCORE: error writing shmem"); 1060 close(instance->shmemfd); 1061 return; 1062 } 1063 1064 instance->shmem = (u_char *) mmap(0, shmem_length, 1065 PROT_READ | PROT_WRITE, 1066 #ifdef MAP_HASSEMAPHORE 1067 MAP_HASSEMAPHORE | 1068 #endif 1069 MAP_SHARED, instance->shmemfd, (off_t)0); 1070 1071 if (instance->shmem == (u_char *)MAP_FAILED) { 1072 instance->shmem = 0; 1073 close(instance->shmemfd); 1074 return; 1075 } 1076 1077 oncore_log_f(instance, LOG_NOTICE, 1078 "SHMEM (size = %ld) is CONFIGURED and available as %s", 1079 (u_long) shmem_length, instance->shmem_fname); 1080 } 1081 #endif /* ONCORE_SHMEM_STATUS */ 1082 1083 1084 1085 /* 1086 * Read Input file if it exists. 1087 */ 1088 1089 static void 1090 oncore_read_config( 1091 struct instance *instance 1092 ) 1093 { 1094 /* 1095 * First we try to open the configuration file 1096 * /etc/ntp.oncore.N 1097 * where N is the unit number viz 127.127.30.N. 1098 * If we don't find it we try 1099 * /etc/ntp.oncoreN 1100 * and then 1101 * /etc/ntp.oncore 1102 * 1103 * If we don't find any then we don't have the cable delay or PPS offset 1104 * and we choose MODE (4) below. 1105 * 1106 * Five Choices for MODE 1107 * (0) ONCORE is preinitialized, don't do anything to change it. 1108 * nb, DON'T set 0D mode, DON'T set Delay, position... 1109 * (1) NO RESET, Read Position, delays from data file, lock it in, go to 0D mode. 1110 * (2) NO RESET, Read Delays from data file, do SITE SURVEY to get position, 1111 * lock this in, go to 0D mode. 1112 * (3) HARD RESET, Read Position, delays from data file, lock it in, go to 0D mode. 1113 * (4) HARD RESET, Read Delays from data file, do SITE SURVEY to get position, 1114 * lock this in, go to 0D mode. 1115 * NB. If a POSITION is specified in the config file with mode=(2,4) [SITE SURVEY] 1116 * then this position is set as the INITIAL position of the ONCORE. 1117 * This can reduce the time to first fix. 1118 * ------------------------------------------------------------------------------- 1119 * Note that an Oncore UT without a battery backup retains NO information if it is 1120 * power cycled, with a Battery Backup it remembers the almanac, etc. 1121 * For an Oncore VP, there is an eeprom that will contain this data, along with the 1122 * option of Battery Backup. 1123 * So a UT without Battery Backup is equivalent to doing a HARD RESET on each 1124 * power cycle, since there is nowhere to store the data. 1125 * ------------------------------------------------------------------------------- 1126 * 1127 * If we open one or the other of the files, we read it looking for 1128 * MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET, ASSERT, CLEAR, HARDPPS, 1129 * STATUS, POSN3D, POSN2D, CHAN, TRAIM 1130 * then initialize using method MODE. For Mode = (1,3) all of (LAT, LON, HT) must 1131 * be present or mode reverts to (2,4). 1132 * 1133 * Read input file. 1134 * 1135 * # is comment to end of line 1136 * = allowed between 1st and 2nd fields. 1137 * 1138 * Expect to see one line with 'MODE' as first field, followed by an integer 1139 * in the range 0-4 (default = 4). 1140 * 1141 * Expect to see two lines with 'LONG', 'LAT' followed by 1-3 fields. 1142 * All numbers are floating point. 1143 * DDD.ddd 1144 * DDD MMM.mmm 1145 * DDD MMM SSS.sss 1146 * 1147 * Expect to see one line with 'HT' as first field, 1148 * followed by 1-2 fields. First is a number, the second is 'FT' or 'M' 1149 * for feet or meters. HT is the height above the GPS ellipsoid. 1150 * If the receiver reports height in both GPS and MSL, then we will report 1151 * the difference GPS-MSL on the clockstats file. 1152 * 1153 * There is an optional line, starting with DELAY, followed 1154 * by 1 or two fields. The first is a number (a time) the second is 1155 * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds. 1156 * DELAY is cable delay, typically a few tens of ns. 1157 * 1158 * There is an optional line, starting with OFFSET, followed 1159 * by 1 or two fields. The first is a number (a time) the second is 1160 * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds. 1161 * OFFSET is the offset of the PPS pulse from 0. (only fully implemented 1162 * with the PPSAPI, we need to be able to tell the Kernel about this 1163 * offset if the Kernel PLL is in use, but can only do this presently 1164 * when using the PPSAPI interface. If not using the Kernel PLL, 1165 * then there is no problem. 1166 * 1167 * There is an optional line, with either ASSERT or CLEAR on it, which 1168 * determine which transition of the PPS signal is used for timing by the 1169 * PPSAPI. If neither is present, then ASSERT is assumed. 1170 * ASSERT/CLEAR can also be set with FLAG2 of the ntp.conf input. 1171 * For Flag2, ASSERT=0, and hence is default. 1172 * 1173 * There is an optional line, with HARDPPS on it. Including this line causes 1174 * the PPS signal to control the kernel PLL. 1175 * HARDPPS can also be set with FLAG3 of the ntp.conf input. 1176 * For Flag3, 0 is disabled, and the default. 1177 * 1178 * There are three options that have to do with using the shared memory option. 1179 * First, to enable the option there must be a SHMEM line with a file name. 1180 * The file name is the file associated with the shared memory. 1181 * 1182 * In shared memory, there is one 'record' for each returned variable. 1183 * For the @@Ea data there are three 'records' containing position data. 1184 * There will always be data in the record corresponding to the '0D' @@Ea record, 1185 * and the user has a choice of filling the '3D' record by specifying POSN3D, 1186 * or the '2D' record by specifying POSN2D. In either case the '2D' or '3D' 1187 * record is filled once every 15s. 1188 * 1189 * Two additional variables that can be set are CHAN and TRAIM. These should be 1190 * set correctly by the code examining the @@Cj record, but we bring them out here 1191 * to allow the user to override either the # of channels, or the existence of TRAIM. 1192 * CHAN expects to be followed by in integer: 6, 8, or 12. TRAIM expects to be 1193 * followed by YES or NO. 1194 * 1195 * There is an optional line with MASK on it followed by one integer field in the 1196 * range 0 to 89. This sets the satellite mask angle and will determine the minimum 1197 * elevation angle for satellites to be tracked by the receiver. The default value 1198 * is 10 deg for the VP and 0 deg for all other receivers. 1199 * 1200 * There is an optional line with PPSCONTROL on it (only valid for M12 or M12+T 1201 * receivers, the option is read, but ignored for all others) 1202 * and it is followed by: 1203 * ON Turn PPS on. This is the default and the default for other 1204 * oncore receivers. The PPS is on even if not tracking 1205 * any satellites. 1206 * SATELLITE Turns PPS on if tracking at least 1 satellite, else off. 1207 * TRAIM Turns PPS on or off controlled by TRAIM. 1208 * The OFF option is NOT implemented, since the Oncore driver will not work 1209 * without the PPS signal. 1210 * 1211 * So acceptable input would be 1212 * # these are my coordinates (RWC) 1213 * LON -106 34.610 1214 * LAT 35 08.999 1215 * HT 1589 # could equally well say HT 5215 FT 1216 * DELAY 60 ns 1217 */ 1218 1219 FILE *fd; 1220 char *cc, *ca, line[100], units[2], device[64]; 1221 const char *dirs[] = { "/etc/ntp", "/etc", 0 }; 1222 const char *cp, **cpp; 1223 int i, sign, lat_flg, long_flg, ht_flg, mode, mask; 1224 double f1, f2, f3; 1225 1226 fd = NULL; /* just to shutup gcc complaint */ 1227 for (cpp=dirs; *cpp; cpp++) { 1228 cp = *cpp; 1229 snprintf(device, sizeof(device), "%s/ntp.oncore.%d", 1230 cp, instance->unit); /* try "ntp.oncore.0 */ 1231 if ((fd=fopen(device, "r"))) 1232 break; 1233 snprintf(device, sizeof(device), "%s/ntp.oncore%d", 1234 cp, instance->unit); /* try "ntp.oncore0" */ 1235 if ((fd=fopen(device, "r"))) 1236 break; 1237 snprintf(device, sizeof(device), "%s/ntp.oncore", cp); 1238 if ((fd=fopen(device, "r"))) /* last try "ntp.oncore" */ 1239 break; 1240 } 1241 1242 if (!fd) { /* no inputfile, default to the works ... */ 1243 instance->init_type = 4; 1244 return; 1245 } 1246 1247 mode = mask = 0; 1248 lat_flg = long_flg = ht_flg = 0; 1249 while (fgets(line, 100, fd)) { 1250 char *cpw; 1251 1252 /* Remove comments */ 1253 if ((cpw = strchr(line, '#'))) 1254 *cpw = '\0'; 1255 1256 /* Remove trailing space */ 1257 for (i = strlen(line); 1258 i > 0 && isascii((unsigned char)line[i - 1]) && isspace((unsigned char)line[i - 1]); 1259 ) 1260 line[--i] = '\0'; 1261 1262 /* Remove leading space */ 1263 for (cc = line; *cc && isascii((unsigned char)*cc) && isspace((unsigned char)*cc); cc++) 1264 continue; 1265 1266 /* Stop if nothing left */ 1267 if (!*cc) 1268 continue; 1269 1270 /* Uppercase the command and find the arg */ 1271 for (ca = cc; *ca; ca++) { 1272 if (isascii((unsigned char)*ca)) { 1273 if (islower((unsigned char)*ca)) { 1274 *ca = toupper((unsigned char)*ca); 1275 } else if (isspace((unsigned char)*ca) || (*ca == '=')) 1276 break; 1277 } 1278 } 1279 1280 /* Remove space (and possible =) leading the arg */ 1281 for (; *ca && isascii((unsigned char)*ca) && (isspace((unsigned char)*ca) || (*ca == '=')); ca++) 1282 continue; 1283 1284 if (!strncmp(cc, "STATUS", (size_t) 6) || !strncmp(cc, "SHMEM", (size_t) 5)) { 1285 instance->shmem_fname = estrdup(ca); 1286 continue; 1287 } 1288 1289 /* Uppercase argument as well */ 1290 for (cpw = ca; *cpw; cpw++) 1291 if (isascii((unsigned char)*cpw) && islower((unsigned char)*cpw)) 1292 *cpw = toupper((unsigned char)*cpw); 1293 1294 if (!strncmp(cc, "LAT", (size_t) 3)) { 1295 f1 = f2 = f3 = 0; 1296 sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3); 1297 sign = 1; 1298 if (f1 < 0) { 1299 f1 = -f1; 1300 sign = -1; 1301 } 1302 instance->ss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/ 1303 lat_flg++; 1304 } else if (!strncmp(cc, "LON", (size_t) 3)) { 1305 f1 = f2 = f3 = 0; 1306 sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3); 1307 sign = 1; 1308 if (f1 < 0) { 1309 f1 = -f1; 1310 sign = -1; 1311 } 1312 instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/ 1313 long_flg++; 1314 } else if (!strncmp(cc, "HT", (size_t) 2)) { 1315 f1 = 0; 1316 units[0] = '\0'; 1317 sscanf(ca, "%lf %1s", &f1, units); 1318 if (units[0] == 'F') 1319 f1 = 0.3048 * f1; 1320 instance->ss_ht = 100 * f1; /* cm */ 1321 ht_flg++; 1322 } else if (!strncmp(cc, "DELAY", (size_t) 5)) { 1323 f1 = 0; 1324 units[0] = '\0'; 1325 sscanf(ca, "%lf %1s", &f1, units); 1326 if (units[0] == 'N') 1327 ; 1328 else if (units[0] == 'U') 1329 f1 = 1000 * f1; 1330 else if (units[0] == 'M') 1331 f1 = 1000000 * f1; 1332 else 1333 f1 = 1000000000 * f1; 1334 if (f1 < 0 || f1 > 1.e9) 1335 f1 = 0; 1336 if (f1 < 0 || f1 > 999999) 1337 oncore_log_f(instance, LOG_WARNING, 1338 "PPS Cable delay of %fns out of Range, ignored", 1339 f1); 1340 else 1341 instance->delay = f1; /* delay in ns */ 1342 } else if (!strncmp(cc, "OFFSET", (size_t) 6)) { 1343 f1 = 0; 1344 units[0] = '\0'; 1345 sscanf(ca, "%lf %1s", &f1, units); 1346 if (units[0] == 'N') 1347 ; 1348 else if (units[0] == 'U') 1349 f1 = 1000 * f1; 1350 else if (units[0] == 'M') 1351 f1 = 1000000 * f1; 1352 else 1353 f1 = 1000000000 * f1; 1354 if (f1 < 0 || f1 > 1.e9) 1355 f1 = 0; 1356 if (f1 < 0 || f1 > 999999999.) 1357 oncore_log_f(instance, LOG_WARNING, 1358 "PPS Offset of %fns out of Range, ignored", 1359 f1); 1360 else 1361 instance->offset = f1; /* offset in ns */ 1362 } else if (!strncmp(cc, "MODE", (size_t) 4)) { 1363 sscanf(ca, "%d", &mode); 1364 if (mode < 0 || mode > 4) 1365 mode = 4; 1366 } else if (!strncmp(cc, "ASSERT", (size_t) 6)) { 1367 instance->assert = 1; 1368 } else if (!strncmp(cc, "CLEAR", (size_t) 5)) { 1369 instance->assert = 0; 1370 } else if (!strncmp(cc, "HARDPPS", (size_t) 7)) { 1371 instance->hardpps = 1; 1372 } else if (!strncmp(cc, "POSN2D", (size_t) 6)) { 1373 instance->shmem_Posn = 2; 1374 } else if (!strncmp(cc, "POSN3D", (size_t) 6)) { 1375 instance->shmem_Posn = 3; 1376 } else if (!strncmp(cc, "CHAN", (size_t) 4)) { 1377 sscanf(ca, "%d", &i); 1378 if ((i == 6) || (i == 8) || (i == 12)) 1379 instance->chan_in = i; 1380 } else if (!strncmp(cc, "TRAIM", (size_t) 5)) { 1381 instance->traim_in = 1; /* so TRAIM alone is YES */ 1382 if (!strcmp(ca, "NO") || !strcmp(ca, "OFF")) /* Yes/No, On/Off */ 1383 instance->traim_in = 0; 1384 } else if (!strncmp(cc, "MASK", (size_t) 4)) { 1385 sscanf(ca, "%d", &mask); 1386 if (mask > -1 && mask < 90) 1387 instance->Ag = mask; /* Satellite mask angle */ 1388 } else if (!strncmp(cc,"PPSCONTROL",10)) { /* pps control M12 only */ 1389 if (!strcmp(ca,"ON") || !strcmp(ca, "CONTINUOUS")) { 1390 instance->pps_control = 1; /* PPS always on */ 1391 } else if (!strcmp(ca,"SATELLITE")) { 1392 instance->pps_control = 2; /* PPS on when satellite is available */ 1393 } else if (!strcmp(ca,"TRAIM")) { 1394 instance->pps_control = 3; /* PPS on when TRAIM status is OK */ 1395 } else { 1396 oncore_log_f(instance, LOG_WARNING, 1397 "Unknown value \"%s\" for PPSCONTROL, ignored", 1398 cc); 1399 } 1400 } 1401 } 1402 fclose(fd); 1403 1404 /* 1405 * OK, have read all of data file, and extracted the good stuff. 1406 * If lat/long/ht specified they ALL must be specified for mode = (1,3). 1407 */ 1408 1409 instance->posn_set = 1; 1410 if (!( lat_flg && long_flg && ht_flg )) { 1411 oncore_log_f(instance, LOG_WARNING, 1412 "ONCORE: incomplete data on %s", device); 1413 instance->posn_set = 0; 1414 if (mode == 1 || mode == 3) { 1415 oncore_log_f(instance, LOG_WARNING, 1416 "Input Mode = %d, but no/incomplete position, mode set to %d", 1417 mode, mode+1); 1418 mode++; 1419 } 1420 } 1421 instance->init_type = mode; 1422 1423 oncore_log_f(instance, LOG_INFO, "Input mode = %d", mode); 1424 } 1425 1426 1427 1428 /* 1429 * move data from NTP to buffer (toss the extra in the unlikely case it won't fit) 1430 */ 1431 1432 static void 1433 oncore_receive( 1434 struct recvbuf *rbufp 1435 ) 1436 { 1437 size_t i; 1438 u_char *p; 1439 struct peer *peer; 1440 struct instance *instance; 1441 1442 peer = rbufp->recv_peer; 1443 instance = peer->procptr->unitptr; 1444 p = (u_char *) &rbufp->recv_space; 1445 1446 #ifdef ONCORE_VERBOSE_RECEIVE 1447 if (debug > 4) { 1448 int i; 1449 char Msg[120], Msg2[10]; 1450 1451 oncore_log_f(instance, LOG_DEBUG, 1452 ">>> %d bytes available", 1453 rbufp->recv_length); 1454 strlcpy(Msg, ">>>", sizeof(Msg)); 1455 for (i = 0; i < rbufp->recv_length; i++) { 1456 snprintf(Msg2, sizeof(Msg2), "%02x ", p[i]); 1457 strlcat(Msg, Msg2, sizeof(Msg)); 1458 } 1459 oncore_log(instance, LOG_DEBUG, Msg); 1460 1461 strlcpy(Msg, ">>>", sizeof(Msg)); 1462 for (i = 0; i < rbufp->recv_length; i++) { 1463 snprintf(Msg2, sizeof(Msg2), "%03o ", p[i]); 1464 strlcat(Msg, Msg2, sizeof(Msg)); 1465 } 1466 oncore_log(instance, LOG_DEBUG, Msg); 1467 } 1468 #endif 1469 1470 i = rbufp->recv_length; 1471 if ((size_t)rcvptr + i >= sizeof(rcvbuf)) 1472 i = sizeof(rcvbuf) - rcvptr; /* and some char will be lost */ 1473 memcpy(rcvbuf+rcvptr, p, i); 1474 rcvptr += i; 1475 oncore_consume(instance); 1476 } 1477 1478 1479 1480 /* 1481 * Deal with any complete messages 1482 */ 1483 1484 static void 1485 oncore_consume( 1486 struct instance *instance 1487 ) 1488 { 1489 unsigned i, m, l; 1490 1491 while (rcvptr >= 7) { 1492 if (rcvbuf[0] != '@' || rcvbuf[1] != '@') { 1493 /* We're not in sync, lets try to get there */ 1494 for (i=1; i < rcvptr-1; i++) 1495 if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@') 1496 break; 1497 #ifdef ONCORE_VERBOSE_CONSUME 1498 if (debug > 4) 1499 oncore_log_f(instance, LOG_DEBUG, 1500 ">>> skipping %d chars", 1501 i); 1502 #endif 1503 if (i != rcvptr) 1504 memcpy(rcvbuf, rcvbuf+i, (size_t)(rcvptr-i)); 1505 rcvptr -= i; 1506 continue; 1507 } 1508 1509 /* Ok, we have a header now */ 1510 l = sizeof(oncore_messages)/sizeof(oncore_messages[0]) -1; 1511 for(m=0; m<l; m++) 1512 if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), (size_t) 2)) 1513 break; 1514 if (m == l) { 1515 #ifdef ONCORE_VERBOSE_CONSUME 1516 if (debug > 4) 1517 oncore_log_f(instance, LOG_DEBUG, 1518 ">>> Unknown MSG, skipping 4 (%c%c)", 1519 rcvbuf[2], rcvbuf[3]); 1520 #endif 1521 memcpy(rcvbuf, rcvbuf+4, (size_t) 4); 1522 rcvptr -= 4; 1523 continue; 1524 } 1525 1526 l = oncore_messages[m].len; 1527 #ifdef ONCORE_VERBOSE_CONSUME 1528 if (debug > 3) 1529 oncore_log_f(instance, LOG_DEBUG, 1530 "GOT: %c%c %d of %d entry %d", 1531 instance->unit, rcvbuf[2], 1532 rcvbuf[3], rcvptr, l, m); 1533 #endif 1534 /* Got the entire message ? */ 1535 1536 if (rcvptr < l) 1537 return; 1538 1539 /* are we at the end of message? should be <Cksum><CR><LF> */ 1540 1541 if (rcvbuf[l-2] != '\r' || rcvbuf[l-1] != '\n') { 1542 #ifdef ONCORE_VERBOSE_CONSUME 1543 if (debug) 1544 oncore_log(instance, LOG_DEBUG, "NO <CR><LF> at end of message"); 1545 #endif 1546 } else { /* check the CheckSum */ 1547 if (oncore_checksum_ok(rcvbuf, l)) { 1548 if (instance->shmem != NULL) { 1549 instance->shmem[oncore_messages[m].shmem + 2]++; 1550 memcpy(instance->shmem + oncore_messages[m].shmem + 3, 1551 rcvbuf, (size_t) l); 1552 } 1553 oncore_msg_any(instance, rcvbuf, (size_t) (l-3), m); 1554 if (oncore_messages[m].handler) 1555 oncore_messages[m].handler(instance, rcvbuf, (size_t) (l-3)); 1556 } 1557 #ifdef ONCORE_VERBOSE_CONSUME 1558 else if (debug) { 1559 char Msg[120], Msg2[10]; 1560 1561 oncore_log(instance, LOG_ERR, "Checksum mismatch!"); 1562 snprintf(Msg, sizeof(Msg), "@@%c%c ", rcvbuf[2], rcvbuf[3]); 1563 for (i = 4; i < l; i++) { 1564 snprintf(Msg2, sizeof(Msg2), 1565 "%03o ", rcvbuf[i]); 1566 strlcat(Msg, Msg2, sizeof(Msg)); 1567 } 1568 oncore_log(instance, LOG_DEBUG, Msg); 1569 } 1570 #endif 1571 } 1572 1573 if (l != rcvptr) 1574 memcpy(rcvbuf, rcvbuf+l, (size_t) (rcvptr-l)); 1575 rcvptr -= l; 1576 } 1577 } 1578 1579 1580 1581 static void 1582 oncore_get_timestamp( 1583 struct instance *instance, 1584 long dt1, /* tick offset THIS time step */ 1585 long dt2 /* tick offset NEXT time step */ 1586 ) 1587 { 1588 int Rsm; 1589 u_long j; 1590 l_fp ts, ts_tmp; 1591 double dmy; 1592 #ifdef HAVE_STRUCT_TIMESPEC 1593 struct timespec *tsp = 0; 1594 #else 1595 struct timeval *tsp = 0; 1596 #endif 1597 int current_mode; 1598 pps_params_t current_params; 1599 struct timespec timeout; 1600 struct peer *peer; 1601 pps_info_t pps_i; 1602 char Msg[160]; 1603 1604 peer = instance->peer; 1605 1606 #if 1 1607 /* If we are in SiteSurvey mode, then we are in 3D mode, and we fall thru. 1608 * If we have Finished the SiteSurvey, then we fall thru for the 14/15 1609 * times we get here in 0D mode (the 1/15 is in 3D for SHMEM). 1610 * This gives good time, which gets better when the SS is done. 1611 */ 1612 1613 if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D)) { 1614 #else 1615 /* old check, only fall thru for SS_DONE and 0D mode, 2h45m wait for ticks */ 1616 1617 if ((instance->site_survey != ONCORE_SS_DONE) || (instance->mode != MODE_0D)) { 1618 #endif 1619 peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1620 return; 1621 } 1622 1623 /* Don't do anything without an almanac to define the GPS->UTC delta */ 1624 1625 if (instance->rsm.bad_almanac) { 1626 peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1627 return; 1628 } 1629 1630 /* Once the Almanac is valid, the M12+T does not produce valid UTC 1631 * immediately. 1632 * Wait for UTC offset decode valid, then wait one message more 1633 * so we are not off by 13 seconds after reset. 1634 */ 1635 1636 if (instance->count5) { 1637 instance->count5--; 1638 peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1639 return; 1640 } 1641 1642 j = instance->ev_serial; 1643 timeout.tv_sec = 0; 1644 timeout.tv_nsec = 0; 1645 if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i, 1646 &timeout) < 0) { 1647 oncore_log_f(instance, LOG_ERR, 1648 "time_pps_fetch failed %m"); 1649 peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1650 return; 1651 } 1652 1653 if (instance->assert) { 1654 tsp = &pps_i.assert_timestamp; 1655 1656 #ifdef ONCORE_VERBOSE_GET_TIMESTAMP 1657 if (debug > 2) { 1658 u_long i; 1659 1660 i = (u_long) pps_i.assert_sequence; 1661 # ifdef HAVE_STRUCT_TIMESPEC 1662 oncore_log_f(instance, LOG_DEBUG, 1663 "serial/j (%lu, %lu) %ld.%09ld", i, 1664 j, (long)tsp->tv_sec, 1665 (long)tsp->tv_nsec); 1666 # else 1667 oncore_log_f(instance, LOG_DEBUG, 1668 "serial/j (%lu, %lu) %ld.%06ld", i, 1669 j, (long)tsp->tv_sec, 1670 (long)tsp->tv_usec); 1671 # endif 1672 } 1673 #endif 1674 1675 if (pps_i.assert_sequence == j) { 1676 oncore_log(instance, LOG_NOTICE, "ONCORE: oncore_get_timestamp, error serial pps"); 1677 peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1678 return; 1679 } 1680 1681 instance->ev_serial = pps_i.assert_sequence; 1682 } else { 1683 tsp = &pps_i.clear_timestamp; 1684 1685 #if 0 1686 if (debug > 2) { 1687 u_long i; 1688 1689 i = (u_long) pps_i.clear_sequence; 1690 # ifdef HAVE_STRUCT_TIMESPEC 1691 oncore_log_f(instance, LOG_DEBUG, 1692 "serial/j (%lu, %lu) %ld.%09ld", i, 1693 j, (long)tsp->tv_sec, 1694 (long)tsp->tv_nsec); 1695 # else 1696 oncore_log_f(instance, LOG_DEBUG, 1697 "serial/j (%lu, %lu) %ld.%06ld", i, 1698 j, (long)tsp->tv_sec, 1699 (long)tsp->tv_usec); 1700 # endif 1701 } 1702 #endif 1703 1704 if (pps_i.clear_sequence == j) { 1705 oncore_log(instance, LOG_ERR, "oncore_get_timestamp, error serial pps"); 1706 peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1707 return; 1708 } 1709 instance->ev_serial = pps_i.clear_sequence; 1710 } 1711 1712 /* convert timespec -> ntp l_fp */ 1713 1714 dmy = tsp->tv_nsec; 1715 dmy /= 1e9; 1716 ts.l_uf = dmy * 4294967296.0; 1717 ts.l_ui = tsp->tv_sec; 1718 1719 #if 0 1720 alternate code for previous 4 lines is 1721 dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */ 1722 DTOLFP(dmy, &ts); 1723 dmy = tsp->tv_sec; /* integer part */ 1724 DTOLFP(dmy, &ts_tmp); 1725 L_ADD(&ts, &ts_tmp); 1726 or more simply 1727 dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */ 1728 DTOLFP(dmy, &ts); 1729 ts.l_ui = tsp->tv_sec; 1730 #endif /* 0 */ 1731 1732 /* now have timestamp in ts */ 1733 /* add in saw_tooth and offset, these will be ZERO if no TRAIM */ 1734 /* they will be IGNORED if the PPSAPI cant do PPS_OFFSET/ASSERT/CLEAR */ 1735 /* we just try to add them in and dont test for that here */ 1736 1737 /* saw_tooth not really necessary if using TIMEVAL */ 1738 /* since its only precise to us, but do it anyway. */ 1739 1740 /* offset in ns, and is positive (late), we subtract */ 1741 /* to put the PPS time transition back where it belongs */ 1742 1743 /* must hand the offset for the NEXT sec off to the Kernel to do */ 1744 /* the addition, so that the Kernel PLL sees the offset too */ 1745 1746 if (instance->assert) 1747 instance->pps_p.assert_offset.tv_nsec = -dt2; 1748 else 1749 instance->pps_p.clear_offset.tv_nsec = -dt2; 1750 1751 /* The following code is necessary, and not just a time_pps_setparams, 1752 * using the saved instance->pps_p, since some other process on the 1753 * machine may have diddled with the mode bits (say adding something 1754 * that it needs). We take what is there and ADD what we need. 1755 * [[ The results from the time_pps_getcap is unlikely to change so 1756 * we could probably just save it, but I choose to do the call ]] 1757 * Unfortunately, there is only ONE set of mode bits in the kernel per 1758 * interface, and not one set for each open handle. 1759 * 1760 * There is still a race condition here where we might mess up someone 1761 * elses mode, but if he is being careful too, he should survive. 1762 */ 1763 1764 if (time_pps_getcap(instance->pps_h, ¤t_mode) < 0) { 1765 oncore_log_f(instance, LOG_ERR, 1766 "time_pps_getcap failed: %m"); 1767 peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1768 return; 1769 } 1770 1771 if (time_pps_getparams(instance->pps_h, ¤t_params) < 0) { 1772 oncore_log_f(instance, LOG_ERR, 1773 "time_pps_getparams failed: %m"); 1774 peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1775 return; 1776 } 1777 1778 /* or current and mine */ 1779 current_params.mode |= instance->pps_p.mode; 1780 /* but only set whats legal */ 1781 current_params.mode &= current_mode; 1782 1783 current_params.assert_offset.tv_sec = 0; 1784 current_params.assert_offset.tv_nsec = -dt2; 1785 current_params.clear_offset.tv_sec = 0; 1786 current_params.clear_offset.tv_nsec = -dt2; 1787 1788 if (time_pps_setparams(instance->pps_h, ¤t_params)) 1789 oncore_log(instance, LOG_ERR, "ONCORE: Error doing time_pps_setparams"); 1790 1791 /* have time from UNIX origin, convert to NTP origin. */ 1792 1793 ts.l_ui += JAN_1970; 1794 instance->pp->lastrec = ts; 1795 1796 /* print out information about this timestamp (long line) */ 1797 1798 ts_tmp = ts; 1799 ts_tmp.l_ui = 0; /* zero integer part */ 1800 LFPTOD(&ts_tmp, dmy); /* convert fractional part to a double */ 1801 j = 1.0e9*dmy; /* then to integer ns */ 1802 1803 Rsm = 0; 1804 if (instance->chan == 6) 1805 Rsm = instance->BEHa[64]; 1806 else if (instance->chan == 8) 1807 Rsm = instance->BEHa[72]; 1808 else if (instance->chan == 12) 1809 Rsm = ((instance->BEHa[129]<<8) | instance->BEHa[130]); 1810 1811 if (instance->chan == 6 || instance->chan == 8) { 1812 char f1[6], f2[6], f3[6], f4[6]; 1813 if (instance->traim) { 1814 snprintf(f1, sizeof(f1), "%d", 1815 instance->BEHn[21]); 1816 snprintf(f2, sizeof(f2), "%d", 1817 instance->BEHn[22]); 1818 snprintf(f3, sizeof(f3), "%2d", 1819 instance->BEHn[23] * 256 + 1820 instance->BEHn[24]); 1821 snprintf(f4, sizeof(f4), "%3d", 1822 (s_char)instance->BEHn[25]); 1823 } else { 1824 strlcpy(f1, "x", sizeof(f1)); 1825 strlcpy(f2, "x", sizeof(f2)); 1826 strlcpy(f3, "xx", sizeof(f3)); 1827 strlcpy(f4, "xxx", sizeof(f4)); 1828 } 1829 snprintf(Msg, sizeof(Msg), /* MAX length 128, currently at 127 */ 1830 "%u.%09lu %d %d %2d %2d %2d %2ld rstat %02x dop %4.1f nsat %2d,%d traim %d,%s,%s sigma %s neg-sawtooth %s sat %d%d%d%d%d%d%d%d", 1831 ts.l_ui, j, 1832 instance->pp->year, instance->pp->day, 1833 instance->pp->hour, instance->pp->minute, instance->pp->second, 1834 (long) tsp->tv_sec % 60, 1835 Rsm, 0.1*(256*instance->BEHa[35]+instance->BEHa[36]), 1836 /*rsat dop */ 1837 instance->BEHa[38], instance->BEHa[39], instance->traim, f1, f2, 1838 /* nsat visible, nsat tracked, traim,traim,traim */ 1839 f3, f4, 1840 /* sigma neg-sawtooth */ 1841 /*sat*/ instance->BEHa[41], instance->BEHa[45], instance->BEHa[49], instance->BEHa[53], 1842 instance->BEHa[57], instance->BEHa[61], instance->BEHa[65], instance->BEHa[69] 1843 ); /* will be 0 for 6 chan */ 1844 } else if (instance->chan == 12) { 1845 char f1[6], f2[6], f3[6], f4[6]; 1846 if (instance->traim) { 1847 snprintf(f1, sizeof(f1), "%d", 1848 instance->BEHn[6]); 1849 snprintf(f2, sizeof(f2), "%d", 1850 instance->BEHn[7]); 1851 snprintf(f3, sizeof(f3), "%d", 1852 instance->BEHn[12] * 256 + 1853 instance->BEHn[13]); 1854 snprintf(f4, sizeof(f4), "%3d", 1855 (s_char)instance->BEHn[14]); 1856 } else { 1857 strlcpy(f1, "x", sizeof(f1)); 1858 strlcpy(f2, "x", sizeof(f2)); 1859 strlcpy(f3, "xx", sizeof(f3)); 1860 strlcpy(f4, "xxx", sizeof(f4)); 1861 } 1862 snprintf(Msg, sizeof(Msg), 1863 "%u.%09lu %d %d %2d %2d %2d %2ld rstat %02x dop %4.1f nsat %2d,%d traim %d,%s,%s sigma %s neg-sawtooth %s sat %d%d%d%d%d%d%d%d%d%d%d%d", 1864 ts.l_ui, j, 1865 instance->pp->year, instance->pp->day, 1866 instance->pp->hour, instance->pp->minute, instance->pp->second, 1867 (long) tsp->tv_sec % 60, 1868 Rsm, 0.1*(256*instance->BEHa[53]+instance->BEHa[54]), 1869 /*rsat dop */ 1870 instance->BEHa[55], instance->BEHa[56], instance->traim, f1, f2, 1871 /* nsat visible, nsat tracked traim,traim,traim */ 1872 f3, f4, 1873 /* sigma neg-sawtooth */ 1874 /*sat*/ instance->BEHa[58], instance->BEHa[64], instance->BEHa[70], instance->BEHa[76], 1875 instance->BEHa[82], instance->BEHa[88], instance->BEHa[94], instance->BEHa[100], 1876 instance->BEHa[106], instance->BEHa[112], instance->BEHa[118], instance->BEHa[124] 1877 ); 1878 } 1879 1880 /* and some things I dont understand (magic ntp things) */ 1881 1882 #if 1 1883 oncore_feed_clockproc(instance); 1884 #else 1885 if (!refclock_process(instance->pp)) { 1886 refclock_report(peer, CEVNT_BADTIME); 1887 peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1888 return; 1889 } 1890 #endif 1891 1892 oncore_log(instance, LOG_INFO, Msg); /* this is long message above */ 1893 instance->pollcnt = 2; 1894 1895 if (instance->polled) { 1896 instance->polled = 0; 1897 /* instance->pp->dispersion = instance->pp->skew = 0; */ 1898 instance->pp->lastref = instance->pp->lastrec; 1899 refclock_receive(instance->peer); 1900 } 1901 peer->flags |= FLAG_PPS; 1902 } 1903 1904 1905 /*************** oncore_msg_XX routines start here *******************/ 1906 1907 1908 /* 1909 * print Oncore response message. 1910 */ 1911 1912 static void 1913 oncore_msg_any( 1914 struct instance *instance, 1915 u_char *buf, 1916 size_t len, 1917 int idx 1918 ) 1919 { 1920 #ifdef ONCORE_VERBOSE_MSG_ANY 1921 int i; 1922 const char *fmt = oncore_messages[idx].fmt; 1923 const char *p; 1924 char *q; 1925 char *qlim; 1926 #ifdef HAVE_GETCLOCK 1927 struct timespec ts; 1928 #endif 1929 struct timeval tv; 1930 char Msg[120], Msg2[10]; 1931 1932 if (debug > 3) { 1933 # ifdef HAVE_GETCLOCK 1934 (void) getclock(TIMEOFDAY, &ts); 1935 tv.tv_sec = ts.tv_sec; 1936 tv.tv_usec = ts.tv_nsec / 1000; 1937 # else 1938 GETTIMEOFDAY(&tv, 0); 1939 # endif 1940 oncore_log(instance, LOG_DEBUG, "%ld.%06ld", 1941 (long)tv.tv_sec, (long)tv.tv_usec); 1942 1943 if (!*fmt) { 1944 snprintf(Msg, sizeof(Msg), ">>@@%c%c ", buf[2], 1945 buf[3]); 1946 for(i = 2; i < len && i < 2400 ; i++) { 1947 snprintf(Msg2, sizeof(Msg2), "%02x", 1948 buf[i]); 1949 strlcat(Msg, Msg2, sizeof(Msg)); 1950 } 1951 oncore_log(instance, LOG_DEBUG, Msg); 1952 return; 1953 } else { 1954 strlcpy(Msg, "##", sizeof(Msg)); 1955 qlim = Msg + sizeof(Msg) - 3; 1956 for (p = fmt, q = Msg + 2; q < qlim && *p; ) { 1957 *q++ = *p++; 1958 *q++ = '_'; 1959 } 1960 *q = '\0'; 1961 oncore_log(instance, LOG_DEBUG, Msg); 1962 snprintf(Msg, sizeof(Msg), "%c%c", buf[2], 1963 buf[3]); 1964 i = 4; 1965 for (p = fmt; *p; p++) { 1966 snprintf(Msg2, "%02x", buf[i++]); 1967 strlcat(Msg, Msg2, sizeof(Msg)); 1968 } 1969 oncore_log(instance, LOG_DEBUG, Msg); 1970 } 1971 } 1972 #endif 1973 } 1974 1975 1976 1977 /* Latitude, Longitude, Height */ 1978 1979 static void 1980 oncore_msg_Adef( 1981 struct instance *instance, 1982 u_char *buf, 1983 size_t len 1984 ) 1985 { 1986 } 1987 1988 1989 1990 /* Mask Angle */ 1991 1992 static void 1993 oncore_msg_Ag( 1994 struct instance *instance, 1995 u_char *buf, 1996 size_t len 1997 ) 1998 { 1999 const char *cp; 2000 2001 cp = "set to"; 2002 if (instance->o_state == ONCORE_RUN) 2003 cp = "is"; 2004 2005 instance->Ag = buf[4]; 2006 oncore_log_f(instance, LOG_INFO, 2007 "Satellite mask angle %s %d degrees", cp, 2008 (int)instance->Ag); 2009 } 2010 2011 2012 2013 /* 2014 * get Position hold position 2015 */ 2016 2017 static void 2018 oncore_msg_As( 2019 struct instance *instance, 2020 u_char *buf, 2021 size_t len 2022 ) 2023 { 2024 instance->ss_lat = buf_w32(&buf[4]); 2025 instance->ss_long = buf_w32(&buf[8]); 2026 instance->ss_ht = buf_w32(&buf[12]); 2027 2028 /* Print out Position */ 2029 oncore_print_posn(instance); 2030 } 2031 2032 2033 2034 /* 2035 * Try to use Oncore UT+ Auto Survey Feature 2036 * If its not there (VP), set flag to do it ourselves. 2037 */ 2038 2039 static void 2040 oncore_msg_At( 2041 struct instance *instance, 2042 u_char *buf, 2043 size_t len 2044 ) 2045 { 2046 instance->saw_At = 1; 2047 if (instance->site_survey == ONCORE_SS_TESTING) { 2048 if (buf[4] == 2) { 2049 oncore_log(instance, LOG_NOTICE, 2050 "Initiating hardware 3D site survey"); 2051 2052 oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_HW"); 2053 instance->site_survey = ONCORE_SS_HW; 2054 } 2055 } 2056 } 2057 2058 2059 2060 /* 2061 * get PPS Offset 2062 * Nb. @@Ay is not supported for early UT (no plus) model 2063 */ 2064 2065 static void 2066 oncore_msg_Ay( 2067 struct instance *instance, 2068 u_char *buf, 2069 size_t len 2070 ) 2071 { 2072 if (instance->saw_Ay) 2073 return; 2074 2075 instance->saw_Ay = 1; 2076 2077 instance->offset = buf_w32(&buf[4]); 2078 2079 oncore_log_f(instance, LOG_INFO, "PPS Offset is set to %ld ns", 2080 instance->offset); 2081 } 2082 2083 2084 2085 /* 2086 * get Cable Delay 2087 */ 2088 2089 static void 2090 oncore_msg_Az( 2091 struct instance *instance, 2092 u_char *buf, 2093 size_t len 2094 ) 2095 { 2096 if (instance->saw_Az) 2097 return; 2098 2099 instance->saw_Az = 1; 2100 2101 instance->delay = buf_w32(&buf[4]); 2102 2103 oncore_log_f(instance, LOG_INFO, "Cable delay is set to %ld ns", 2104 instance->delay); 2105 } 2106 2107 2108 2109 /* Ba, Ea and Ha come here, these contain Position */ 2110 2111 static void 2112 oncore_msg_BaEaHa( 2113 struct instance *instance, 2114 u_char *buf, 2115 size_t len 2116 ) 2117 { 2118 const char *cp; 2119 int mode; 2120 2121 /* OK, we are close to the RUN state now. 2122 * But we have a few more items to initialize first. 2123 * 2124 * At the beginning of this routine there are several 'timers'. 2125 * We enter this routine 1/sec, and since the upper levels of NTP have usurped 2126 * the use of timers, we use the 1/sec entry to do things that 2127 * we would normally do with timers... 2128 */ 2129 2130 if (instance->o_state == ONCORE_CHECK_CHAN) { /* here while checking for the # chan */ 2131 if (buf[2] == 'B') { /* 6chan */ 2132 if (instance->chan_ck < 6) instance->chan_ck = 6; 2133 } else if (buf[2] == 'E') { /* 8chan */ 2134 if (instance->chan_ck < 8) instance->chan_ck = 8; 2135 } else if (buf[2] == 'H') { /* 12chan */ 2136 if (instance->chan_ck < 12) instance->chan_ck = 12; 2137 } 2138 2139 if (instance->count3++ < 5) 2140 return; 2141 2142 instance->count3 = 0; 2143 2144 if (instance->chan_in != -1) /* set in Input */ 2145 instance->chan = instance->chan_in; 2146 else /* set from test */ 2147 instance->chan = instance->chan_ck; 2148 2149 oncore_log_f(instance, LOG_INFO, "Input says chan = %d", 2150 instance->chan_in); 2151 oncore_log_f(instance, LOG_INFO, "Model # says chan = %d", 2152 instance->chan_id); 2153 oncore_log_f(instance, LOG_INFO, "Testing says chan = %d", 2154 instance->chan_ck); 2155 oncore_log_f(instance, LOG_INFO, "Using chan = %d", 2156 instance->chan); 2157 2158 instance->o_state = ONCORE_HAVE_CHAN; 2159 oncore_log(instance, LOG_NOTICE, "state = ONCORE_HAVE_CHAN"); 2160 2161 instance->timeout = 4; 2162 oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 2163 return; 2164 } 2165 2166 if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN) 2167 return; 2168 2169 /* PAUSE 5sec - make sure results are stable, before using position */ 2170 2171 if (instance->count) { 2172 if (instance->count++ < 5) 2173 return; 2174 instance->count = 0; 2175 } 2176 2177 memcpy(instance->BEHa, buf, (size_t) (len+3)); /* Ba, Ea or Ha */ 2178 2179 /* check if we saw a response to Gc (M12 or M12+T */ 2180 2181 if (instance->pps_control_msg_seen != -2) { 2182 if ((instance->pps_control_msg_seen == -1) && (instance->pps_control != -1)) { 2183 oncore_log(instance, LOG_INFO, "PPSCONTROL set, but not implemented (not M12)"); 2184 } 2185 instance->pps_control_msg_seen = -2; 2186 } 2187 2188 /* check the antenna (did it get unplugged) and almanac (is it ready) for changes. */ 2189 2190 oncore_check_almanac(instance); 2191 oncore_check_antenna(instance); 2192 2193 /* If we are in Almanac mode, waiting for Almanac, we can't do anything till we have it */ 2194 /* When we have an almanac, we will start the Bn/En/@@Hn messages */ 2195 2196 if (instance->o_state == ONCORE_ALMANAC) 2197 if (oncore_wait_almanac(instance)) 2198 return; 2199 2200 /* do some things once when we get this far in BaEaHa */ 2201 2202 if (instance->once) { 2203 instance->once = 0; 2204 instance->count2 = 1; 2205 2206 /* Have we seen an @@At (position hold) command response */ 2207 /* if not, message out */ 2208 2209 if (instance->chan != 12 && !instance->saw_At) { 2210 oncore_log(instance, LOG_NOTICE, 2211 "Not Good, no @@At command (no Position Hold), must be a GT/GT+"); 2212 oncore_sendmsg(instance, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); 2213 } 2214 2215 /* have an Almanac, can start the SiteSurvey 2216 * (actually only need to get past the almanac_load where we diddle with At 2217 * command,- we can't change it after we start the HW_SS below 2218 */ 2219 2220 mode = instance->init_type; 2221 switch (mode) { 2222 case 0: /* NO initialization, don't change anything */ 2223 case 1: /* Use given Position */ 2224 case 3: 2225 instance->site_survey = ONCORE_SS_DONE; 2226 oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_DONE"); 2227 break; 2228 2229 case 2: 2230 case 4: /* Site Survey */ 2231 oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_TESTING"); 2232 instance->site_survey = ONCORE_SS_TESTING; 2233 instance->count1 = 1; 2234 if (instance->chan == 12) 2235 oncore_sendmsg(instance, oncore_cmd_Gd3, sizeof(oncore_cmd_Gd3)); /* M12+T */ 2236 else 2237 oncore_sendmsg(instance, oncore_cmd_At2, sizeof(oncore_cmd_At2)); /* not GT, arg not VP */ 2238 break; 2239 } 2240 2241 /* Read back PPS Offset for Output */ 2242 /* Nb. This will fail silently for early UT (no plus) and M12 models */ 2243 2244 oncore_sendmsg(instance, oncore_cmd_Ayx, sizeof(oncore_cmd_Ayx)); 2245 2246 /* Read back Cable Delay for Output */ 2247 2248 oncore_sendmsg(instance, oncore_cmd_Azx, sizeof(oncore_cmd_Azx)); 2249 2250 /* Read back Satellite Mask Angle for Output */ 2251 2252 oncore_sendmsg(instance, oncore_cmd_Agx, sizeof(oncore_cmd_Agx)); 2253 } 2254 2255 2256 /* Unfortunately, the Gd3 command returns '3' for the M12 v1.3 firmware where it is 2257 * out-of-range and it should return 0-2. (v1.3 can't do a HW Site Survey) 2258 * We must do the Gd3, and then wait a cycle or two for things to settle, 2259 * then check Ha[130]&0x10 to see if a SS is in progress. 2260 * We will set SW if HW has not been set after an appropriate delay. 2261 */ 2262 2263 if (instance->site_survey == ONCORE_SS_TESTING) { 2264 if (instance->chan == 12) { 2265 if (instance->count1) { 2266 if (instance->count1++ > 5 || instance->BEHa[130]&0x10) { 2267 instance->count1 = 0; 2268 if (instance->BEHa[130]&0x10) { 2269 oncore_log(instance, LOG_NOTICE, 2270 "Initiating hardware 3D site survey"); 2271 2272 oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_HW"); 2273 instance->site_survey = ONCORE_SS_HW; 2274 } else { 2275 oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_SW"); 2276 instance->site_survey = ONCORE_SS_SW; 2277 } 2278 } 2279 } 2280 } else { 2281 if (instance->count1) { 2282 if (instance->count1++ > 5) { 2283 instance->count1 = 0; 2284 /* 2285 * For instance->site_survey to still be ONCORE_SS_TESTING, then after a 5sec 2286 * wait after the @@At2/@@Gd3 command we have not changed the state to 2287 * ONCORE_SS_HW. If the Hardware is capable of doing a Site Survey, then 2288 * the variable would have been changed by now. 2289 * There are three possibilities: 2290 * 6/8chan 2291 * (a) We did not get a response to the @@At0 or @@At2 commands, 2292 * and it must be a GT/GT+/SL with no position hold mode. 2293 * We will have to do it ourselves. 2294 * (b) We saw the @@At0, @@At2 commands, but @@At2 failed, 2295 * must be a VP or older UT which doesn't have Site Survey mode. 2296 * We will have to do it ourselves. 2297 * 12chan 2298 * (c) We saw the @@Gd command, and saw H[13]*0x10 2299 * We will have to do it ourselves (done above) 2300 */ 2301 2302 oncore_log_f(instance, LOG_INFO, 2303 "Initiating software 3D site survey (%d samples)", 2304 POS_HOLD_AVERAGE); 2305 2306 oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_SW"); 2307 instance->site_survey = ONCORE_SS_SW; 2308 2309 instance->ss_lat = instance->ss_long = instance->ss_ht = 0; 2310 if (instance->chan == 12) 2311 oncore_sendmsg(instance, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* disable */ 2312 else { 2313 oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* disable */ 2314 oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* disable */ 2315 } 2316 } 2317 } 2318 } 2319 } 2320 2321 /* check the mode we are in 0/2/3D */ 2322 2323 if (instance->chan == 6) { 2324 if (instance->BEHa[64]&0x8) 2325 instance->mode = MODE_0D; 2326 else if (instance->BEHa[64]&0x10) 2327 instance->mode = MODE_2D; 2328 else if (instance->BEHa[64]&0x20) 2329 instance->mode = MODE_3D; 2330 } else if (instance->chan == 8) { 2331 if (instance->BEHa[72]&0x8) 2332 instance->mode = MODE_0D; 2333 else if (instance->BEHa[72]&0x10) 2334 instance->mode = MODE_2D; 2335 else if (instance->BEHa[72]&0x20) 2336 instance->mode = MODE_3D; 2337 } else if (instance->chan == 12) { 2338 int bits; 2339 2340 bits = (instance->BEHa[129]>>5) & 0x7; /* actually Ha */ 2341 if (bits == 0x4) 2342 instance->mode = MODE_0D; 2343 else if (bits == 0x6) 2344 instance->mode = MODE_2D; 2345 else if (bits == 0x7) 2346 instance->mode = MODE_3D; 2347 } 2348 2349 /* copy the record to the (extra) location in SHMEM */ 2350 2351 if (instance->shmem) { 2352 int i; 2353 u_char *smp; /* pointer to start of shared mem for Ba/Ea/Ha */ 2354 2355 switch(instance->chan) { 2356 case 6: smp = &instance->shmem[instance->shmem_Ba]; break; 2357 case 8: smp = &instance->shmem[instance->shmem_Ea]; break; 2358 case 12: smp = &instance->shmem[instance->shmem_Ha]; break; 2359 default: smp = (u_char *) NULL; break; 2360 } 2361 2362 switch (instance->mode) { 2363 case MODE_0D: i = 1; break; /* 0D, Position Hold */ 2364 case MODE_2D: i = 2; break; /* 2D, Altitude Hold */ 2365 case MODE_3D: i = 3; break; /* 3D fix */ 2366 default: i = 0; break; 2367 } 2368 2369 if (i && smp != NULL) { 2370 i *= (len+6); 2371 smp[i + 2]++; 2372 memcpy(&smp[i+3], buf, (size_t) (len+3)); 2373 } 2374 } 2375 2376 /* 2377 * check if traim timer active 2378 * if it hasn't been cleared, then @@Bn/@@En/@@Hn did not respond 2379 */ 2380 2381 if (instance->traim_delay) { 2382 if (instance->traim_delay++ > 5) { 2383 instance->traim = 0; 2384 instance->traim_delay = 0; 2385 cp = "ONCORE: Did not detect TRAIM response, TRAIM = OFF"; 2386 oncore_log(instance, LOG_INFO, cp); 2387 2388 oncore_set_traim(instance); 2389 } else 2390 return; 2391 2392 } 2393 2394 /* by now should have a @@Ba/@@Ea/@@Ha with good data in it */ 2395 2396 if (!instance->have_dH && !instance->traim_delay) 2397 oncore_compute_dH(instance); 2398 2399 /* 2400 * must be ONCORE_RUN if we are here. 2401 * Have # chan and TRAIM by now. 2402 */ 2403 2404 instance->pp->year = buf[6]*256+buf[7]; 2405 instance->pp->day = ymd2yd(buf[6]*256+buf[7], buf[4], buf[5]); 2406 instance->pp->hour = buf[8]; 2407 instance->pp->minute = buf[9]; 2408 instance->pp->second = buf[10]; 2409 2410 /* 2411 * Are we doing a Hardware or Software Site Survey? 2412 */ 2413 2414 if (instance->site_survey == ONCORE_SS_HW || instance->site_survey == ONCORE_SS_SW) 2415 oncore_ss(instance); 2416 2417 /* see if we ever saw a response from the @@Ayx above */ 2418 2419 if (instance->count2) { 2420 if (instance->count2++ > 5) { /* this delay to check on @@Ay command */ 2421 instance->count2 = 0; 2422 2423 /* Have we seen an Ay (1PPS time offset) command response */ 2424 /* if not, and non-zero offset, zero the offset, and send message */ 2425 2426 if (!instance->saw_Ay && instance->offset) { 2427 oncore_log(instance, LOG_INFO, "No @@Ay command, PPS OFFSET ignored"); 2428 instance->offset = 0; 2429 } 2430 } 2431 } 2432 2433 /* 2434 * Check the leap second status once per day. 2435 */ 2436 2437 oncore_check_leap_sec(instance); 2438 2439 /* 2440 * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn. 2441 */ 2442 2443 if (instance->shmem && !instance->shmem_bad_Ea && instance->shmem_Posn && (instance->site_survey == ONCORE_SS_DONE)) 2444 oncore_shmem_get_3D(instance); 2445 2446 if (!instance->traim) /* NO traim, no BnEnHn, go get tick */ 2447 oncore_get_timestamp(instance, instance->offset, instance->offset); 2448 } 2449 2450 2451 2452 /* Almanac Status */ 2453 2454 static void 2455 oncore_msg_Bd( 2456 struct instance *instance, 2457 u_char *buf, 2458 size_t len 2459 ) 2460 { 2461 oncore_log_f(instance, LOG_NOTICE, 2462 "Bd: Almanac %s, week = %d, t = %d, %d SVs: %x", 2463 ((buf[4]) ? "LOADED" : "(NONE)"), buf[5], buf[6], 2464 buf[7], w32(&buf[8])); 2465 } 2466 2467 2468 2469 /* get leap-second warning message */ 2470 2471 /* 2472 * @@Bj does NOT behave as documented in current Oncore firmware. 2473 * It turns on the LEAP indicator when the data is set, and does not, 2474 * as documented, wait until the beginning of the month when the 2475 * leap second will occur. 2476 * Since this firmware bug will never be fixed in all the outstanding Oncore receivers 2477 * @@Bj is only called in June/December. 2478 */ 2479 2480 static void 2481 oncore_msg_Bj( 2482 struct instance *instance, 2483 u_char *buf, 2484 size_t len 2485 ) 2486 { 2487 const char *cp; 2488 2489 instance->saw_Bj = 1; 2490 2491 switch(buf[4]) { 2492 case 1: 2493 instance->pp->leap = LEAP_ADDSECOND; 2494 cp = "Set pp.leap to LEAP_ADDSECOND"; 2495 break; 2496 case 2: 2497 instance->pp->leap = LEAP_DELSECOND; 2498 cp = "Set pp.leap to LEAP_DELSECOND"; 2499 break; 2500 case 0: 2501 default: 2502 instance->pp->leap = LEAP_NOWARNING; 2503 cp = "Set pp.leap to LEAP_NOWARNING"; 2504 break; 2505 } 2506 oncore_log(instance, LOG_NOTICE, cp); 2507 } 2508 2509 2510 2511 static void 2512 oncore_msg_Bl( 2513 struct instance *instance, 2514 u_char *buf, 2515 size_t len 2516 ) 2517 { 2518 int subframe, valid, page, i, j, tow; 2519 int day_now, day_lsf; 2520 const char *cp; 2521 enum { 2522 WARN_NOT_YET, 2523 WARN_0, 2524 WARN_PLUS, 2525 WARN_MINUS 2526 } warn; 2527 2528 2529 subframe = buf[6] & 017; 2530 valid = (buf[6] >> 4) & 017; 2531 page = buf[7]; 2532 2533 if ((!instance->Bl.lsf_flg && !instance->Bl.wn_flg) && (subframe == 4 && page == 18 && valid == 10)) { 2534 instance->Bl.dt_ls = buf[32]; 2535 instance->Bl.WN_lsf = buf[33]; 2536 instance->Bl.DN_lsf = buf[34]; 2537 instance->Bl.dt_lsf = buf[35]; 2538 instance->Bl.lsf_flg++; 2539 } 2540 if ((instance->Bl.lsf_flg && !instance->Bl.wn_flg) && (subframe == 1 && valid == 10)) { 2541 i = (buf[7+7]<<8) + buf[7+8]; 2542 instance->Bl.WN = i >> 6; 2543 tow = (buf[7+4]<<16) + (buf[7+5]<<8) + buf[7+6]; 2544 tow >>= 7; 2545 tow = tow & 0377777; 2546 tow <<= 2; 2547 instance->Bl.DN = tow/57600L + 1; 2548 instance->Bl.wn_flg++; 2549 } 2550 if (instance->Bl.wn_flg && instance->Bl.lsf_flg) { 2551 instance->Bl.wn_flg = instance->Bl.lsf_flg = 0; 2552 oncore_cmd_Bl[2] = 0; 2553 oncore_sendmsg(instance, oncore_cmd_Bl, sizeof oncore_cmd_Bl); 2554 oncore_cmd_Bl[2] = 1; 2555 2556 i = instance->Bl.WN&01400; 2557 instance->Bl.WN_lsf |= i; 2558 2559 /* have everything I need, doit */ 2560 2561 i = (instance->Bl.WN_lsf - instance->Bl.WN); 2562 if (i < 0) 2563 i += 1024; 2564 day_now = instance->Bl.DN; 2565 day_lsf = 7*i + instance->Bl.DN_lsf; 2566 2567 /* ignore if in past or more than a month in future */ 2568 2569 warn = WARN_NOT_YET; 2570 if (day_lsf >= day_now && day_lsf - day_now < 32) { 2571 /* if < 28d, doit, if 28-31, ck day-of-month < 20 (not at end of prev month) */ 2572 if (day_lsf - day_now < 28 || instance->BEHa[5] < 20) { 2573 i = instance->Bl.dt_lsf - instance->Bl.dt_ls; 2574 switch (i) { 2575 case -1: 2576 warn = WARN_MINUS; 2577 break; 2578 case 0: 2579 warn = WARN_0; 2580 break; 2581 case 1: 2582 warn = WARN_PLUS; 2583 break; 2584 } 2585 } 2586 } 2587 2588 switch (warn) { 2589 case WARN_0: 2590 case WARN_NOT_YET: 2591 instance->peer->leap = LEAP_NOWARNING; 2592 cp = "Set peer.leap to LEAP_NOWARNING"; 2593 break; 2594 case WARN_MINUS: 2595 instance->peer->leap = LEAP_DELSECOND; 2596 cp = "Set peer.leap to LEAP_DELSECOND"; 2597 break; 2598 case WARN_PLUS: 2599 instance->peer->leap = LEAP_ADDSECOND; 2600 cp = "Set peer.leap to LEAP_ADDSECOND"; 2601 break; 2602 default: 2603 cp = NULL; 2604 break; 2605 } 2606 oncore_log(instance, LOG_NOTICE, cp); 2607 2608 i = instance->Bl.dt_lsf-instance->Bl.dt_ls; 2609 if (i) { 2610 j = (i >= 0) ? i : -i; /* abs(i) */ 2611 oncore_log_f(instance, LOG_NOTICE, 2612 "see Leap_Second (%c%d) in %d days", 2613 ((i >= 0) ? '+' : '-'), j, 2614 day_lsf-day_now); 2615 } 2616 } 2617 2618 /* 2619 * Reg only wants the following output for "deeper" driver debugging. 2620 * See Bug 2142 and Bug 1866 2621 */ 2622 #if 0 2623 oncore_log_f(instance, LOG_DEBUG, 2624 "dt_ls = %d dt_lsf = %d WN = %d DN = %d WN_lsf = %d DNlsf = %d wn_flg = %d lsf_flg = %d Bl_day = %d", 2625 instance->Bl.dt_ls, instance->Bl.dt_lsf, 2626 instance->Bl.WN, instance->Bl.DN, 2627 instance->Bl.WN_lsf, instance->Bl.DN_lsf, 2628 instance->Bl.wn_flg, instance->Bl.lsf_flg, 2629 instance->Bl.Bl_day); 2630 #endif 2631 } 2632 2633 2634 static void 2635 oncore_msg_BnEnHn( 2636 struct instance *instance, 2637 u_char *buf, 2638 size_t len 2639 ) 2640 { 2641 long dt1, dt2; 2642 2643 if (instance->o_state != ONCORE_RUN) 2644 return; 2645 2646 if (instance->traim_delay) { /* flag that @@Bn/@@En/Hn returned */ 2647 instance->traim_ck = 1; 2648 instance->traim_delay = 0; 2649 oncore_log(instance, LOG_NOTICE, "ONCORE: Detected TRAIM, TRAIM = ON"); 2650 2651 oncore_set_traim(instance); 2652 } 2653 2654 memcpy(instance->BEHn, buf, (size_t) len); /* Bn or En or Hn */ 2655 2656 if (!instance->traim) /* BnEnHn will be turned off in any case */ 2657 return; 2658 2659 /* If Time RAIM doesn't like it, don't trust it */ 2660 2661 if (buf[2] == 'H') { 2662 if (instance->BEHn[6]) { /* bad TRAIM */ 2663 oncore_log(instance, LOG_WARNING, "BAD TRAIM"); 2664 return; 2665 } 2666 2667 dt1 = instance->saw_tooth + instance->offset; /* dt this time step */ 2668 instance->saw_tooth = (s_char) instance->BEHn[14]; /* update for next time Hn[14] */ 2669 dt2 = instance->saw_tooth + instance->offset; /* dt next time step */ 2670 } else { 2671 if (instance->BEHn[21]) /* bad TRAIM */ 2672 return; 2673 2674 dt1 = instance->saw_tooth + instance->offset; /* dt this time step */ 2675 instance->saw_tooth = (s_char) instance->BEHn[25]; /* update for next time Bn[25], En[25] */ 2676 dt2 = instance->saw_tooth + instance->offset; /* dt next time step */ 2677 } 2678 2679 oncore_get_timestamp(instance, dt1, dt2); 2680 } 2681 2682 2683 2684 /* Here for @@Ca, @@Fa and @@Ia messages */ 2685 2686 /* These are Self test Commands for 6, 8, and 12 chan receivers. 2687 * There are good reasons NOT to do a @@Ca, @@Fa or @@Ia command with the ONCORE. 2688 * It was found that under some circumstances the following 2689 * command would fail if issued immediately after the return from the 2690 * @@Fa, but a 2sec delay seemed to fix things. Since simply calling 2691 * sleep(2) is wasteful, and may cause trouble for some OS's, repeating 2692 * itimer, we set a flag, and test it at the next POLL. If it hasn't 2693 * been cleared, we reissue the @@Cj that is issued below. 2694 * Note that we do a @@Cj at the beginning, and again here. 2695 * The first is to get the info, the 2nd is just used as a safe command 2696 * after the @@Fa for all Oncores (and it was in this posn in the 2697 * original code). 2698 */ 2699 2700 static void 2701 oncore_msg_CaFaIa( 2702 struct instance *instance, 2703 u_char *buf, 2704 size_t len 2705 ) 2706 { 2707 int i; 2708 2709 if (instance->o_state == ONCORE_TEST_SENT) { 2710 enum antenna_state antenna; 2711 2712 instance->timeout = 0; 2713 2714 #if ONCORE_VERBOSE_SELF_TEST 2715 if (debug > 2) { 2716 if (buf[2] == 'I') 2717 oncore_log_f(instance, LOG_DEBUG, 2718 ">>@@%ca %x %x %x", buf[2], 2719 buf[4], buf[5], buf[6]); 2720 else 2721 oncore_log_f(instance, LOG_DEBUG, 2722 ">>@@%ca %x %x", buf[2], 2723 buf[4], buf[5]); 2724 } 2725 #endif 2726 2727 antenna = (buf[4] & 0xc0) >> 6; 2728 buf[4] &= ~0xc0; 2729 2730 i = buf[4] || buf[5]; 2731 if (buf[2] == 'I') i = i || buf[6]; 2732 if (i) { 2733 if (buf[2] == 'I') 2734 oncore_log_f(instance, LOG_ERR, 2735 "self test failed: result %02x %02x %02x", 2736 buf[4], buf[5], buf[6]); 2737 else 2738 oncore_log_f(instance, LOG_ERR, 2739 "self test failed: result %02x %02x", 2740 buf[4], buf[5]); 2741 2742 oncore_log(instance, LOG_ERR, 2743 "ONCORE: self test failed, shutting down driver"); 2744 2745 refclock_report(instance->peer, CEVNT_FAULT); 2746 oncore_shutdown(instance->unit, instance->peer); 2747 return; 2748 } 2749 2750 /* report the current antenna state */ 2751 2752 oncore_antenna_report(instance, antenna); 2753 2754 instance->o_state = ONCORE_INIT; 2755 oncore_log(instance, LOG_NOTICE, "state = ONCORE_INIT"); 2756 2757 instance->timeout = 4; 2758 oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 2759 } 2760 } 2761 2762 2763 2764 /* 2765 * Demultiplex the almanac into shmem 2766 */ 2767 2768 static void 2769 oncore_msg_Cb( 2770 struct instance *instance, 2771 u_char *buf, 2772 size_t len 2773 ) 2774 { 2775 int i; 2776 2777 if (instance->shmem == NULL) 2778 return; 2779 2780 if (buf[4] == 5 && buf[5] > 0 && buf[5] < 26) 2781 i = buf[5]; 2782 else if (buf[4] == 4 && buf[5] <= 5) 2783 i = buf[5] + 24; 2784 else if (buf[4] == 4 && buf[5] <= 10) 2785 i = buf[5] + 23; 2786 else if (buf[4] == 4 && buf[5] == 25) 2787 i = 34; 2788 else { 2789 oncore_log(instance, LOG_NOTICE, "Cb: Response is NO ALMANAC"); 2790 return; 2791 } 2792 2793 i *= 36; 2794 instance->shmem[instance->shmem_Cb + i + 2]++; 2795 memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3)); 2796 2797 #ifdef ONCORE_VERBOSE_MSG_CB 2798 oncore_log_f(instance, LOG_DEBUG, "See Cb [%d,%d]", buf[4], 2799 buf[5]); 2800 #endif 2801 } 2802 2803 2804 2805 /* 2806 * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup 2807 * not so for VP (eeprom) or any unit with a battery 2808 */ 2809 2810 static void 2811 oncore_msg_Cf( 2812 struct instance *instance, 2813 u_char *buf, 2814 size_t len 2815 ) 2816 { 2817 if (instance->o_state == ONCORE_RESET_SENT) { 2818 oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */ 2819 /* Reset set VP to IDLE */ 2820 instance->o_state = ONCORE_TEST_SENT; 2821 oncore_log(instance, LOG_NOTICE, "state = ONCORE_TEST_SENT"); 2822 2823 oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 2824 } 2825 } 2826 2827 2828 2829 /* 2830 * This is the Grand Central Station for the Preliminary Initialization. 2831 * Once done here we move on to oncore_msg_BaEaHa for final Initialization and Running. 2832 * 2833 * We do an @@Cj whenever we need a safe command for all Oncores. 2834 * The @@Cj gets us back here where we can switch to the next phase of setup. 2835 * 2836 * o Once at the very beginning (in start) to get the Model number. 2837 * This info is printed, but no longer used. 2838 * o Again after we have determined the number of Channels in the receiver. 2839 * o And once later after we have done a reset and test, (which may hang), 2840 * as we are about to initialize the Oncore and start it running. 2841 * o We have one routine below for each case. 2842 */ 2843 2844 static void 2845 oncore_msg_Cj( 2846 struct instance *instance, 2847 u_char *buf, 2848 size_t len 2849 ) 2850 { 2851 int mode; 2852 2853 memcpy(instance->Cj, buf, len); 2854 2855 instance->timeout = 0; 2856 if (instance->o_state == ONCORE_CHECK_ID) { 2857 oncore_msg_Cj_id(instance, buf, len); 2858 oncore_chan_test(instance); 2859 } else if (instance->o_state == ONCORE_HAVE_CHAN) { 2860 mode = instance->init_type; 2861 if (mode == 3 || mode == 4) { /* Cf will return here to check for TEST */ 2862 instance->o_state = ONCORE_RESET_SENT; 2863 oncore_log(instance, LOG_NOTICE, "state = ONCORE_RESET_SENT"); 2864 oncore_sendmsg(instance, oncore_cmd_Cf, sizeof(oncore_cmd_Cf)); 2865 } else { 2866 instance->o_state = ONCORE_TEST_SENT; 2867 oncore_log(instance, LOG_NOTICE, "state = ONCORE_TEST_SENT"); 2868 } 2869 } 2870 2871 if (instance->o_state == ONCORE_TEST_SENT) { 2872 if (instance->chan == 6) 2873 oncore_sendmsg(instance, oncore_cmd_Ca, sizeof(oncore_cmd_Ca)); 2874 else if (instance->chan == 8) 2875 oncore_sendmsg(instance, oncore_cmd_Fa, sizeof(oncore_cmd_Fa)); 2876 else if (instance->chan == 12) 2877 oncore_sendmsg(instance, oncore_cmd_Ia, sizeof(oncore_cmd_Ia)); 2878 } else if (instance->o_state == ONCORE_INIT) 2879 oncore_msg_Cj_init(instance, buf, len); 2880 } 2881 2882 2883 2884 /* The information on determining a Oncore 'Model', viz VP, UT, etc, from 2885 * the Model Number comes from "Richard M. Hambly" <rick@cnssys.com> 2886 * and from Motorola. Until recently Rick was the only source of 2887 * this information as Motorola didn't give the information out. 2888 * 2889 * Determine the Type from the Model #, this determines #chan and if TRAIM is 2890 * available. 2891 * 2892 * The Information from this routine is NO LONGER USED. 2893 * The RESULTS are PRINTED, BUT NOT USED, and the routine COULD BE DELETED 2894 */ 2895 2896 static void 2897 oncore_msg_Cj_id( 2898 struct instance *instance, 2899 u_char *buf, 2900 size_t len 2901 ) 2902 { 2903 char *cp2, Model[21]; 2904 const char *cp, *cp1; 2905 2906 /* Write Receiver ID message to clockstats file */ 2907 2908 instance->Cj[294] = '\0'; 2909 for (cp= (char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) { 2910 char *cpw = strchr(cp, '\r'); 2911 if (!cpw) 2912 cpw = (char *)&instance->Cj[294]; 2913 *cpw = '\0'; 2914 oncore_log(instance, LOG_NOTICE, cp); 2915 *cpw = '\r'; 2916 cp = cpw+2; 2917 } 2918 2919 /* next, the Firmware Version and Revision numbers */ 2920 2921 instance->version = atoi((char *) &instance->Cj[83]); 2922 instance->revision = atoi((char *) &instance->Cj[111]); 2923 2924 /* from model number decide which Oncore this is, 2925 and then the number of channels */ 2926 2927 for (cp= (char *) &instance->Cj[160]; *cp == ' '; cp++) /* start right after 'Model #' */ 2928 ; 2929 cp1 = cp; 2930 cp2 = Model; 2931 for (; !isspace((unsigned char)*cp) && cp-cp1 < 20; cp++, cp2++) 2932 *cp2 = *cp; 2933 *cp2 = '\0'; 2934 2935 cp = 0; 2936 if (!strncmp(Model, "PVT6", (size_t) 4)) { 2937 cp = "PVT6"; 2938 instance->model = ONCORE_PVT6; 2939 } else if (Model[0] == 'A') { 2940 cp = "Basic"; 2941 instance->model = ONCORE_BASIC; 2942 } else if (Model[0] == 'B' || !strncmp(Model, "T8", (size_t) 2)) { 2943 cp = "VP"; 2944 instance->model = ONCORE_VP; 2945 } else if (Model[0] == 'P') { 2946 cp = "M12"; 2947 instance->model = ONCORE_M12; 2948 } else if (Model[0] == 'R' || Model[0] == 'D' || Model[0] == 'S') { 2949 if (Model[5] == 'N') { 2950 cp = "GT"; 2951 instance->model = ONCORE_GT; 2952 } else if ((Model[1] == '3' || Model[1] == '4') && Model[5] == 'G') { 2953 cp = "GT+"; 2954 instance->model = ONCORE_GTPLUS; 2955 } else if ((Model[1] == '5' && Model[5] == 'U') || (Model[1] == '1' && Model[5] == 'A')) { 2956 cp = "UT"; 2957 instance->model = ONCORE_UT; 2958 } else if (Model[1] == '5' && Model[5] == 'G') { 2959 cp = "UT+"; 2960 instance->model = ONCORE_UTPLUS; 2961 } else if (Model[1] == '6' && Model[5] == 'G') { 2962 cp = "SL"; 2963 instance->model = ONCORE_SL; 2964 } else { 2965 cp = "Unknown"; 2966 instance->model = ONCORE_UNKNOWN; 2967 } 2968 } else { 2969 cp = "Unknown"; 2970 instance->model = ONCORE_UNKNOWN; 2971 } 2972 2973 /* use MODEL to set CHAN and TRAIM and possibly zero SHMEM */ 2974 2975 oncore_log_f(instance, LOG_INFO, 2976 "This looks like an Oncore %s with version %d.%d firmware.", 2977 cp, instance->version, instance->revision); 2978 2979 instance->chan_id = 8; /* default */ 2980 if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6) 2981 instance->chan_id = 6; 2982 else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS) 2983 instance->chan_id = 8; 2984 else if (instance->model == ONCORE_M12) 2985 instance->chan_id = 12; 2986 2987 instance->traim_id = 0; /* default */ 2988 if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6) 2989 instance->traim_id = 0; 2990 else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS) 2991 instance->traim_id = 1; 2992 else if (instance->model == ONCORE_M12) 2993 instance->traim_id = -1; 2994 2995 oncore_log_f(instance, LOG_INFO, "Channels = %d, TRAIM = %s", 2996 instance->chan_id, 2997 ((instance->traim_id < 0) 2998 ? "UNKNOWN" 2999 : (instance->traim_id > 0) 3000 ? "ON" 3001 : "OFF")); 3002 } 3003 3004 3005 3006 /* OK, know type of Oncore, have possibly reset it, and have tested it. 3007 * We know the number of channels. 3008 * We will determine whether we have TRAIM before we actually start. 3009 * Now initialize. 3010 */ 3011 3012 static void 3013 oncore_msg_Cj_init( 3014 struct instance *instance, 3015 u_char *buf, 3016 size_t len 3017 ) 3018 { 3019 u_char Cmd[20]; 3020 int mode; 3021 3022 3023 /* The M12 with 1.3 or 2.0 Firmware, loses track of all Satellites and has to 3024 * start again if we go from 0D -> 3D, then loses them again when we 3025 * go from 3D -> 0D. We do this to get a @@Ea message for SHMEM. 3026 * For NOW we will turn this aspect of filling SHMEM off for the M12 3027 */ 3028 3029 if (instance->chan == 12) { 3030 instance->shmem_bad_Ea = 1; 3031 oncore_log_f(instance, LOG_NOTICE, 3032 "*** SHMEM partially enabled for ONCORE M12 s/w v%d.%d ***", 3033 instance->version, instance->revision); 3034 } 3035 3036 oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */ 3037 oncore_sendmsg(instance, oncore_cmd_Bb, sizeof(oncore_cmd_Bb)); /* turn on for shmem (6/8/12) */ 3038 oncore_sendmsg(instance, oncore_cmd_Ek, sizeof(oncore_cmd_Ek)); /* turn off (VP) */ 3039 oncore_sendmsg(instance, oncore_cmd_Aw, sizeof(oncore_cmd_Aw)); /* UTC time (6/8/12) */ 3040 oncore_sendmsg(instance, oncore_cmd_AB, sizeof(oncore_cmd_AB)); /* Appl type static (VP) */ 3041 oncore_sendmsg(instance, oncore_cmd_Be, sizeof(oncore_cmd_Be)); /* Tell us the Almanac for shmem (6/8/12) */ 3042 oncore_sendmsg(instance, oncore_cmd_Bd, sizeof(oncore_cmd_Bd)); /* Tell us when Almanac changes */ 3043 3044 mode = instance->init_type; 3045 3046 /* If there is Position input in the Config file 3047 * and mode = (1,3) set it as posn hold posn, goto 0D mode. 3048 * or mode = (2,4) set it as INITIAL position, and do Site Survey. 3049 */ 3050 3051 if (instance->posn_set) { 3052 oncore_log(instance, LOG_INFO, "Setting Posn from input data"); 3053 oncore_set_posn(instance); /* this should print posn indirectly thru the As cmd */ 3054 } else /* must issue an @@At here to check on 6/8 Position Hold, set_posn would have */ 3055 if (instance->chan != 12) 3056 oncore_sendmsg(instance, oncore_cmd_Atx, sizeof(oncore_cmd_Atx)); 3057 3058 if (mode != 0) { 3059 /* cable delay in ns */ 3060 memcpy(Cmd, oncore_cmd_Az, (size_t) sizeof(oncore_cmd_Az)); 3061 w32_buf(&Cmd[-2+4], (int)instance->delay); 3062 oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Az)); /* 6,8,12 */ 3063 3064 /* PPS offset in ns */ 3065 memcpy(Cmd, oncore_cmd_Ay, (size_t) sizeof(oncore_cmd_Ay)); /* some have it, some don't */ 3066 w32_buf(&Cmd[-2+4], instance->offset); /* will check for hw response */ 3067 oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ay)); 3068 3069 /* Satellite mask angle */ 3070 3071 if (instance->Ag != 0xff) { /* will have 0xff in it if not set by user */ 3072 memcpy(Cmd, oncore_cmd_Ag, (size_t) sizeof(oncore_cmd_Ag)); 3073 Cmd[-2+4] = instance->Ag; 3074 oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ag)); 3075 } 3076 } 3077 3078 /* 6, 8 12 chan - Position/Status/Data Output Message, 1/s 3079 * now we're really running 3080 * these were ALL started in the chan test, 3081 * However, if we had mode=3,4 then commands got turned off, so we turn 3082 * them on again here just in case 3083 */ 3084 3085 if (instance->chan == 6) { /* start 6chan, kill 8,12chan commands, possibly testing VP in 6chan mode */ 3086 oncore_sendmsg(instance, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0)); 3087 oncore_sendmsg(instance, oncore_cmd_En0, sizeof(oncore_cmd_En0)); 3088 oncore_sendmsg(instance, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0)); 3089 oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0)); 3090 oncore_sendmsg(instance, oncore_cmd_Ba, sizeof(oncore_cmd_Ba )); 3091 } else if (instance->chan == 8) { /* start 8chan, kill 6,12chan commands */ 3092 oncore_sendmsg(instance, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0)); 3093 oncore_sendmsg(instance, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0)); 3094 oncore_sendmsg(instance, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0)); 3095 oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0)); 3096 oncore_sendmsg(instance, oncore_cmd_Ea, sizeof(oncore_cmd_Ea )); 3097 } else if (instance->chan == 12){ /* start 12chan, kill 6,12chan commands */ 3098 oncore_sendmsg(instance, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0)); 3099 oncore_sendmsg(instance, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0)); 3100 oncore_sendmsg(instance, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0)); 3101 oncore_sendmsg(instance, oncore_cmd_En0, sizeof(oncore_cmd_En0)); 3102 oncore_sendmsg(instance, oncore_cmd_Ha, sizeof(oncore_cmd_Ha )); 3103 oncore_cmd_Gc[2] = (instance->pps_control < 0) ? 1 : instance->pps_control; 3104 oncore_sendmsg(instance, oncore_cmd_Gc, sizeof(oncore_cmd_Gc)); /* PPS off/continuous/Tracking 1+sat/TRAIM */ 3105 } 3106 3107 instance->count = 1; 3108 instance->o_state = ONCORE_ALMANAC; 3109 oncore_log(instance, LOG_NOTICE, "state = ONCORE_ALMANAC"); 3110 } 3111 3112 3113 3114 /* 12chan position */ 3115 3116 static void 3117 oncore_msg_Ga( 3118 struct instance *instance, 3119 u_char *buf, 3120 size_t len 3121 ) 3122 { 3123 long lat, lon, ht; 3124 double Lat, Lon, Ht; 3125 3126 3127 lat = buf_w32(&buf[4]); 3128 lon = buf_w32(&buf[8]); 3129 ht = buf_w32(&buf[12]); /* GPS ellipsoid */ 3130 3131 Lat = lat; 3132 Lon = lon; 3133 Ht = ht; 3134 3135 Lat /= 3600000; 3136 Lon /= 3600000; 3137 Ht /= 100; 3138 3139 oncore_log_f(instance, LOG_NOTICE, 3140 "Ga Posn Lat = %.7f, Lon = %.7f, Ht = %.2f", Lat, 3141 Lon, Ht); 3142 3143 instance->ss_lat = lat; 3144 instance->ss_long = lon; 3145 instance->ss_ht = ht; 3146 3147 oncore_print_posn(instance); 3148 } 3149 3150 3151 3152 /* 12 chan time/date */ 3153 3154 static void 3155 oncore_msg_Gb( 3156 struct instance *instance, 3157 u_char *buf, 3158 size_t len 3159 ) 3160 { 3161 const char * gmts; 3162 int mo, d, y, h, m, s, gmth, gmtm; 3163 3164 mo = buf[4]; 3165 d = buf[5]; 3166 y = 256*buf[6]+buf[7]; 3167 3168 h = buf[8]; 3169 m = buf[9]; 3170 s = buf[10]; 3171 3172 gmts = ((buf[11] == 0) ? "+" : "-"); 3173 gmth = buf[12]; 3174 gmtm = buf[13]; 3175 3176 oncore_log_f(instance, LOG_NOTICE, 3177 "Date/Time set to: %d%s%d %2d:%02d:%02d GMT (GMT offset is %s%02d:%02d)", 3178 d, months[mo-1], y, h, m, s, gmts, gmth, gmtm); 3179 } 3180 3181 3182 3183 /* Response to PPS Control message (M12 and M12+T only ) */ 3184 3185 static void 3186 oncore_msg_Gc( 3187 struct instance *instance, 3188 u_char *buf, 3189 size_t len 3190 ) 3191 { 3192 const char *tbl[] = {"OFF", "ON", "SATELLITE", "TRAIM" }; 3193 3194 instance->pps_control_msg_seen = 1; 3195 oncore_log_f(instance, LOG_INFO, "PPS Control set to %s", 3196 tbl[buf[4]]); 3197 } 3198 3199 3200 3201 /* Leap Second for M12, gives all info from satellite message */ 3202 /* also in UT v3.0 */ 3203 3204 static void 3205 oncore_msg_Gj( 3206 struct instance *instance, 3207 u_char *buf, 3208 size_t len 3209 ) 3210 { 3211 static const char * insrem[2] = { 3212 "removed", 3213 "inserted" 3214 }; 3215 3216 int dt; 3217 const char *cp; 3218 3219 instance->saw_Gj = 1; /* flag, saw_Gj, dont need to try Bj in check_leap */ 3220 3221 /* print the message to verify whats there */ 3222 3223 dt = buf[5] - buf[4]; 3224 3225 oncore_log_f(instance, LOG_INFO, 3226 "Leap Sec Msg: %d %d %d %d %d %d %d %d %d %d", 3227 buf[4], buf[5], 256 * buf[6] + buf[7], buf[8], 3228 buf[9], buf[10], 3229 (buf[14] + 256 * 3230 (buf[13] + 256 * (buf[12] + 256 * buf[11]))), 3231 buf[15], buf[16], buf[17]); 3232 3233 /* There seems to be eternal confusion about when a leap second 3234 * takes place. It's the second *before* the new TAI offset 3235 * becomes effective. But since the ONCORE receiver tells us 3236 * just that, we would have to do some time/date calculations to 3237 * get the actual leap second -- that is, the one that is 3238 * deleted or inserted. 3239 * 3240 * Going through all this for a simple log is probably overkill, 3241 * so for fixing bug#1050 the message output is changed to 3242 * reflect the fact that it tells the second after the leap 3243 * second. 3244 */ 3245 if (dt) 3246 oncore_log_f(instance, LOG_NOTICE, 3247 "Leap second %s (%d) before %04u-%02u-%02u/%02u:%02u:%02u", 3248 insrem[(dt > 0)], dt, 3249 256u * buf[6] + buf[7], buf[8], buf[9], 3250 buf[15], buf[16], buf[17]); 3251 3252 /* Only raise warning within a month of the leap second */ 3253 3254 instance->pp->leap = LEAP_NOWARNING; 3255 cp = "Set pp.leap to LEAP_NOWARNING"; 3256 3257 if (buf[6] == instance->BEHa[6] && buf[7] == instance->BEHa[7] && /* year */ 3258 buf[8] == instance->BEHa[4]) { /* month */ 3259 if (dt) { 3260 if (dt < 0) { 3261 instance->pp->leap = LEAP_DELSECOND; 3262 cp = "Set pp.leap to LEAP_DELSECOND"; 3263 } else { 3264 instance->pp->leap = LEAP_ADDSECOND; 3265 cp = "Set pp.leap to LEAP_ADDSECOND"; 3266 } 3267 } 3268 } 3269 oncore_log(instance, LOG_INFO, cp); 3270 } 3271 3272 3273 3274 /* Power on failure */ 3275 3276 static void 3277 oncore_msg_Sz( 3278 struct instance *instance, 3279 u_char *buf, 3280 size_t len 3281 ) 3282 { 3283 if (instance && instance->peer) { 3284 oncore_log(instance, LOG_ERR, "Oncore: System Failure at Power On"); 3285 oncore_shutdown(instance->unit, instance->peer); 3286 } 3287 } 3288 3289 /************** Small Subroutines ***************/ 3290 3291 3292 static void 3293 oncore_antenna_report( 3294 struct instance *instance, 3295 enum antenna_state new_state) 3296 { 3297 const char *cp; 3298 3299 if (instance->ant_state == new_state) 3300 return; 3301 3302 switch (new_state) { 3303 case ONCORE_ANTENNA_OK: cp = "GPS antenna: OK"; break; 3304 case ONCORE_ANTENNA_OC: cp = "GPS antenna: short (overcurrent)"; break; 3305 case ONCORE_ANTENNA_UC: cp = "GPS antenna: open (not connected)"; break; 3306 case ONCORE_ANTENNA_NV: cp = "GPS antenna: short (no voltage)"; break; 3307 default: cp = "GPS antenna: ?"; break; 3308 } 3309 3310 instance->ant_state = new_state; 3311 oncore_log(instance, LOG_NOTICE, cp); 3312 } 3313 3314 3315 3316 static void 3317 oncore_chan_test( 3318 struct instance *instance 3319 ) 3320 { 3321 /* subroutine oncore_Cj_id has determined the number of channels from the 3322 * model number of the attached oncore. This is not always correct since 3323 * the oncore could have non-standard firmware. Here we check (independently) by 3324 * trying a 6, 8, and 12 chan command, and see which responds. 3325 * Caution: more than one CAN respond. 3326 * 3327 * This #chan is used by the code rather than that calculated from the model number. 3328 */ 3329 3330 instance->o_state = ONCORE_CHECK_CHAN; 3331 oncore_log(instance, LOG_NOTICE, "state = ONCORE_CHECK_CHAN"); 3332 3333 instance->count3 = 1; 3334 oncore_sendmsg(instance, oncore_cmd_Ba, sizeof(oncore_cmd_Ba)); 3335 oncore_sendmsg(instance, oncore_cmd_Ea, sizeof(oncore_cmd_Ea)); 3336 oncore_sendmsg(instance, oncore_cmd_Ha, sizeof(oncore_cmd_Ha)); 3337 } 3338 3339 3340 3341 /* check for a GOOD Almanac, have we got one yet? */ 3342 3343 static void 3344 oncore_check_almanac( 3345 struct instance *instance 3346 ) 3347 { 3348 if (instance->chan == 6) { 3349 instance->rsm.bad_almanac = instance->BEHa[64]&0x1; 3350 instance->rsm.bad_fix = instance->BEHa[64]&0x52; 3351 } else if (instance->chan == 8) { 3352 instance->rsm.bad_almanac = instance->BEHa[72]&0x1; 3353 instance->rsm.bad_fix = instance->BEHa[72]&0x52; 3354 } else if (instance->chan == 12) { 3355 int bits1, bits2, bits3; 3356 3357 bits1 = (instance->BEHa[129]>>5) & 0x7; /* actually Ha */ 3358 bits2 = instance->BEHa[130]; 3359 instance->rsm.bad_almanac = (bits2 & 0x80); 3360 instance->rsm.bad_fix = (bits2 & 0x8) || (bits1 == 0x2); 3361 /* too few sat Bad Geom */ 3362 3363 bits3 = instance->BEHa[141]; /* UTC parameters */ 3364 if (!instance->count5_set && (bits3 & 0xC0)) { 3365 instance->count5 = 4; /* was 2 [Bug 1766] */ 3366 instance->count5_set = 1; 3367 } 3368 #ifdef ONCORE_VERBOSE_CHECK_ALMANAC 3369 oncore_log_f(instance, LOG_DEBUG, 3370 "DEBUG BITS: (%x %x), (%x %x %x), %x %x %x %x %x", 3371 instance->BEHa[129], instance->BEHa[130], 3372 bits1, bits2, bits3, 3373 instance->mode == MODE_0D, 3374 instance->mode == MODE_2D, 3375 instance->mode == MODE_3D, 3376 instance->rsm.bad_almanac, 3377 instance->rsm.bad_fix); 3378 } 3379 #endif 3380 } 3381 } 3382 3383 3384 3385 /* check the antenna for changes (did it get unplugged?) */ 3386 3387 static void 3388 oncore_check_antenna( 3389 struct instance *instance 3390 ) 3391 { 3392 enum antenna_state antenna; /* antenna state */ 3393 3394 if (instance->chan == 12) 3395 antenna = (instance->BEHa[130] & 0x6 ) >> 1; 3396 else 3397 antenna = (instance->BEHa[37] & 0xc0) >> 6; /* prob unset 6, set GT, UT unset VP */ 3398 3399 oncore_antenna_report (instance, antenna); 3400 } 3401 3402 3403 3404 /* 3405 * Check the leap second status once per day. 3406 * 3407 * Note that the ONCORE firmware for the Bj command is wrong at 3408 * least in the VP. 3409 * It starts advertising a LEAP SECOND as soon as the GPS satellite 3410 * data message (page 18, subframe 4) is updated to a date in the 3411 * future, and does not wait for the month that it will occur. 3412 * The event will usually be advertised several months in advance. 3413 * Since there is a one bit flag, there is no way to tell if it is 3414 * this month, or when... 3415 * 3416 * As such, we have the workaround below, of only checking for leap 3417 * seconds with the Bj command in June/December. 3418 * 3419 * The Gj command gives more information, and we can tell in which 3420 * month to apply the correction. 3421 * 3422 * Note that with the VP we COULD read the raw data message, and 3423 * interpret it ourselves, but since this is specific to this receiver 3424 * only, and the above workaround is adequate, we don't bother. 3425 */ 3426 3427 static void 3428 oncore_check_leap_sec( 3429 struct instance *instance 3430 ) 3431 { 3432 oncore_cmd_Bl[2] = 1; /* just to be sure */ 3433 if (instance->Bj_day != instance->BEHa[5]) { /* do this 1/day */ 3434 instance->Bj_day = instance->BEHa[5]; 3435 3436 if (instance->saw_Gj < 0) { /* -1 DONT have Gj use Bj */ 3437 if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12)) 3438 oncore_sendmsg(instance, oncore_cmd_Bj, sizeof(oncore_cmd_Bj)); 3439 oncore_sendmsg(instance, oncore_cmd_Bl, sizeof(oncore_cmd_Bl)); 3440 return; 3441 } 3442 3443 if (instance->saw_Gj == 0) /* 0 is dont know if we have Gj */ 3444 instance->count4 = 1; 3445 3446 oncore_sendmsg(instance, oncore_cmd_Gj, sizeof(oncore_cmd_Gj)); 3447 return; 3448 } 3449 3450 /* Gj works for some 6/8 chan UT and the M12 */ 3451 /* if no response from Gj in 5 sec, we try Bj */ 3452 /* which isnt implemented in all the GT/UT either */ 3453 3454 if (instance->count4) { /* delay, waiting for Gj response */ 3455 if (instance->saw_Gj == 1) 3456 instance->count4 = 0; 3457 else if (instance->count4++ > 5) { /* delay, waiting for Gj response */ 3458 instance->saw_Gj = -1; /* didnt see it, will use Bj */ 3459 instance->count4 = 0; 3460 if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12)) { 3461 oncore_sendmsg(instance, oncore_cmd_Bj, sizeof(oncore_cmd_Bj)); 3462 oncore_sendmsg(instance, oncore_cmd_Bl, sizeof(oncore_cmd_Bl)); 3463 } 3464 } 3465 } 3466 } 3467 3468 3469 3470 /* check the message checksum, 3471 * buf points to START of message ( @@ ) 3472 * len is length WITH CR/LF. 3473 */ 3474 3475 static int 3476 oncore_checksum_ok( 3477 u_char *buf, 3478 int len 3479 ) 3480 { 3481 int i, j; 3482 3483 j = 0; 3484 for (i = 2; i < len-3; i++) 3485 j ^= buf[i]; 3486 3487 return(j == buf[len-3]); 3488 } 3489 3490 3491 3492 static void 3493 oncore_compute_dH( 3494 struct instance *instance 3495 ) 3496 { 3497 int GPS, MSL; 3498 3499 /* Here calculate dH = GPS - MSL for output message */ 3500 /* also set Altitude Hold mode if GT */ 3501 3502 instance->have_dH = 1; 3503 if (instance->chan == 12) { 3504 GPS = buf_w32(&instance->BEHa[39]); 3505 MSL = buf_w32(&instance->BEHa[43]); 3506 } else { 3507 GPS = buf_w32(&instance->BEHa[23]); 3508 MSL = buf_w32(&instance->BEHa[27]); 3509 } 3510 instance->dH = GPS - MSL; 3511 instance->dH /= 100.; 3512 3513 /* if MSL is not set, the calculation is meaningless */ 3514 3515 if (MSL) /* not set ! */ 3516 oncore_log_f(instance, LOG_INFO, 3517 "dH = (GPS - MSL) = %.2fm", instance->dH); 3518 } 3519 3520 3521 3522 /* 3523 * try loading Almanac from shmem (where it was copied from shmem_old 3524 */ 3525 3526 static void 3527 oncore_load_almanac( 3528 struct instance *instance 3529 ) 3530 { 3531 u_char *cp, Cmd[20]; 3532 int n; 3533 struct timeval tv; 3534 struct tm *tm; 3535 3536 if (!instance->shmem) 3537 return; 3538 3539 #ifndef ONCORE_VERBOSE_LOAD_ALMANAC 3540 for (cp = instance->shmem + 4; (n = 256 * (*(cp-3)) + *(cp-2)); 3541 cp += (n + 3)) { 3542 if (!strncmp((char *) cp, "@@Cb", 4) && 3543 oncore_checksum_ok(cp, 33) && 3544 (*(cp+4) == 4 || *(cp+4) == 5)) { 3545 refclock_fdwrite(instance->peer, instance->ttyfd, 3546 cp, n, "data"); 3547 oncore_print_Cb(instance, cp); 3548 } 3549 } 3550 #else /* ONCORE_VERBOSE_LOAD_ALMANAC follows */ 3551 for (cp = instance->shmem + 4; (n = 256 * (*(cp-3)) + *(cp-2)); 3552 cp += (n+3)) { 3553 oncore_log_f(instance, LOG_DEBUG, "See %c%c%c%c %d", 3554 *(cp), *(cp+1), *(cp+2), *(cp+3), *(cp+4)); 3555 3556 if (!strncmp(cp, "@@Cb", 4)) { 3557 oncore_print_Cb(instance, cp); 3558 if (oncore_checksum_ok(cp, 33)) { 3559 if (*(cp+4) == 4 || *(cp+4) == 5) { 3560 oncore_log(instance, LOG_DEBUG, "GOOD SF"); 3561 write(instance->ttyfd, cp, n); 3562 } else 3563 oncore_log(instance, LOG_DEBUG, "BAD SF"); 3564 } else 3565 oncore_log(instance, LOG_DEBUG, "BAD CHECKSUM"); 3566 } 3567 } 3568 #endif 3569 3570 /* Must load position and time or the Almanac doesn't do us any good */ 3571 3572 if (!instance->posn_set) { /* if we input a posn use it, else from SHMEM */ 3573 oncore_log(instance, LOG_NOTICE, "Loading Posn from SHMEM"); 3574 for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) { 3575 if ((instance->chan == 6 && (!strncmp((char *) cp, "@@Ba", 4) && oncore_checksum_ok(cp, 68))) || 3576 (instance->chan == 8 && (!strncmp((char *) cp, "@@Ea", 4) && oncore_checksum_ok(cp, 76))) || 3577 (instance->chan == 12 && (!strncmp((char *) cp, "@@Ha", 4) && oncore_checksum_ok(cp, 154)))) { 3578 int ii, jj, kk; 3579 3580 instance->posn_set = 1; 3581 ii = buf_w32(cp + 15); 3582 jj = buf_w32(cp + 19); 3583 kk = buf_w32(cp + 23); 3584 #ifdef ONCORE_VERBOSE_LOAD_ALMANAC 3585 oncore_log_f(instance, LOG_DEBUG, 3586 "SHMEM posn = %ld (%d, %d, %d)", 3587 (long)(cp-instance->shmem), 3588 ii, jj, kk); 3589 #endif 3590 if (ii != 0 || jj != 0 || kk != 0) { /* phk asked for this test */ 3591 instance->ss_lat = ii; 3592 instance->ss_long = jj; 3593 instance->ss_ht = kk; 3594 } 3595 } 3596 } 3597 } 3598 oncore_set_posn(instance); 3599 3600 /* and set time to time from Computer clock */ 3601 3602 GETTIMEOFDAY(&tv, 0); 3603 tm = gmtime((const time_t *) &tv.tv_sec); 3604 3605 #ifdef ONCORE_VERBOSE_LOAD_ALMANAC 3606 oncore_log_f(instance, LOG_DEBUG, "DATE %d %d %d, %d %d %d", 3607 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, 3608 tm->tm_hour, tm->tm_min, tm->tm_sec); 3609 #endif 3610 if (instance->chan == 12) { 3611 memcpy(Cmd, oncore_cmd_Gb, (size_t) sizeof(oncore_cmd_Gb)); 3612 Cmd[-2+4] = tm->tm_mon + 1; 3613 Cmd[-2+5] = tm->tm_mday; 3614 Cmd[-2+6] = (1900+tm->tm_year)/256; 3615 Cmd[-2+7] = (1900+tm->tm_year)%256; 3616 Cmd[-2+8] = tm->tm_hour; 3617 Cmd[-2+9] = tm->tm_min; 3618 Cmd[-2+10] = tm->tm_sec; 3619 Cmd[-2+11] = 0; 3620 Cmd[-2+12] = 0; 3621 Cmd[-2+13] = 0; 3622 oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Gb)); 3623 } else { 3624 /* First set GMT offset to zero */ 3625 3626 oncore_sendmsg(instance, oncore_cmd_Ab, sizeof(oncore_cmd_Ab)); 3627 3628 memcpy(Cmd, oncore_cmd_Ac, (size_t) sizeof(oncore_cmd_Ac)); 3629 Cmd[-2+4] = tm->tm_mon + 1; 3630 Cmd[-2+5] = tm->tm_mday; 3631 Cmd[-2+6] = (1900+tm->tm_year)/256; 3632 Cmd[-2+7] = (1900+tm->tm_year)%256; 3633 oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ac)); 3634 3635 memcpy(Cmd, oncore_cmd_Aa, (size_t) sizeof(oncore_cmd_Aa)); 3636 Cmd[-2+4] = tm->tm_hour; 3637 Cmd[-2+5] = tm->tm_min; 3638 Cmd[-2+6] = tm->tm_sec; 3639 oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Aa)); 3640 } 3641 3642 oncore_log(instance, LOG_INFO, "Setting Posn and Time after Loading Almanac"); 3643 } 3644 3645 3646 3647 /* Almanac data input */ 3648 3649 static void 3650 oncore_print_Cb( 3651 struct instance *instance, 3652 u_char *cp 3653 ) 3654 { 3655 #ifdef ONCORE_VERBOSE_CB 3656 int ii; 3657 char Msg[160], Msg2[10]; 3658 3659 oncore_log_f(instance, LOG_DEBUG, "DEBUG: See: %c%c%c%c", *(cp), 3660 *(cp+1), *(cp+2), *(cp+3)); 3661 3662 snprintf(Msg, sizeof(Msg), "DEBUG: Cb: [%d,%d]", *(cp+4), 3663 *(cp+5)); 3664 for (ii = 0; ii < 33; ii++) { 3665 snprintf(Msg2, sizeof(Msg2), " %d", *(cp+ii)); 3666 strlcat(Msg, Msg2, sizeof(Msg)); 3667 } 3668 oncore_log(instance, LOG_DEBUG, Msg); 3669 3670 oncore_log_f(instance, LOG_DEBUG, "Debug: Cb: [%d,%d]", *(cp+4), 3671 *(cp+5)); 3672 #endif 3673 } 3674 3675 3676 #if 0 3677 static void 3678 oncore_print_array( 3679 u_char *cp, 3680 int n 3681 ) 3682 { 3683 int jj, i, j, nn; 3684 3685 nn = 0; 3686 printf("\nTOP\n"); 3687 jj = n/16; 3688 for (j=0; j<jj; j++) { 3689 printf("%4d: ", nn); 3690 nn += 16; 3691 for (i=0; i<16; i++) 3692 printf(" %o", *cp++); 3693 printf("\n"); 3694 } 3695 } 3696 #endif 3697 3698 3699 static void 3700 oncore_print_posn( 3701 struct instance *instance 3702 ) 3703 { 3704 char ew, ns; 3705 double xd, xm, xs, yd, ym, ys, hm, hft; 3706 int idx, idy, is, imx, imy; 3707 long lat, lon; 3708 3709 oncore_log(instance, LOG_INFO, "Posn:"); 3710 ew = 'E'; 3711 lon = instance->ss_long; 3712 if (lon < 0) { 3713 ew = 'W'; 3714 lon = -lon; 3715 } 3716 3717 ns = 'N'; 3718 lat = instance->ss_lat; 3719 if (lat < 0) { 3720 ns = 'S'; 3721 lat = -lat; 3722 } 3723 3724 hm = instance->ss_ht/100.; 3725 hft= hm/0.3048; 3726 3727 xd = lat/3600000.; /* lat, lon in int msec arc, ht in cm. */ 3728 yd = lon/3600000.; 3729 oncore_log_f(instance, LOG_INFO, 3730 "Lat = %c %11.7fdeg, Long = %c %11.7fdeg, Alt = %5.2fm (%5.2fft) GPS", 3731 ns, xd, ew, yd, hm, hft); 3732 3733 idx = xd; 3734 idy = yd; 3735 imx = lat%3600000; 3736 imy = lon%3600000; 3737 xm = imx/60000.; 3738 ym = imy/60000.; 3739 oncore_log_f(instance, LOG_INFO, 3740 "Lat = %c %3ddeg %7.4fm, Long = %c %3ddeg %8.5fm, Alt = %7.2fm (%7.2fft) GPS", 3741 ns, idx, xm, ew, idy, ym, hm, hft); 3742 3743 imx = xm; 3744 imy = ym; 3745 is = lat%60000; 3746 xs = is/1000.; 3747 is = lon%60000; 3748 ys = is/1000.; 3749 oncore_log_f(instance, LOG_INFO, 3750 "Lat = %c %3ddeg %2dm %5.2fs, Long = %c %3ddeg %2dm %5.2fs, Alt = %7.2fm (%7.2fft) GPS", 3751 ns, idx, imx, xs, ew, idy, imy, ys, hm, hft); 3752 } 3753 3754 3755 3756 /* 3757 * write message to Oncore. 3758 */ 3759 3760 static void 3761 oncore_sendmsg( 3762 struct instance *instance, 3763 u_char *ptr, 3764 size_t len 3765 ) 3766 { 3767 int fd; 3768 u_char cs = 0; 3769 const struct peer * peer; 3770 3771 fd = instance->ttyfd; 3772 peer = instance->peer; 3773 #ifdef ONCORE_VERBOSE_SENDMSG 3774 if (debug > 4) { 3775 oncore_log_f(instance, LOG_DEBUG, "ONCORE: Send @@%c%c %d", 3776 ptr[0], ptr[1], (int)len); 3777 } 3778 #endif 3779 refclock_fdwrite(peer, fd, "@@", (size_t)2, "data"); 3780 refclock_fdwrite(peer, fd, ptr, len, "data"); 3781 while (len--) 3782 cs ^= *ptr++; 3783 refclock_fdwrite(peer, fd, &cs, (size_t)1, "data"); 3784 refclock_fdwrite(peer, fd, "\r\n", (size_t)2, "data"); 3785 } 3786 3787 3788 3789 static void 3790 oncore_set_posn( 3791 struct instance *instance 3792 ) 3793 { 3794 int mode; 3795 u_char Cmd[20]; 3796 3797 /* Turn OFF position hold, it needs to be off to set position (for some units), 3798 will get set ON in @@Ea later */ 3799 3800 if (instance->chan == 12) 3801 oncore_sendmsg(instance, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* (12) */ 3802 else { 3803 oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* (6/8) */ 3804 oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* (6/8) */ 3805 } 3806 3807 mode = instance->init_type; 3808 3809 if (mode != 0) { /* first set posn hold position */ 3810 memcpy(Cmd, oncore_cmd_As, (size_t) sizeof(oncore_cmd_As)); /* don't modify static variables */ 3811 w32_buf(&Cmd[-2+4], (int) instance->ss_lat); 3812 w32_buf(&Cmd[-2+8], (int) instance->ss_long); 3813 w32_buf(&Cmd[-2+12], (int) instance->ss_ht); 3814 Cmd[-2+16] = 0; 3815 oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_As)); /* posn hold 3D posn (6/8/12) */ 3816 3817 memcpy(Cmd, oncore_cmd_Au, (size_t) sizeof(oncore_cmd_Au)); 3818 w32_buf(&Cmd[-2+4], (int) instance->ss_ht); 3819 Cmd[-2+8] = 0; 3820 oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Au)); /* altitude hold (6/8/12 not UT, M12T) */ 3821 3822 /* next set current position */ 3823 3824 if (instance->chan == 12) { 3825 memcpy(Cmd, oncore_cmd_Ga, (size_t) sizeof(oncore_cmd_Ga)); 3826 w32_buf(&Cmd[-2+4], (int) instance->ss_lat); 3827 w32_buf(&Cmd[-2+8], (int) instance->ss_long); 3828 w32_buf(&Cmd[-2+12],(int) instance->ss_ht); 3829 Cmd[-2+16] = 0; 3830 oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ga)); /* 3d posn (12) */ 3831 } else { 3832 memcpy(Cmd, oncore_cmd_Ad, (size_t) sizeof(oncore_cmd_Ad)); 3833 w32_buf(&Cmd[-2+4], (int) instance->ss_lat); 3834 oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ad)); /* lat (6/8) */ 3835 3836 memcpy(Cmd, oncore_cmd_Ae, (size_t) sizeof(oncore_cmd_Ae)); 3837 w32_buf(&Cmd[-2+4], (int) instance->ss_long); 3838 oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ae)); /* long (6/8) */ 3839 3840 memcpy(Cmd, oncore_cmd_Af, (size_t) sizeof(oncore_cmd_Af)); 3841 w32_buf(&Cmd[-2+4], (int) instance->ss_ht); 3842 Cmd[-2+8] = 0; 3843 oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Af)); /* ht (6/8) */ 3844 } 3845 3846 /* Finally, turn on position hold */ 3847 3848 if (instance->chan == 12) 3849 oncore_sendmsg(instance, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); 3850 else 3851 oncore_sendmsg(instance, oncore_cmd_At1, sizeof(oncore_cmd_At1)); 3852 } 3853 } 3854 3855 3856 3857 static void 3858 oncore_set_traim( 3859 struct instance *instance 3860 ) 3861 { 3862 if (instance->traim_in != -1) /* set in Input */ 3863 instance->traim = instance->traim_in; 3864 else 3865 instance->traim = instance->traim_ck; 3866 3867 oncore_log_f(instance, LOG_INFO, "Input says TRAIM = %d", 3868 instance->traim_in); 3869 oncore_log_f(instance, LOG_INFO, "Model # says TRAIM = %d", 3870 instance->traim_id); 3871 oncore_log_f(instance, LOG_INFO, "Testing says TRAIM = %d", 3872 instance->traim_ck); 3873 oncore_log_f(instance, LOG_INFO, "Using TRAIM = %d", 3874 instance->traim); 3875 3876 if (instance->traim_ck == 1 && instance->traim == 0) { 3877 /* if it should be off, and I turned it on during testing, 3878 then turn it off again */ 3879 if (instance->chan == 6) 3880 oncore_sendmsg(instance, oncore_cmd_Bnx, sizeof(oncore_cmd_Bnx)); 3881 else if (instance->chan == 8) 3882 oncore_sendmsg(instance, oncore_cmd_Enx, sizeof(oncore_cmd_Enx)); 3883 else /* chan == 12 */ 3884 oncore_sendmsg(instance, oncore_cmd_Ge0, sizeof(oncore_cmd_Ge0)); 3885 oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0)); 3886 } 3887 } 3888 3889 3890 3891 /* 3892 * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn. 3893 */ 3894 3895 static void 3896 oncore_shmem_get_3D( 3897 struct instance *instance 3898 ) 3899 { 3900 if (instance->pp->second%15 == 3) { /* start the sequence */ /* by changing mode */ 3901 instance->shmem_reset = 1; 3902 if (instance->chan == 12) { 3903 if (instance->shmem_Posn == 2) 3904 oncore_sendmsg(instance, oncore_cmd_Gd2, sizeof(oncore_cmd_Gd2)); /* 2D */ 3905 else 3906 oncore_sendmsg(instance, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* 3D */ 3907 } else { 3908 if (instance->saw_At) { /* out of 0D -> 3D mode */ 3909 oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0)); 3910 if (instance->shmem_Posn == 2) /* 3D -> 2D mode */ 3911 oncore_sendmsg(instance, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); 3912 } else 3913 oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); 3914 } 3915 } else if (instance->shmem_reset || (instance->mode != MODE_0D)) { 3916 instance->shmem_reset = 0; 3917 if (instance->chan == 12) 3918 oncore_sendmsg(instance, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); /* 0D */ 3919 else { 3920 if (instance->saw_At) { 3921 if (instance->mode == MODE_2D) /* 2D -> 3D or 0D mode */ 3922 oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); 3923 oncore_sendmsg(instance, oncore_cmd_At1, sizeof(oncore_cmd_At1)); /* to 0D mode */ 3924 } else 3925 oncore_sendmsg(instance, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); 3926 } 3927 } 3928 } 3929 3930 3931 3932 /* 3933 * Here we do the Software SiteSurvey. 3934 * We have to average our own position for the Position Hold Mode 3935 * We use Heights from the GPS ellipsoid. 3936 * We check for the END of either HW or SW SiteSurvey. 3937 */ 3938 3939 static void 3940 oncore_ss( 3941 struct instance *instance 3942 ) 3943 { 3944 double lat, lon, ht; 3945 3946 3947 if (instance->site_survey == ONCORE_SS_HW) { 3948 /* 3949 * Check to see if Hardware SiteSurvey has Finished. 3950 */ 3951 3952 if ((instance->chan == 8 && !(instance->BEHa[37] & 0x20)) || 3953 (instance->chan == 12 && !(instance->BEHa[130] & 0x10))) { 3954 oncore_log(instance, LOG_INFO, "Now in 0D mode"); 3955 3956 if (instance->chan == 12) 3957 oncore_sendmsg(instance, oncore_cmd_Gax, sizeof(oncore_cmd_Gax)); 3958 else 3959 oncore_sendmsg(instance, oncore_cmd_Asx, sizeof(oncore_cmd_Asx)); 3960 3961 oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_DONE"); 3962 instance->site_survey = ONCORE_SS_DONE; 3963 } 3964 } else { 3965 /* 3966 * Must be a Software Site Survey. 3967 */ 3968 3969 if (instance->rsm.bad_fix) /* Not if poor geometry or less than 3 sats */ 3970 return; 3971 3972 if (instance->mode != MODE_3D) /* Use only 3D Fixes */ 3973 return; 3974 3975 instance->ss_lat += buf_w32(&instance->BEHa[15]); 3976 instance->ss_long += buf_w32(&instance->BEHa[19]); 3977 instance->ss_ht += buf_w32(&instance->BEHa[23]); /* GPS ellipsoid */ 3978 instance->ss_count++; 3979 3980 if (instance->ss_count != POS_HOLD_AVERAGE) 3981 return; 3982 3983 instance->ss_lat /= POS_HOLD_AVERAGE; 3984 instance->ss_long /= POS_HOLD_AVERAGE; 3985 instance->ss_ht /= POS_HOLD_AVERAGE; 3986 3987 oncore_log_f(instance, LOG_NOTICE, 3988 "Surveyed posn: lat %.3f (mas) long %.3f (mas) ht %.3f (cm)", 3989 instance->ss_lat, instance->ss_long, 3990 instance->ss_ht); 3991 lat = instance->ss_lat/3600000.; 3992 lon = instance->ss_long/3600000.; 3993 ht = instance->ss_ht/100; 3994 oncore_log_f(instance, LOG_NOTICE, 3995 "Surveyed posn: lat %.7f (deg) long %.7f (deg) ht %.2f (m)", 3996 lat, lon, ht); 3997 3998 oncore_set_posn(instance); 3999 4000 oncore_log(instance, LOG_INFO, "Now in 0D mode"); 4001 4002 oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_DONE"); 4003 instance->site_survey = ONCORE_SS_DONE; 4004 } 4005 } 4006 4007 4008 4009 static int 4010 oncore_wait_almanac( 4011 struct instance *instance 4012 ) 4013 { 4014 if (instance->rsm.bad_almanac) { 4015 instance->counta++; 4016 if (instance->counta%5 == 0) 4017 oncore_log(instance, LOG_INFO, "Waiting for Almanac"); 4018 4019 /* 4020 * If we get here (first time) then we don't have an almanac in memory. 4021 * Check if we have a SHMEM, and if so try to load whatever is there. 4022 */ 4023 4024 if (!instance->almanac_from_shmem) { 4025 instance->almanac_from_shmem = 1; 4026 oncore_load_almanac(instance); 4027 } 4028 return(1); 4029 } else { /* Here we have the Almanac, we will be starting the @@Bn/@@En/@@Hn 4030 commands, and can finally check for TRAIM. Again, we set a delay 4031 (5sec) and wait for things to settle down */ 4032 4033 if (instance->chan == 6) 4034 oncore_sendmsg(instance, oncore_cmd_Bn, sizeof(oncore_cmd_Bn)); 4035 else if (instance->chan == 8) 4036 oncore_sendmsg(instance, oncore_cmd_En, sizeof(oncore_cmd_En)); 4037 else if (instance->chan == 12) { 4038 oncore_sendmsg(instance, oncore_cmd_Gc, sizeof(oncore_cmd_Gc)); /* 1PPS on, continuous */ 4039 oncore_sendmsg(instance, oncore_cmd_Ge, sizeof(oncore_cmd_Ge)); /* TRAIM on */ 4040 oncore_sendmsg(instance, oncore_cmd_Hn, sizeof(oncore_cmd_Hn)); /* TRAIM status 1/s */ 4041 } 4042 instance->traim_delay = 1; 4043 4044 oncore_log(instance, LOG_NOTICE, "Have now loaded an ALMANAC"); 4045 4046 instance->o_state = ONCORE_RUN; 4047 oncore_log(instance, LOG_NOTICE, "state = ONCORE_RUN"); 4048 } 4049 return(0); 4050 } 4051 4052 4053 static void 4054 oncore_feed_clockproc( 4055 struct instance * instance 4056 ) 4057 { 4058 struct peer * const peer = instance->peer; 4059 struct refclockproc * const pp = instance->pp; 4060 4061 TCivilDate cd; /* calendar date + time */ 4062 TGpsDatum gd; /* GPS datum, remapped into NTP epoch */ 4063 l_fp fp; /* the reference time in NTP format */ 4064 4065 if (pp->year >= 1980) { 4066 /* There are oncore receivers that run in a fixed 4067 * (possibly shifted) GPS era and fold back into that 4068 * era on every GPS week rollover. 4069 * 4070 * We do not trust the date we get and remap to a GPS 4071 * era defined by the GPS base date (derived from the 4072 * build time stamp or a 'tos basedate' config option. 4073 */ 4074 ZERO(fp); /* has a zero to begin with */ 4075 ZERO(cd); /* month == monthday == 0 -> use year+yearday */ 4076 cd.year = pp->year; 4077 cd.yearday = pp->day; 4078 cd.hour = pp->hour; 4079 cd.minute = pp->minute; 4080 cd.second = pp->second; 4081 4082 /* the magic happens in the next line: */ 4083 gd = gpscal_from_calendar(&cd, fp); /* fp should be zero here */ 4084 4085 /* To avoid the trouble the day-of-year calculations in 4086 * 'refclock_process()' can cause we feed the time 4087 * stamps we have now directly. This also saves us two 4088 * full calendar calendar conversion cycles. 4089 */ 4090 fp = ntpfp_from_gpsdatum(&gd); 4091 refclock_process_offset(pp, fp, pp->lastrec, pp->fudgetime1); 4092 } else { 4093 /* This is obviously a bad date/time... */ 4094 refclock_report(peer, CEVNT_BADDATE); 4095 peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 4096 return; 4097 } 4098 } 4099 4100 static void 4101 oncore_log ( 4102 struct instance *instance, 4103 int log_level, 4104 const char *msg 4105 ) 4106 { 4107 msyslog(log_level, "ONCORE[%d]: %s", instance->unit, msg); 4108 mprintf_clock_stats(&instance->peer->srcadr, "ONCORE[%d]: %s", 4109 instance->unit, msg); 4110 } 4111 4112 4113 static int 4114 oncore_log_f( 4115 struct instance * instance, 4116 int log_level, 4117 const char * fmt, 4118 ... 4119 ) 4120 { 4121 va_list ap; 4122 int rc; 4123 char msg[512]; 4124 4125 va_start(ap, fmt); 4126 rc = mvsnprintf(msg, sizeof(msg), fmt, ap); 4127 va_end(ap); 4128 oncore_log(instance, log_level, msg); 4129 4130 #ifdef ONCORE_VERBOSE_ONCORE_LOG 4131 instance->max_len = max(strlen(msg), instance->max_len); 4132 instance->max_count++; 4133 if (instance->max_count % 100 == 0) 4134 oncore_log_f(instance, LOG_INFO, 4135 "Max Message Length so far is %d", 4136 instance->max_len); 4137 #endif 4138 return rc; 4139 } 4140 4141 #else 4142 NONEMPTY_TRANSLATION_UNIT 4143 #endif /* REFCLOCK && CLOCK_ONCORE */ 4144