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