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