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