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