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 * ----------------------------------------------------------------------------
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
15 * The receivers without position hold (GT, GT+) will be less accurate.
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
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
43 * --------------------------------------------------------------------------
44 * This code uses the two devices
45 * /dev/oncore.serial.n
47 * which may be linked to the same device.
48 * and can read initialization data from the file
49 * /etc/ntp.oncoreN, /etc/ntp.oncore.N, or /etc/ntp.oncore, where
50 * n or N are the unit number, viz 127.127.30.N.
51 * --------------------------------------------------------------------------
52 * Reg.Clemens <reg@dwf.com> Sep98.
53 * Original code written for FreeBSD.
54 * With these mods it works on FreeBSD, SunOS, Solaris and Linux
55 * (SunOS 4.1.3 + ppsclock)
57 * (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + or later).
59 * Lat,Long,Ht, cable-delay, offset, and the ReceiverID (along with the
60 * state machine state) are printed to CLOCKSTATS if that file is enabled
63 * --------------------------------------------------------------------------
65 * According to the ONCORE manual (TRM0003, Rev 3.2, June 1998, page 3.13)
66 * doing an average of 10000 valid 2D and 3D fixes is what the automatic
67 * site survey mode does. Looking at the output from the receiver
68 * it seems like it is only using 3D fixes.
69 * When we do it ourselves, take 10000 3D fixes.
72 #define POS_HOLD_AVERAGE 10000 /* nb, 10000s ~= 2h45m */
75 * ONCORE_SHMEM_STATUS will create a mmap(2)'ed file named according to a
76 * "STATUS" line in the oncore config file, which contains the most recent
77 * copy of all types of messages we recognize. This file can be mmap(2)'ed
78 * by monitoring and statistics programs.
80 * See separate HTML documentation for this option.
87 #if defined(REFCLOCK) && defined(CLOCK_ONCORE) && defined(HAVE_PPSAPI)
91 #include "ntp_unixtime.h"
92 #include "ntp_refclock.h"
93 #include "ntp_stdlib.h"
98 #ifdef ONCORE_SHMEM_STATUS
99 # ifdef HAVE_SYS_MMAN_H
100 # include <sys/mman.h>
102 # define MAP_FAILED ((u_char *) -1)
103 # endif /* not MAP_FAILED */
104 # endif /* HAVE_SYS_MMAN_H */
105 #endif /* ONCORE_SHMEM_STATUS */
108 # ifdef HAVE_TIMEPPS_H
109 # include <timepps.h>
111 # ifdef HAVE_SYS_TIMEPPS_H
112 # include <sys/timepps.h>
117 #ifdef HAVE_SYS_SIO_H
118 # include <sys/sio.h>
121 #ifdef HAVE_SYS_TERMIOS_H
122 # include <sys/termios.h>
125 #ifdef HAVE_SYS_PPSCLOCK_H
126 # include <sys/ppsclock.h>
129 #ifndef HAVE_STRUCT_PPSCLOCKEV
131 # ifdef HAVE_STRUCT_TIMESPEC
138 #endif /* not HAVE_STRUCT_PPSCLOCKEV */
152 enum site_survey_state {
161 ONCORE_ANTENNA_UNKNOWN = -1,
162 ONCORE_ANTENNA_OK = 0,
163 ONCORE_ANTENNA_OC = 1,
164 ONCORE_ANTENNA_UC = 2,
165 ONCORE_ANTENNA_NV = 3
168 /* Model Name, derived from the @@Cj message.
169 * Used to initialize some variables.
185 /* the bits that describe these properties are in the same place
186 * on the VP/UT, but have moved on the M12. As such we extract
187 * them, and use them from this struct.
199 /* It is possible to test the VP/UT each cycle (@@Ea or equivalent) to
200 * see what mode it is in. The bits on the M12 are multiplexed with
201 * other messages, so we have to 'keep' the last known mode here.
212 int unit; /* 127.127.30.unit */
213 struct refclockproc *pp;
216 int ttyfd; /* TTY file descriptor */
217 int ppsfd; /* PPS file descriptor */
218 int shmemfd; /* Status shm descriptor */
223 enum receive_state o_state; /* Receive state */
224 enum posn_mode mode; /* 0D, 2D, 3D */
225 enum site_survey_state site_survey; /* Site Survey state */
226 enum antenna_state ant_state; /* antenna state */
230 u_long delay; /* ns */
231 long offset; /* ns */
242 u_char almanac_from_shmem;
251 enum oncore_model model;
255 u_char chan; /* 6 for PVT6 or BASIC, 8 for UT/VP, 12 for m12, 0 if unknown */
256 s_char traim; /* do we have traim? yes UT/VP, no BASIC, GT, M12+T, -1 unknown, 0 no, +1 yes */
258 /* the following 7 are all timing counters */
259 u_char traim_delay; /* seconds counter, waiting for reply */
260 u_char count; /* cycles thru Ea before starting */
261 u_char count1; /* cycles thru Ea after SS_TESTING, waiting for SS_HW */
262 u_char count2; /* cycles thru Ea after count, to check for @@Ea */
263 u_char count3; /* cycles thru Ea checking for # channels */
264 u_char count4; /* cycles thru leap after Gj to issue Bj */
266 u_char timeout; /* count to retry Cj after Fa self-test */
268 struct RSM rsm; /* bits extracted from Receiver Status Msg in @@Ea */
274 u_char BEHa[160]; /* Ba, Ea or Ha */
275 u_char BEHn[80]; /* Bn , En , or Hn */
277 u_char Ag; /* Satellite mask angle */
285 s_char chan_in; /* chan number from INPUT, will always use it */
286 u_char chan_id; /* chan number determined from part number */
287 u_char chan_ck; /* chan number determined by sending commands to hardware */
288 s_char traim_in; /* TRAIM from INPUT, will always use it */
289 s_char traim_id; /* TRAIM determined from part number */
290 u_char traim_ck; /* TRAIM determined by sending commands to hardware */
291 u_char once; /* one pass code at top of BaEaHa */
296 #define rcvbuf instance->Rcvbuf
297 #define rcvptr instance->Rcvptr
299 static int oncore_start P((int, struct peer *));
300 static void oncore_control P((int, struct refclockstat *, struct refclockstat *, struct peer *));
301 static void oncore_poll P((int, struct peer *));
302 static void oncore_shutdown P((int, struct peer *));
303 static void oncore_consume P((struct instance *));
304 static void oncore_read_config P((struct instance *));
305 static void oncore_receive P((struct recvbuf *));
306 static int oncore_ppsapi P((struct instance *));
307 static void oncore_get_timestamp P((struct instance *, long, long));
308 static void oncore_init_shmem P((struct instance *));
310 static void oncore_antenna_report P((struct instance *, enum antenna_state));
311 static void oncore_chan_test P((struct instance *));
312 static void oncore_check_almanac P((struct instance *));
313 static void oncore_check_antenna P((struct instance *));
314 static void oncore_check_leap_sec P((struct instance *));
315 static int oncore_checksum_ok P((u_char *, int));
316 static void oncore_compute_dH P((struct instance *));
317 static void oncore_load_almanac P((struct instance *));
318 static void oncore_print_Cb P((struct instance *, u_char *));
319 /* static void oncore_print_array P((u_char *, int)); */
320 static void oncore_print_posn P((struct instance *));
321 static void oncore_sendmsg P((int, u_char *, size_t));
322 static void oncore_set_posn P((struct instance *));
323 static void oncore_set_traim P((struct instance *));
324 static void oncore_shmem_get_3D P((struct instance *));
325 static void oncore_ss P((struct instance *));
326 static int oncore_wait_almanac P((struct instance *));
328 static void oncore_msg_any P((struct instance *, u_char *, size_t, int));
329 static void oncore_msg_Adef P((struct instance *, u_char *, size_t));
330 static void oncore_msg_Ag P((struct instance *, u_char *, size_t));
331 static void oncore_msg_As P((struct instance *, u_char *, size_t));
332 static void oncore_msg_At P((struct instance *, u_char *, size_t));
333 static void oncore_msg_Ay P((struct instance *, u_char *, size_t));
334 static void oncore_msg_Az P((struct instance *, u_char *, size_t));
335 static void oncore_msg_BaEaHa P((struct instance *, u_char *, size_t));
336 static void oncore_msg_Bd P((struct instance *, u_char *, size_t));
337 static void oncore_msg_Bj P((struct instance *, u_char *, size_t));
338 static void oncore_msg_BnEnHn P((struct instance *, u_char *, size_t));
339 static void oncore_msg_CaFaIa P((struct instance *, u_char *, size_t));
340 static void oncore_msg_Cb P((struct instance *, u_char *, size_t));
341 static void oncore_msg_Cf P((struct instance *, u_char *, size_t));
342 static void oncore_msg_Cj P((struct instance *, u_char *, size_t));
343 static void oncore_msg_Cj_id P((struct instance *, u_char *, size_t));
344 static void oncore_msg_Cj_init P((struct instance *, u_char *, size_t));
345 static void oncore_msg_Ga P((struct instance *, u_char *, size_t));
346 static void oncore_msg_Gb P((struct instance *, u_char *, size_t));
347 static void oncore_msg_Gd P((struct instance *, u_char *, size_t));
348 static void oncore_msg_Gj P((struct instance *, u_char *, size_t));
349 static void oncore_msg_Sz P((struct instance *, u_char *, size_t));
351 struct refclock refclock_oncore = {
352 oncore_start, /* start up driver */
353 oncore_shutdown, /* shut down driver */
354 oncore_poll, /* transmit poll message */
355 oncore_control, /* fudge (flag) control messages */
356 noentry, /* not used */
357 noentry, /* not used */
358 NOFLAGS /* not used */
362 * Understanding the next bit here is not easy unless you have a manual
363 * for the the various Oncore Models.
366 static struct msg_desc {
369 void (*handler) P((struct instance *, u_char *, size_t));
372 } oncore_messages[] = {
373 /* Ea and En first since they're most common */
374 { "Ea", 76, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" },
375 { "Ba", 68, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC" },
376 { "Ha", 154, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC" },
377 { "Bn", 59, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC" },
378 { "En", 69, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" },
379 { "Hn", 78, oncore_msg_BnEnHn, "" },
382 { "Ad", 11, oncore_msg_Adef, "" },
383 { "Ae", 11, oncore_msg_Adef, "" },
384 { "Af", 15, oncore_msg_Adef, "" },
385 { "Ag", 8, oncore_msg_Ag, "" }, /* Satellite mask angle */
386 { "As", 20, oncore_msg_As, "" },
387 { "At", 8, oncore_msg_At, "" },
391 { "Ay", 11, oncore_msg_Ay, "" },
392 { "Az", 11, oncore_msg_Az, "" },
395 { "Bd", 23, oncore_msg_Bd, "" },
396 { "Bj", 8, oncore_msg_Bj, "" },
397 { "Ca", 9, oncore_msg_CaFaIa, "" },
398 { "Cb", 33, oncore_msg_Cb, "" },
399 { "Cf", 7, oncore_msg_Cf, "" },
402 { "Cj", 294, oncore_msg_Cj, "" },
404 { "Fa", 9, oncore_msg_CaFaIa, "" },
405 { "Ga", 20, oncore_msg_Ga, "" },
406 { "Gb", 17, oncore_msg_Gb, "" },
408 { "Gd", 8, oncore_msg_Gd, "" },
410 { "Gj", 21, oncore_msg_Gj, "" },
411 { "Ia", 10, oncore_msg_CaFaIa, "" },
412 { "Sz", 8, oncore_msg_Sz, "" },
417 static u_char oncore_cmd_Aa[] = { 'A', 'a', 0, 0, 0 }; /* 6/8 Time of Day */
418 static u_char oncore_cmd_Ab[] = { 'A', 'b', 0, 0, 0 }; /* 6/8 GMT Correction */
419 static u_char oncore_cmd_AB[] = { 'A', 'B', 4 }; /* VP Application Type: Static */
420 static u_char oncore_cmd_Ac[] = { 'A', 'c', 0, 0, 0, 0 }; /* 6/8 Date */
421 static u_char oncore_cmd_Ad[] = { 'A', 'd', 0,0,0,0 }; /* 6/8 Latitude */
422 static u_char oncore_cmd_Ae[] = { 'A', 'e', 0,0,0,0 }; /* 6/8 Longitude */
423 static u_char oncore_cmd_Af[] = { 'A', 'f', 0,0,0,0, 0 }; /* 6/8 Height */
424 static u_char oncore_cmd_Ag[] = { 'A', 'g', 0 }; /* 6/8/12 Satellite Mask Angle */
425 static u_char oncore_cmd_Agx[] = { 'A', 'g', 0xff }; /* 6/8/12 Satellite Mask Angle: read */
426 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 */
427 static u_char oncore_cmd_Asx[] = { 'A', 's', 0x7f,0xff,0xff,0xff, /* 6/8/12 Posn Hold Readback */
428 0x7f,0xff,0xff,0xff, /* on UT+ this doesnt work with 0xff */
429 0x7f,0xff,0xff,0xff, 0xff }; /* but does work with 0x7f (sigh). */
430 static u_char oncore_cmd_At0[] = { 'A', 't', 0 }; /* 6/8 Posn Hold: off */
431 static u_char oncore_cmd_At1[] = { 'A', 't', 1 }; /* 6/8 Posn Hold: on */
432 static u_char oncore_cmd_At2[] = { 'A', 't', 2 }; /* 6/8 Posn Hold: Start Site Survey */
433 static u_char oncore_cmd_Atx[] = { 'A', 't', 0xff }; /* 6/8 Posn Hold: Read Back */
434 static u_char oncore_cmd_Au[] = { 'A', 'u', 0,0,0,0, 0 }; /* GT/M12 Altitude Hold Ht. */
435 static u_char oncore_cmd_Av0[] = { 'A', 'v', 0 }; /* VP/GT Altitude Hold: off */
436 static u_char oncore_cmd_Av1[] = { 'A', 'v', 1 }; /* VP/GT Altitude Hold: on */
437 static u_char oncore_cmd_Aw[] = { 'A', 'w', 1 }; /* 6/8/12 UTC/GPS time selection */
438 static u_char oncore_cmd_Ay[] = { 'A', 'y', 0, 0, 0, 0 }; /* Timing 1PPS time offset: set */
439 static u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff }; /* Timing 1PPS time offset: Read */
440 static u_char oncore_cmd_Az[] = { 'A', 'z', 0, 0, 0, 0 }; /* 6/8UT/12 1PPS Cable Delay: set */
441 static u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff }; /* 6/8UT/12 1PPS Cable Delay: Read */
442 static u_char oncore_cmd_Ba0[] = { 'B', 'a', 0 }; /* 6 Position/Data/Status: off */
443 static u_char oncore_cmd_Ba[] = { 'B', 'a', 1 }; /* 6 Position/Data/Status: on */
444 static u_char oncore_cmd_Bb[] = { 'B', 'b', 1 }; /* 6/8/12 Visible Satellites */
445 static u_char oncore_cmd_Bd[] = { 'B', 'd', 1 }; /* 6/8/12? Almanac Status Msg. */
446 static u_char oncore_cmd_Be[] = { 'B', 'e', 1 }; /* 6/8/12 Request Almanac Data */
447 static u_char oncore_cmd_Bj[] = { 'B', 'j', 0 }; /* 6/8 Leap Second Pending */
448 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 */
449 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 */
450 static u_char oncore_cmd_Bnx[] = { 'B', 'n', 1, 0, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6 TRAIM setup/status: msg on traim off */
451 static u_char oncore_cmd_Ca[] = { 'C', 'a' }; /* 6 Self Test */
452 static u_char oncore_cmd_Cf[] = { 'C', 'f' }; /* 6/8/12 Set to Defaults */
453 static u_char oncore_cmd_Cg[] = { 'C', 'g', 1 }; /* VP Posn Fix/Idle Mode */
454 static u_char oncore_cmd_Cj[] = { 'C', 'j' }; /* 6/8/12 Receiver ID */
455 static u_char oncore_cmd_Ea0[] = { 'E', 'a', 0 }; /* 8 Position/Data/Status: off */
456 static u_char oncore_cmd_Ea[] = { 'E', 'a', 1 }; /* 8 Position/Data/Status: on */
457 static u_char oncore_cmd_Ek[] = { 'E', 'k', 0 }; /* just turn off */ /* 8 Posn/Status/Data - extension */
458 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 */
459 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 */
460 static u_char oncore_cmd_Enx[] = { 'E', 'n', 1, 0, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT TRAIM setup/status: msg on traim off */
461 static u_char oncore_cmd_Fa[] = { 'F', 'a' }; /* 8 Self Test */
462 static u_char oncore_cmd_Ga[] = { 'G', 'a', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; /* 12 Position Set */
463 static u_char oncore_cmd_Gax[] = { 'G', 'a', 0xff, 0xff, 0xff, 0xff, /* 12 Position Set: Read */
464 0xff, 0xff, 0xff, 0xff, /* */
465 0xff, 0xff, 0xff, 0xff, 0xff }; /* */
466 static u_char oncore_cmd_Gb[] = { 'G', 'b', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* 12 set Date/Time */
467 static u_char oncore_cmd_Gc[] = { 'G', 'c', 1 }; /* 12 PPS Control: On Cont */
468 static u_char oncore_cmd_Gd0[] = { 'G', 'd', 0 }; /* 12 Position Control: 3D (no hold) */
469 static u_char oncore_cmd_Gd1[] = { 'G', 'd', 1 }; /* 12 Position Control: 0D (3D hold) */
470 static u_char oncore_cmd_Gd2[] = { 'G', 'd', 2 }; /* 12 Position Control: 2D (Alt Hold) */
471 static u_char oncore_cmd_Gd3[] = { 'G', 'd', 3 }; /* 12 Position Coltrol: Start Site Survey */
472 static u_char oncore_cmd_Ge0[] = { 'G', 'e', 0 }; /* M12+T TRAIM: off */
473 static u_char oncore_cmd_Ge[] = { 'G', 'e', 1 }; /* M12+T TRAIM: on */
474 static u_char oncore_cmd_Gj[] = { 'G', 'j' }; /* 8?/12 Leap Second Pending */
475 static u_char oncore_cmd_Ha0[] = { 'H', 'a', 0 }; /* 12 Position/Data/Status: off */
476 static u_char oncore_cmd_Ha[] = { 'H', 'a', 1 }; /* 12 Position/Data/Status: on */
477 static u_char oncore_cmd_Hn0[] = { 'H', 'n', 0 }; /* 12 TRAIM Status: off */
478 static u_char oncore_cmd_Hn[] = { 'H', 'n', 1 }; /* 12 TRAIM Status: on */
479 static u_char oncore_cmd_Ia[] = { 'I', 'a' }; /* 12 Self Test */
481 /* it appears that as of 1997/1998, the UT had As,At, but not Au,Av
482 * the GT had Au,Av, but not As,At
483 * This was as of v2.0 of both firmware sets. possibly 1.3 for UT.
485 * dont see Bd in UT/GT thru 1999
486 * Gj in UT as of 3.0, 1999 , Bj as of 1.3
489 static char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jly",
490 "Aug", "Sep", "Oct", "Nov", "Dec" };
492 #define DEVICE1 "/dev/oncore.serial.%d" /* name of serial device */
493 #define DEVICE2 "/dev/oncore.pps.%d" /* name of pps device */
494 #define INIT_FILE "/etc/ntp.oncore" /* optional init file */
496 #define SPEED B9600 /* Oncore Binary speed (9600 bps) */
499 * Assemble and disassemble 32bit signed quantities from a buffer.
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; \
512 #define w32(buf) (((buf)[0]&0xff) << 24 | \
513 ((buf)[1]&0xff) << 16 | \
514 ((buf)[2]&0xff) << 8 | \
517 /* from buffer, char *buf, result to an int */
518 #define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf))
522 * oncore_start - initialize data for processing
531 register struct instance *instance;
532 struct refclockproc *pp;
534 char device1[30], device2[30];
536 struct stat stat1, stat2;
539 /* opening different devices for fd1 and fd2 presents no problems */
540 /* opening the SAME device twice, seems to be OS dependent.
541 (a) on Linux (no streams) no problem
542 (b) on SunOS (and possibly Solaris, untested), (streams)
543 never see the line discipline.
544 Since things ALWAYS work if we only open the device once, we check
545 to see if the two devices are in fact the same, then proceed to
549 (void)sprintf(device1, DEVICE1, unit);
550 (void)sprintf(device2, DEVICE2, unit);
552 if (stat(device1, &stat1)) {
553 perror("ONCORE: stat fd1");
557 if (stat(device2, &stat2)) {
558 perror("ONCORE: stat fd2");
562 /* create instance structure for this unit */
564 if (!(instance = (struct instance *) malloc(sizeof *instance))) {
568 memset((char *) instance, 0, sizeof *instance);
570 if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino)) {
571 /* same device here */
572 if (!(fd1 = refclock_open(device1, SPEED, LDISC_RAW
573 #if !defined(HAVE_PPSAPI) && !defined(TIOCDCDTIMESTAMP)
577 perror("ONCORE: fd1");
581 } else { /* different devices here */
582 if (!(fd1=refclock_open(device1, SPEED, LDISC_RAW))) {
583 perror("ONCORE: fd1");
586 if ((fd2=open(device2, O_RDWR)) < 0) {
587 perror("ONCORE: fd2");
592 /* initialize miscellaneous variables */
595 pp->unitptr = (caddr_t) instance;
597 instance->unit = unit;
598 instance->peer = peer;
599 instance->assert = 1;
602 cp = "ONCORE DRIVER -- CONFIGURING";
603 record_clock_stats(&(instance->peer->srcadr), cp);
605 instance->o_state = ONCORE_NO_IDEA;
606 cp = "state = ONCORE_NO_IDEA";
607 record_clock_stats(&(instance->peer->srcadr), cp);
609 instance->ttyfd = fd1;
610 instance->ppsfd = fd2;
612 instance->Bj_day = -1;
613 instance->traim = -1;
614 instance->traim_in = -1;
615 instance->chan_in = -1;
616 instance->model = ONCORE_UNKNOWN;
617 instance->mode = MODE_UNKNOWN;
618 instance->site_survey = ONCORE_SS_UNKNOWN;
619 instance->Ag = 0xff; /* Satellite mask angle, unset by user */
620 instance->ant_state = ONCORE_ANTENNA_UNKNOWN;
622 peer->precision = -26;
625 pp->clockdesc = "Motorola Oncore GPS Receiver";
626 memcpy((char *)&pp->refid, "GPS\0", (size_t) 4);
628 /* go read any input data in /etc/ntp.oncoreX or /etc/ntp/oncore.X */
630 oncore_read_config(instance);
633 if (time_pps_create(fd2, &instance->pps_h) < 0) {
634 perror("time_pps_create");
638 if (instance->assert)
639 cp = "Initializing timing to Assert.";
641 cp = "Initializing timing to Clear.";
642 record_clock_stats(&(instance->peer->srcadr), cp);
644 if (instance->hardpps) {
646 record_clock_stats(&(instance->peer->srcadr), cp);
649 if (!oncore_ppsapi(instance))
653 pp->io.clock_recv = oncore_receive;
654 pp->io.srcclock = (caddr_t)peer;
657 if (!io_addclock(&pp->io)) {
658 perror("io_addclock");
664 #ifdef ONCORE_SHMEM_STATUS
666 * Before starting ONCORE, lets setup SHMEM
667 * This will include merging an old SHMEM into the new one if
668 * an old one is found.
671 oncore_init_shmem(instance);
675 * This will return the Model of the Oncore receiver.
676 * and start the Initialization loop in oncore_msg_Cj.
679 instance->o_state = ONCORE_CHECK_ID;
680 cp = "state = ONCORE_CHECK_ID";
681 record_clock_stats(&(instance->peer->srcadr), cp);
683 instance->timeout = 4;
684 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Set Posn Fix mode (not Idle (VP)) */
685 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
687 instance->pollcnt = 2;
693 * Fudge control (get Flag2 and Flag3, not available at oncore_start time.
698 int unit, /* unit (not used) */
699 struct refclockstat *in, /* input parameters (not used) */
700 struct refclockstat *out, /* output parameters (not used) */
701 struct peer *peer /* peer structure pointer */
705 struct refclockproc *pp;
706 struct instance *instance;
709 instance = (struct instance *) pp->unitptr;
711 instance->assert = !(pp->sloppyclockflag & CLK_FLAG2);
712 instance->hardpps = pp->sloppyclockflag & CLK_FLAG3;
714 if (instance->assert)
715 cp = "Resetting timing to Assert.";
717 cp = "Resetting timing to Clear.";
718 record_clock_stats(&(instance->peer->srcadr), cp);
720 if (instance->hardpps) {
722 record_clock_stats(&(instance->peer->srcadr), cp);
725 (void) oncore_ppsapi(instance);
731 * oncore_shutdown - shut down the clock
740 register struct instance *instance;
741 struct refclockproc *pp;
744 instance = (struct instance *) pp->unitptr;
746 io_closeclock(&pp->io);
748 close(instance->ttyfd);
749 close(instance->ppsfd);
750 if (instance->shmemfd)
751 close(instance->shmemfd);
758 * oncore_poll - called by the transmit procedure
767 struct instance *instance;
769 instance = (struct instance *) peer->procptr->unitptr;
770 if (instance->timeout) {
774 if (instance->timeout == 0) {
775 cp = "Oncore: No response from @@Cj, shutting down driver";
776 record_clock_stats(&(instance->peer->srcadr), cp);
777 oncore_shutdown(unit, peer);
779 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
780 cp = "Oncore: Resend @@Cj";
781 record_clock_stats(&(instance->peer->srcadr), cp);
786 if (!instance->pollcnt)
787 refclock_report(peer, CEVNT_TIMEOUT);
790 peer->procptr->polls++;
791 instance->polled = 1;
803 struct instance *instance
808 if (time_pps_getcap(instance->pps_h, &mode) < 0) {
809 msyslog(LOG_ERR, "refclock_ioctl: time_pps_getcap failed: %m");
813 if (time_pps_getparams(instance->pps_h, &instance->pps_p) < 0) {
814 msyslog(LOG_ERR, "refclock_ioctl: time_pps_getparams failed: %m");
818 /* nb. only turn things on, if someone else has turned something
819 * on before we get here, leave it alone!
822 if (instance->assert) { /* nb, default or ON */
823 instance->pps_p.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
824 instance->pps_p.assert_offset.tv_sec = 0;
825 instance->pps_p.assert_offset.tv_nsec = 0;
827 instance->pps_p.mode = PPS_CAPTURECLEAR | PPS_OFFSETCLEAR;
828 instance->pps_p.clear_offset.tv_sec = 0;
829 instance->pps_p.clear_offset.tv_nsec = 0;
831 instance->pps_p.mode |= PPS_TSFMT_TSPEC;
832 instance->pps_p.mode &= mode; /* only set what is legal */
834 if (time_pps_setparams(instance->pps_h, &instance->pps_p) < 0) {
835 perror("time_pps_setparams");
839 /* If HARDPPS is on, we tell kernel */
841 if (instance->hardpps) {
844 if (instance->assert)
845 i = PPS_CAPTUREASSERT;
847 i = PPS_CAPTURECLEAR;
850 if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i,
851 PPS_TSFMT_TSPEC) < 0) {
852 msyslog(LOG_ERR, "refclock_ioctl: time_pps_kcbind failed: %m");
864 #ifdef ONCORE_SHMEM_STATUS
867 struct instance *instance
870 int i, l, n, fd, shmem_old_size, n1;
872 u_char *cp, *cp1, *shmem_old;
878 * The first thing we do is see if there is an instance->shmem_fname file (still)
879 * out there from a previous run. If so, we copy it in and use it to initialize
880 * shmem (so we won't lose our almanac if we need it).
884 if ((fd = open(instance->shmem_fname, O_RDONLY)) < 0)
885 perror("LOAD:SHMEM");
888 shmem_old_size = sbuf.st_size;
889 shmem_old = (u_char *) malloc((unsigned) sbuf.st_size);
890 if (shmem_old == NULL) {
896 read(fd, shmem_old, shmem_old_size);
900 /* OK, we now create the NEW SHMEM. */
902 if ((instance->shmemfd = open(instance->shmem_fname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) {
903 perror(instance->shmem_fname);
907 /* see how big it needs to be */
910 for (mp=oncore_messages; mp->flag[0]; mp++) {
912 /* Allocate space for multiplexed almanac, and 0D/2D/3D @@Ea records */
913 if (!strcmp(mp->flag, "Cb")) {
914 instance->shmem_Cb = n;
915 n += (mp->len + 3) * 34;
917 if (!strcmp(mp->flag, "Ba")) {
918 instance->shmem_Ba = n;
919 n += (mp->len + 3) * 3;
921 if (!strcmp(mp->flag, "Ea")) {
922 instance->shmem_Ea = n;
923 n += (mp->len + 3) * 3;
925 if (!strcmp(mp->flag, "Ha")) {
926 instance->shmem_Ha = n;
927 n += (mp->len + 3) * 3;
931 shmem_length = n + 2;
932 fprintf(stderr, "ONCORE: SHMEM length: %d bytes\n", (int) shmem_length);
934 buf = malloc(shmem_length);
937 close(instance->shmemfd);
941 memset(buf, 0, shmem_length);
943 /* next build the new SHMEM buffer in memory */
945 for (mp=oncore_messages; mp->flag[0]; mp++) {
947 buf[l + 0] = mp->len >> 8;
948 buf[l + 1] = mp->len & 0xff;
952 buf[l + 5] = mp->flag[0];
953 buf[l + 6] = mp->flag[1];
954 if (!strcmp(mp->flag, "Cb") || !strcmp(mp->flag, "Ba") || !strcmp(mp->flag, "Ea") || !strcmp(mp->flag, "Ha")) {
955 if (!strcmp(mp->flag, "Cb"))
959 for (i=1; i<n; i++) {
960 buf[l + i * (mp->len+3) + 0] = mp->len >> 8;
961 buf[l + i * (mp->len+3) + 1] = mp->len & 0xff;
962 buf[l + i * (mp->len+3) + 2] = 0;
963 buf[l + i * (mp->len+3) + 3] = '@';
964 buf[l + i * (mp->len+3) + 4] = '@';
965 buf[l + i * (mp->len+3) + 5] = mp->flag[0];
966 buf[l + i * (mp->len+3) + 6] = mp->flag[1];
971 /* we now walk thru the two buffers (shmem_old and buf, soon to become shmem)
972 * copying the data in shmem_old to buf. When we are done we write it out
973 * and free both buffers.
974 * If the structures change (an addition or deletion) I will stop copying.
975 * The two will be the same unless we add/subtract from the oncore_messages list
976 * so this should work most of the time, and takes a lot less code than doing it right.
980 for (cp=buf+4, cp1=shmem_old+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3), cp1+=(n+3)) {
981 n1 = 256*(*(cp1-3)) + *(cp1-2);
982 if (n1 != n || strncmp(cp, cp1, 4))
985 memcpy(cp, cp1, (size_t) n);
990 i = write(instance->shmemfd, buf, shmem_length);
993 if (i != shmem_length) {
994 perror(instance->shmem_fname);
995 close(instance->shmemfd);
999 instance->shmem = (u_char *) mmap(0, shmem_length,
1000 PROT_READ | PROT_WRITE,
1001 #ifdef MAP_HASSEMAPHORE
1004 MAP_SHARED, instance->shmemfd, (off_t)0);
1006 if (instance->shmem == (u_char *)MAP_FAILED) {
1007 instance->shmem = 0;
1008 close(instance->shmemfd);
1012 sprintf(Msg, "SHMEM (size = %d) is CONFIGURED and available as %s", shmem_length, instance->shmem_fname);
1013 record_clock_stats(&(instance->peer->srcadr), Msg);
1015 #endif /* ONCORE_SHMEM_STATUS */
1020 * Read Input file if it exists.
1025 struct instance *instance
1029 * First we try to open the configuration file
1031 * where N is the unit number viz 127.127.30.N.
1032 * If we don't find it we try
1037 * If we don't find any then we don't have the cable delay or PPS offset
1038 * and we choose MODE (4) below.
1040 * Five Choices for MODE
1041 * (0) ONCORE is preinitialized, don't do anything to change it.
1042 * nb, DON'T set 0D mode, DON'T set Delay, position...
1043 * (1) NO RESET, Read Position, delays from data file, lock it in, go to 0D mode.
1044 * (2) NO RESET, Read Delays from data file, do SITE SURVEY to get position,
1045 * lock this in, go to 0D mode.
1046 * (3) HARD RESET, Read Position, delays from data file, lock it in, go to 0D mode.
1047 * (4) HARD RESET, Read Delays from data file, do SITE SURVEY to get position,
1048 * lock this in, go to 0D mode.
1049 * NB. If a POSITION is specified in the config file with mode=(2,4) [SITE SURVEY]
1050 * then this position is set as the INITIAL position of the ONCORE.
1051 * This can reduce the time to first fix.
1052 * -------------------------------------------------------------------------------
1053 * Note that an Oncore UT without a battery backup retains NO information if it is
1054 * power cycled, with a Battery Backup it remembers the almanac, etc.
1055 * For an Oncore VP, there is an eeprom that will contain this data, along with the
1056 * option of Battery Backup.
1057 * So a UT without Battery Backup is equivalent to doing a HARD RESET on each
1058 * power cycle, since there is nowhere to store the data.
1059 * -------------------------------------------------------------------------------
1061 * If we open one or the other of the files, we read it looking for
1062 * MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET, ASSERT, CLEAR, HARDPPS,
1063 * STATUS, POSN3D, POSN2D, CHAN, TRAIM
1064 * then initialize using method MODE. For Mode = (1,3) all of (LAT, LON, HT) must
1065 * be present or mode reverts to (2,4).
1069 * # is comment to end of line
1070 * = allowed between 1st and 2nd fields.
1072 * Expect to see one line with 'MODE' as first field, followed by an integer
1073 * in the range 0-4 (default = 4).
1075 * Expect to see two lines with 'LONG', 'LAT' followed by 1-3 fields.
1076 * All numbers are floating point.
1081 * Expect to see one line with 'HT' as first field,
1082 * followed by 1-2 fields. First is a number, the second is 'FT' or 'M'
1083 * for feet or meters. HT is the height above the GPS ellipsoid.
1084 * If the receiver reports height in both GPS and MSL, then we will report
1085 * the difference GPS-MSL on the clockstats file.
1087 * There is an optional line, starting with DELAY, followed
1088 * by 1 or two fields. The first is a number (a time) the second is
1089 * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
1090 * DELAY is cable delay, typically a few tens of ns.
1092 * There is an optional line, starting with OFFSET, followed
1093 * by 1 or two fields. The first is a number (a time) the second is
1094 * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
1095 * OFFSET is the offset of the PPS pulse from 0. (only fully implemented
1096 * with the PPSAPI, we need to be able to tell the Kernel about this
1097 * offset if the Kernel PLL is in use, but can only do this presently
1098 * when using the PPSAPI interface. If not using the Kernel PLL,
1099 * then there is no problem.
1101 * There is an optional line, with either ASSERT or CLEAR on it, which
1102 * determine which transition of the PPS signal is used for timing by the
1103 * PPSAPI. If neither is present, then ASSERT is assumed.
1104 * ASSERT/CLEAR can also be set with FLAG2 of the ntp.conf input.
1105 * For Flag2, ASSERT=0, and hence is default.
1107 * There is an optional line, with HARDPPS on it. Including this line causes
1108 * the PPS signal to control the kernel PLL.
1109 * HARDPPS can also be set with FLAG3 of the ntp.conf input.
1110 * For Flag3, 0 is disabled, and the default.
1112 * There are three options that have to do with using the shared memory option.
1113 * First, to enable the option there must be a SHMEM line with a file name.
1114 * The file name is the file associated with the shared memory.
1116 * In shared memory, there is one 'record' for each returned variable.
1117 * For the @@Ea data there are three 'records' containing position data.
1118 * There will always be data in the record corresponding to the '0D' @@Ea record,
1119 * and the user has a choice of filling the '3D' record by specifying POSN3D,
1120 * or the '2D' record by specifying POSN2D. In either case the '2D' or '3D'
1121 * record is filled once every 15s.
1123 * Two additional variables that can be set are CHAN and TRAIM. These should be
1124 * set correctly by the code examining the @@Cj record, but we bring them out here
1125 * to allow the user to override either the # of channels, or the existence of TRAIM.
1126 * CHAN expects to be followed by in integer: 6, 8, or 12. TRAIM expects to be
1127 * followed by YES or NO.
1129 * There is an optional line with MASK on it followed by one integer field in the
1130 * range 0 to 89. This sets the satellite mask angle and will determine the minimum
1131 * elevation angle for satellites to be tracked by the receiver. The default value
1132 * is 10 deg for the VP and 0 deg for all other receivers.
1134 * So acceptable input would be
1135 * # these are my coordinates (RWC)
1138 * HT 1589 # could equally well say HT 5215 FT
1143 char *cp, *cc, *ca, line[100], units[2], device[20], Msg[160];
1144 int i, sign, lat_flg, long_flg, ht_flg, mode, mask;
1147 sprintf(device, "%s%d", INIT_FILE, instance->unit); /* try "ntp.oncore0" first */
1148 if ((fd=fopen(device, "r")) == NULL) { /* it was in the original documentation */
1149 sprintf(device, "%s.%d", INIT_FILE, instance->unit); /* then try "ntp.oncore.0 */
1150 if ((fd=fopen(device, "r")) == NULL) {
1151 if ((fd=fopen(INIT_FILE, "r")) == NULL) { /* and finally "ntp.oncore" */
1152 instance->init_type = 4;
1159 lat_flg = long_flg = ht_flg = 0;
1160 while (fgets(line, 100, fd)) {
1162 /* Remove comments */
1163 if ((cp = strchr(line, '#')))
1166 /* Remove trailing space */
1167 for (i = strlen(line);
1168 i > 0 && isascii((int)line[i - 1]) && isspace((int)line[i - 1]);
1172 /* Remove leading space */
1173 for (cc = line; *cc && isascii((int)*cc) && isspace((int)*cc); cc++)
1176 /* Stop if nothing left */
1180 /* Uppercase the command and find the arg */
1181 for (ca = cc; *ca; ca++) {
1182 if (isascii((int)*ca)) {
1183 if (islower((int)*ca)) {
1185 } else if (isspace((int)*ca) || (*ca == '='))
1190 /* Remove space (and possible =) leading the arg */
1191 for (; *ca && isascii((int)*ca) && (isspace((int)*ca) || (*ca == '=')); ca++)
1194 if (!strncmp(cc, "STATUS", (size_t) 6) || !strncmp(cc, "SHMEM", (size_t) 5)) {
1196 instance->shmem_fname = (char *) malloc((unsigned) (i+1));
1197 strcpy(instance->shmem_fname, ca);
1201 /* Uppercase argument as well */
1202 for (cp = ca; *cp; cp++)
1203 if (isascii((int)*cp) && islower((int)*cp))
1206 if (!strncmp(cc, "LAT", (size_t) 3)) {
1208 sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
1214 instance->ss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
1216 } else if (!strncmp(cc, "LON", (size_t) 3)) {
1218 sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
1224 instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
1226 } else if (!strncmp(cc, "HT", (size_t) 2)) {
1229 sscanf(ca, "%lf %1s", &f1, units);
1230 if (units[0] == 'F')
1232 instance->ss_ht = 100 * f1; /* cm */
1234 } else if (!strncmp(cc, "DELAY", (size_t) 5)) {
1237 sscanf(ca, "%lf %1s", &f1, units);
1238 if (units[0] == 'N')
1240 else if (units[0] == 'U')
1242 else if (units[0] == 'M')
1245 f1 = 1000000000 * f1;
1246 if (f1 < 0 || f1 > 1.e9)
1248 if (f1 < 0 || f1 > 999999) {
1249 sprintf(Msg, "PPS Cable delay of %fns out of Range, ignored", f1);
1250 record_clock_stats(&(instance->peer->srcadr), Msg);
1252 instance->delay = f1; /* delay in ns */
1253 } else if (!strncmp(cc, "OFFSET", (size_t) 6)) {
1256 sscanf(ca, "%lf %1s", &f1, units);
1257 if (units[0] == 'N')
1259 else if (units[0] == 'U')
1261 else if (units[0] == 'M')
1264 f1 = 1000000000 * f1;
1265 if (f1 < 0 || f1 > 1.e9)
1267 if (f1 < 0 || f1 > 999999999.) {
1268 sprintf(Msg, "PPS Offset of %fns out of Range, ignored", f1);
1269 record_clock_stats(&(instance->peer->srcadr), Msg);
1271 instance->offset = f1; /* offset in ns */
1272 } else if (!strncmp(cc, "MODE", (size_t) 4)) {
1273 sscanf(ca, "%d", &mode);
1274 if (mode < 0 || mode > 4)
1276 } else if (!strncmp(cc, "ASSERT", (size_t) 6)) {
1277 instance->assert = 1;
1278 } else if (!strncmp(cc, "CLEAR", (size_t) 5)) {
1279 instance->assert = 0;
1280 } else if (!strncmp(cc, "HARDPPS", (size_t) 7)) {
1281 instance->hardpps = 1;
1282 } else if (!strncmp(cc, "POSN2D", (size_t) 6)) {
1283 instance->shmem_Posn = 2;
1284 } else if (!strncmp(cc, "POSN3D", (size_t) 6)) {
1285 instance->shmem_Posn = 3;
1286 } else if (!strncmp(cc, "CHAN", (size_t) 4)) {
1287 sscanf(ca, "%d", &i);
1288 if ((i == 6) || (i == 8) || (i == 12))
1289 instance->chan_in = i;
1290 } else if (!strncmp(cc, "TRAIM", (size_t) 5)) {
1291 instance->traim_in = 1; /* so TRAIM alone is YES */
1292 if (!strcmp(ca, "NO") || !strcmp(ca, "OFF")) /* Yes/No, On/Off */
1293 instance->traim_in = 0;
1294 } else if (!strncmp(cc, "MASK", (size_t) 4)) {
1295 sscanf(ca, "%d", &mask);
1296 if (mask > -1 && mask < 90)
1297 instance->Ag = mask; /* Satellite mask angle */
1303 * OK, have read all of data file, and extracted the good stuff.
1304 * If lat/long/ht specified they ALL must be specified for mode = (1,3).
1307 instance->posn_set = 1;
1308 if (!( lat_flg && long_flg && ht_flg )) {
1309 printf("ONCORE: incomplete data on %s\n", INIT_FILE);
1310 instance->posn_set = 0;
1311 if (mode == 1 || mode == 3) {
1312 sprintf(Msg, "Input Mode = %d, but no/incomplete position, mode set to %d", mode, mode+1);
1313 record_clock_stats(&(instance->peer->srcadr), Msg);
1317 instance->init_type = mode;
1319 sprintf(Msg, "Input mode = %d", mode);
1320 record_clock_stats(&(instance->peer->srcadr), Msg);
1326 * move data from NTP to buffer (toss the extra in the unlikely case it won't fit)
1331 struct recvbuf *rbufp
1337 struct instance *instance;
1339 peer = (struct peer *)rbufp->recv_srcclock;
1340 instance = (struct instance *) peer->procptr->unitptr;
1341 p = (u_char *) &rbufp->recv_space;
1346 printf("ONCORE: >>>");
1347 for(i=0; i<rbufp->recv_length; i++)
1348 printf("%02x ", p[i]);
1350 printf("ONCORE: >>>");
1351 for(i=0; i<rbufp->recv_length; i++)
1352 printf("%03o ", p[i]);
1357 i = rbufp->recv_length;
1358 if (rcvbuf+rcvptr+i > &rcvbuf[sizeof rcvbuf])
1359 i = sizeof(rcvbuf) - rcvptr; /* and some char will be lost */
1360 memcpy(rcvbuf+rcvptr, p, i);
1362 oncore_consume(instance);
1368 * Deal with any complete messages
1373 struct instance *instance
1379 while (rcvptr >= 7) {
1380 if (rcvbuf[0] != '@' || rcvbuf[1] != '@') {
1381 /* We're not in sync, lets try to get there */
1382 for (i=1; i < rcvptr-1; i++)
1383 if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@')
1386 printf("ONCORE[%d]: >>> skipping %d chars\n", instance->unit, i);
1388 memcpy(rcvbuf, rcvbuf+i, (size_t)(rcvptr-i));
1393 /* Ok, we have a header now */
1394 l = sizeof(oncore_messages)/sizeof(oncore_messages[0]) -1;
1396 if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), (size_t) 2))
1400 printf("ONCORE[%d]: >>> Unknown MSG, skipping 4 (%c%c)\n", instance->unit, rcvbuf[2], rcvbuf[3]);
1401 memcpy(rcvbuf, rcvbuf+4, (size_t) 4);
1406 l = oncore_messages[m].len;
1409 printf("ONCORE[%d]: GOT: %c%c %d of %d entry %d\n", instance->unit, rcvbuf[2], rcvbuf[3], rcvptr, l, m);
1411 /* Got the entire message ? */
1416 /* are we at the end of message? should be <Cksum><CR><LF> */
1418 if (rcvbuf[l-2] != '\r' || rcvbuf[l-1] != '\n') {
1420 printf("ONCORE[%d]: NO <CR><LF> at end of message\n", instance->unit);
1421 } else { /* check the CheckSum */
1422 if (oncore_checksum_ok(rcvbuf, l)) {
1423 if (instance->shmem != NULL) {
1424 instance->shmem[oncore_messages[m].shmem + 2]++;
1425 memcpy(instance->shmem + oncore_messages[m].shmem + 3,
1426 rcvbuf, (size_t) l);
1428 oncore_msg_any(instance, rcvbuf, (size_t) (l-3), m);
1429 if (oncore_messages[m].handler)
1430 oncore_messages[m].handler(instance, rcvbuf, (size_t) (l-3));
1432 printf("ONCORE[%d]: Checksum mismatch!\n", instance->unit);
1433 printf("ONCORE[%d]: @@%c%c ", instance->unit, rcvbuf[2], rcvbuf[3]);
1435 printf("%03o ", rcvbuf[i]);
1441 memcpy(rcvbuf, rcvbuf+l, (size_t) (rcvptr-l));
1449 oncore_get_timestamp(
1450 struct instance *instance,
1451 long dt1, /* tick offset THIS time step */
1452 long dt2 /* tick offset NEXT time step */
1459 #ifdef HAVE_STRUCT_TIMESPEC
1460 struct timespec *tsp = 0;
1462 struct timeval *tsp = 0;
1466 pps_params_t current_params;
1467 struct timespec timeout;
1469 #else /* ! HAVE_PPSAPI */
1470 #ifdef HAVE_CIOGETEV
1471 struct ppsclockev ev;
1474 #ifdef HAVE_TIOCGPPSEV
1475 struct ppsclockev ev;
1478 #if TIOCDCDTIMESTAMP
1481 #endif /* ! HAVE_PPS_API */
1484 /* If we are in SiteSurvey mode, then we are in 3D mode, and we fall thru.
1485 * If we have Finished the SiteSurvey, then we fall thru for the 14/15
1486 * times we get here in 0D mode (the 1/15 is in 3D for SHMEM).
1487 * This gives good time, which gets better when the SS is done.
1490 if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D))
1492 /* old check, only fall thru for SS_DONE and 0D mode, 2h45m wait for ticks */
1494 if ((instance->site_survey != ONCORE_SS_DONE) || (instance->mode != MODE_0D))
1498 /* Don't do anything without an almanac to define the GPS->UTC delta */
1500 if (instance->rsm.bad_almanac)
1504 j = instance->ev_serial;
1506 timeout.tv_nsec = 0;
1507 if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i,
1509 printf("ONCORE: time_pps_fetch failed\n");
1513 if (instance->assert) {
1514 tsp = &pps_i.assert_timestamp;
1517 i = (u_long) pps_i.assert_sequence;
1518 #ifdef HAVE_STRUCT_TIMESPEC
1519 printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n",
1520 instance->unit, i, j,
1521 (long)tsp->tv_sec, (long)tsp->tv_nsec);
1523 printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n",
1524 instance->unit, i, j,
1525 (long)tsp->tv_sec, (long)tsp->tv_usec);
1529 if (pps_i.assert_sequence == j) {
1530 printf("ONCORE: oncore_get_timestamp, error serial pps\n");
1533 instance->ev_serial = pps_i.assert_sequence;
1535 tsp = &pps_i.clear_timestamp;
1538 i = (u_long) pps_i.clear_sequence;
1539 #ifdef HAVE_STRUCT_TIMESPEC
1540 printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n",
1541 instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_nsec);
1543 printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n",
1544 instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_usec);
1548 if (pps_i.clear_sequence == j) {
1549 printf("ONCORE: oncore_get_timestamp, error serial pps\n");
1552 instance->ev_serial = pps_i.clear_sequence;
1555 /* convert timespec -> ntp l_fp */
1559 ts.l_uf = dmy * 4294967296.0;
1560 ts.l_ui = tsp->tv_sec;
1562 alternate code for previous 4 lines is
1563 dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */
1565 dmy = tsp->tv_sec; /* integer part */
1566 DTOLFP(dmy, &ts_tmp);
1567 L_ADD(&ts, &ts_tmp);
1569 dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */
1571 ts.l_ui = tsp->tv_sec;
1574 # if defined(HAVE_TIOCGPPSEV) || defined(HAVE_CIOGETEV)
1575 j = instance->ev_serial;
1576 if (ioctl(instance->ppsfd, r, (caddr_t) &ev) < 0) {
1577 perror("ONCORE: IOCTL:");
1584 #ifdef HAVE_STRUCT_TIMESPEC
1585 printf("ONCORE: serial/j (%d, %d) %ld.%09ld\n",
1586 ev.serial, j, tsp->tv_sec, tsp->tv_nsec);
1588 printf("ONCORE: serial/j (%d, %d) %ld.%06ld\n",
1589 ev.serial, j, tsp->tv_sec, tsp->tv_usec);
1592 if (ev.serial == j) {
1593 printf("ONCORE: oncore_get_timestamp, error serial pps\n");
1596 instance->ev_serial = ev.serial;
1598 /* convert timeval -> ntp l_fp */
1602 # if defined(TIOCDCDTIMESTAMP)
1603 if(ioctl(instance->ppsfd, TIOCDCDTIMESTAMP, &tv) < 0) {
1604 perror("ONCORE: ioctl(TIOCDCDTIMESTAMP)");
1610 #error "Cannot compile -- no PPS mechanism configured!"
1614 /* now have timestamp in ts */
1615 /* add in saw_tooth and offset, these will be ZERO if no TRAIM */
1617 /* saw_tooth not really necessary if using TIMEVAL */
1618 /* since its only precise to us, but do it anyway. */
1620 /* offset in ns, and is positive (late), we subtract */
1621 /* to put the PPS time transition back where it belongs */
1624 /* must hand the offset for the NEXT sec off to the Kernel to do */
1625 /* the addition, so that the Kernel PLL sees the offset too */
1627 if (instance->assert)
1628 instance->pps_p.assert_offset.tv_nsec = -dt2;
1630 instance->pps_p.clear_offset.tv_nsec = -dt2;
1632 /* The following code is necessary, and not just a time_pps_setparams,
1633 * using the saved instance->pps_p, since some other process on the
1634 * machine may have diddled with the mode bits (say adding something
1635 * that it needs). We take what is there and ADD what we need.
1636 * [[ The results from the time_pps_getcap is unlikely to change so
1637 * we could probably just save it, but I choose to do the call ]]
1638 * Unfortunately, there is only ONE set of mode bits in the kernel per
1639 * interface, and not one set for each open handle.
1641 * There is still a race condition here where we might mess up someone
1642 * elses mode, but if he is being careful too, he should survive.
1645 if (time_pps_getcap(instance->pps_h, ¤t_mode) < 0) {
1646 msyslog(LOG_ERR, "refclock_ioctl: time_pps_getcap failed: %m");
1650 if (time_pps_getparams(instance->pps_h, ¤t_params) < 0) {
1651 msyslog(LOG_ERR, "refclock_ioctl: time_pps_getparams failed: %m");
1655 /* or current and mine */
1656 current_params.mode |= instance->pps_p.mode;
1657 /* but only set whats legal */
1658 current_params.mode &= current_mode;
1660 current_params.assert_offset.tv_sec = 0;
1661 current_params.assert_offset.tv_nsec = -dt2;
1662 current_params.clear_offset.tv_sec = 0;
1663 current_params.clear_offset.tv_nsec = -dt2;
1665 if (time_pps_setparams(instance->pps_h, ¤t_params))
1666 perror("time_pps_setparams");
1668 /* if not PPSAPI, no way to inform kernel of OFFSET, just add the */
1669 /* offset for THIS second */
1672 DTOLFP(dmy, &ts_tmp);
1673 L_ADD(&ts, &ts_tmp);
1675 /* have time from UNIX origin, convert to NTP origin. */
1677 ts.l_ui += JAN_1970;
1678 instance->pp->lastrec = ts;
1680 /* print out information about this timestamp (long line) */
1683 ts_tmp.l_ui = 0; /* zero integer part */
1684 LFPTOD(&ts_tmp, dmy); /* convert fractional part to a double */
1685 j = 1.0e9*dmy; /* then to integer ns */
1688 if (instance->chan == 6)
1689 Rsm = instance->BEHa[64];
1690 else if (instance->chan == 8)
1691 Rsm = instance->BEHa[72];
1692 else if (instance->chan == 12)
1693 Rsm = ((instance->BEHa[129]<<8) | instance->BEHa[130]);
1695 if (instance->chan == 6 || instance->chan == 8) {
1696 sprintf(instance->pp->a_lastcode, /* MAX length 128, currently at 117 */
1697 "%u.%09lu %d %d %2d %2d %2d %2ld rstat %02x dop %4.1f nsat %2d,%d traim %d sigma %2d neg-sawtooth %3d sat %d%d%d%d%d%d%d%d",
1699 instance->pp->year, instance->pp->day,
1700 instance->pp->hour, instance->pp->minute, instance->pp->second,
1701 (long) tsp->tv_sec % 60,
1702 Rsm, 0.1*(256*instance->BEHa[35]+instance->BEHa[36]),
1704 instance->BEHa[38], instance->BEHa[39], instance->BEHn[21],
1705 /* nsat visible, nsat tracked, traim */
1706 instance->BEHn[23]*256+instance->BEHn[24], (s_char) instance->BEHn[25],
1707 /* sigma neg-sawtooth */
1708 /*sat*/ instance->BEHa[41], instance->BEHa[45], instance->BEHa[49], instance->BEHa[53],
1709 instance->BEHa[57], instance->BEHa[61], instance->BEHa[65], instance->BEHa[69]
1710 ); /* will be 0 for 6 chan */
1711 } else if (instance->chan == 12) {
1712 sprintf(instance->pp->a_lastcode,
1713 "%u.%09lu %d %d %2d %2d %2d %2ld rstat %02x dop %4.1f nsat %2d,%d traim %d sigma %d neg-sawtooth %3d sat %d%d%d%d%d%d%d%d%d%d%d%d",
1715 instance->pp->year, instance->pp->day,
1716 instance->pp->hour, instance->pp->minute, instance->pp->second,
1717 (long) tsp->tv_sec % 60,
1718 Rsm, 0.1*(256*instance->BEHa[53]+instance->BEHa[54]),
1720 instance->BEHa[55], instance->BEHa[56], instance->BEHn[6],
1721 /* nsat visible, nsat tracked traim */
1722 instance->BEHn[12]*256+instance->BEHn[13], (s_char) instance->BEHn[14],
1723 /* sigma neg-sawtooth */
1724 /*sat*/ instance->BEHa[58], instance->BEHa[64], instance->BEHa[70], instance->BEHa[76],
1725 instance->BEHa[82], instance->BEHa[88], instance->BEHa[94], instance->BEHa[100],
1726 instance->BEHa[106], instance->BEHa[112], instance->BEHa[118], instance->BEHa[124]
1732 n = strlen(instance->pp->a_lastcode);
1733 printf("ONCORE[%d]: len = %d %s\n", instance->unit, n, instance->pp->a_lastcode);
1736 /* and some things I dont understnd (magic ntp things) */
1738 if (!refclock_process(instance->pp)) {
1739 refclock_report(instance->peer, CEVNT_BADTIME);
1743 record_clock_stats(&(instance->peer->srcadr), instance->pp->a_lastcode);
1744 instance->pollcnt = 2;
1746 if (instance->polled) {
1747 instance->polled = 0;
1749 instance->pp->dispersion = instance->pp->skew = 0;
1751 instance->pp->lastref = instance->pp->lastrec;
1752 refclock_receive(instance->peer);
1757 /*************** oncore_msg_XX routines start here *******************/
1761 * print Oncore response message.
1766 struct instance *instance,
1773 const char *fmt = oncore_messages[idx].fmt;
1775 #ifdef HAVE_GETCLOCK
1781 #ifdef HAVE_GETCLOCK
1782 (void) getclock(TIMEOFDAY, &ts);
1783 tv.tv_sec = ts.tv_sec;
1784 tv.tv_usec = ts.tv_nsec / 1000;
1786 GETTIMEOFDAY(&tv, 0);
1788 printf("ONCORE[%d]: %ld.%06ld\n", instance->unit, (long) tv.tv_sec, (long) tv.tv_usec);
1791 printf(">>@@%c%c ", buf[2], buf[3]);
1792 for(i=2; i < len && i < 2400 ; i++)
1793 printf("%02x", buf[i]);
1798 for (p = fmt; *p; p++) {
1802 printf("\n%c%c", buf[2], buf[3]);
1804 for (p = fmt; *p; p++) {
1805 printf("%02x", buf[i++]);
1814 /* Latitude, Longitude, Height */
1818 struct instance *instance,
1831 struct instance *instance,
1835 { char Msg[160], *cp;
1838 if (instance->o_state == ONCORE_RUN)
1841 instance->Ag = buf[4];
1842 sprintf(Msg, "Satellite mask angle %s %d degrees", cp, (int) instance->Ag);
1843 record_clock_stats(&(instance->peer->srcadr), Msg);
1849 * get Position hold position
1854 struct instance *instance,
1859 instance->ss_lat = buf_w32(&buf[4]);
1860 instance->ss_long = buf_w32(&buf[8]);
1861 instance->ss_ht = buf_w32(&buf[12]);
1863 /* Print out Position */
1864 oncore_print_posn(instance);
1870 * Try to use Oncore UT+ Auto Survey Feature
1871 * If its not there (VP), set flag to do it ourselves.
1876 struct instance *instance,
1883 instance->saw_At = 1;
1884 if (instance->site_survey == ONCORE_SS_TESTING) {
1886 record_clock_stats(&(instance->peer->srcadr),
1887 "Initiating hardware 3D site survey");
1889 cp = "SSstate = ONCORE_SS_HW";
1890 record_clock_stats(&(instance->peer->srcadr), cp);
1891 instance->site_survey = ONCORE_SS_HW;
1900 * Nb. @@Ay is not supported for early UT (no plus) model
1905 struct instance *instance,
1912 if (instance->saw_Ay)
1915 instance->saw_Ay = 1;
1917 instance->offset = buf_w32(&buf[4]);
1919 sprintf(Msg, "PPS Offset is set to %ld ns", instance->offset);
1920 record_clock_stats(&(instance->peer->srcadr), Msg);
1931 struct instance *instance,
1938 if (instance->saw_Az)
1941 instance->saw_Az = 1;
1943 instance->delay = buf_w32(&buf[4]);
1945 sprintf(Msg, "Cable delay is set to %ld ns", instance->delay);
1946 record_clock_stats(&(instance->peer->srcadr), Msg);
1951 /* Ba, Ea and Ha come here, these contain Position */
1955 struct instance *instance,
1964 /* OK, we are close to the RUN state now.
1965 * But we have a few more items to initialize first.
1967 * At the beginning of this routine there are several 'timers'.
1968 * We enter this routine 1/sec, and since the upper levels of NTP have usurped
1969 * the use of timers, we use the 1/sec entry to do things that
1970 * we would normally do with timers...
1973 if (instance->o_state == ONCORE_CHECK_CHAN) { /* here while checking for the # chan */
1974 if (buf[2] == 'B') { /* 6chan */
1975 if (instance->chan_ck < 6) instance->chan_ck = 6;
1976 } else if (buf[2] == 'E') { /* 8chan */
1977 if (instance->chan_ck < 8) instance->chan_ck = 8;
1978 } else if (buf[2] == 'H') { /* 12chan */
1979 if (instance->chan_ck < 12) instance->chan_ck = 12;
1982 if (instance->count3++ < 5)
1985 instance->count3 = 0;
1987 if (instance->chan_in != -1) /* set in Input */
1988 instance->chan = instance->chan_in;
1989 else /* set from test */
1990 instance->chan = instance->chan_ck;
1992 sprintf(Msg, "Input says chan = %d", instance->chan_in);
1993 record_clock_stats(&(instance->peer->srcadr), Msg);
1994 sprintf(Msg, "Model # says chan = %d", instance->chan_id);
1995 record_clock_stats(&(instance->peer->srcadr), Msg);
1996 sprintf(Msg, "Testing says chan = %d", instance->chan_ck);
1997 record_clock_stats(&(instance->peer->srcadr), Msg);
1998 sprintf(Msg, "Using chan = %d", instance->chan);
1999 record_clock_stats(&(instance->peer->srcadr), Msg);
2001 instance->o_state = ONCORE_HAVE_CHAN;
2002 cp = "state = ONCORE_HAVE_CHAN";
2003 record_clock_stats(&(instance->peer->srcadr), cp);
2005 instance->timeout = 4;
2006 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
2010 if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN)
2015 if (instance->count) {
2016 if (instance->count++ < 5) /* make sure results are stable, using position */
2018 instance->count = 0;
2021 memcpy(instance->BEHa, buf, (size_t) (len+3)); /* Ba, Ea or Ha */
2023 /* check the antenna and almanac for changes (did it get unplugged, is it ready?) */
2025 oncore_check_almanac(instance);
2026 oncore_check_antenna(instance);
2028 /* Almanac mode, waiting for Almanac, we can't do anything till we have it */
2029 /* When we have an almanac, we will start the Bn/En/@@Hn messages */
2031 if (instance->o_state == ONCORE_ALMANAC)
2032 if (oncore_wait_almanac(instance))
2035 /* do some things once when we get this far in BaEaHa */
2037 if (instance->once) {
2039 instance->count2 = 1;
2041 /* Have we seen an @@At (position hold) command response */
2042 /* if not, message out */
2044 if (instance->chan != 12 && !instance->saw_At) {
2045 cp = "Not Good, no @@At command (no Position Hold), must be a GT/GT+";
2046 record_clock_stats(&(instance->peer->srcadr), cp);
2047 oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
2050 /* have an Almanac, can start the SiteSurvey
2051 * (actually only need to get past the almanac_load where we diddle with At
2052 * command,- we can't change it after we start the HW_SS below
2055 mode = instance->init_type;
2057 case 0: /* NO initialization, don't change anything */
2058 case 1: /* Use given Position */
2060 instance->site_survey = ONCORE_SS_DONE;
2061 cp = "SSstate = ONCORE_SS_DONE";
2062 record_clock_stats(&(instance->peer->srcadr), cp);
2066 case 4: /* Site Survey */
2067 cp = "SSstate = ONCORE_SS_TESTING";
2068 record_clock_stats(&(instance->peer->srcadr), cp);
2069 instance->site_survey = ONCORE_SS_TESTING;
2070 instance->count1 = 1;
2071 if (instance->chan == 12)
2072 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd3, sizeof(oncore_cmd_Gd3)); /* M12+T */
2074 oncore_sendmsg(instance->ttyfd, oncore_cmd_At2, sizeof(oncore_cmd_At2)); /* not GT, arg not VP */
2078 /* Read back PPS Offset for Output */
2079 /* Nb. This will fail silently for early UT (no plus) and M12 models */
2081 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ayx, sizeof(oncore_cmd_Ayx));
2083 /* Read back Cable Delay for Output */
2085 oncore_sendmsg(instance->ttyfd, oncore_cmd_Azx, sizeof(oncore_cmd_Azx));
2087 /* Read back Satellite Mask Angle for Output */
2089 oncore_sendmsg(instance->ttyfd, oncore_cmd_Agx, sizeof(oncore_cmd_Agx));
2092 if (instance->count1) {
2093 if (instance->count1++ > 5 || instance->site_survey == ONCORE_SS_HW) {
2094 instance->count1 = 0;
2095 if (instance->site_survey == ONCORE_SS_TESTING) {
2097 * For instance->site_survey to still be ONCORE_SS_TESTING, then after a 5sec
2098 * wait after the @@At2/@@Gd3 command we have not changed the state to
2099 * ONCORE_SS_HW. If the Hardware is capable of doing a Site Survey, then
2100 * the variable would have been changed by now.
2101 * There are three possibilities:
2103 * (a) We did not get a response to the @@At0 or @@At2 commands,
2104 * and it must be a GT/GT+/SL with no position hold mode.
2105 * We will have to do it ourselves.
2106 * (b) We saw the @@At0, @@At2 commands, but @@At2 failed,
2107 * must be a VP or older UT which doesn't have Site Survey mode.
2108 * We will have to do it ourselves.
2110 * (c) We saw the @@Gd command, but @@Gd3 failed,
2111 * We will have to do it ourselves.
2114 sprintf(Msg, "Initiating software 3D site survey (%d samples)",
2116 record_clock_stats(&(instance->peer->srcadr), Msg);
2118 record_clock_stats(&(instance->peer->srcadr), "SSstate = ONCORE_SS_SW");
2119 instance->site_survey = ONCORE_SS_SW;
2121 instance->ss_lat = instance->ss_long = instance->ss_ht = 0;
2122 if (instance->chan == 12)
2123 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* disable */
2125 oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* disable */
2126 oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* disable */
2132 /* check the mode we are in 0/2/3D */
2134 if (instance->chan == 6) {
2135 if (instance->BEHa[64]&0x8)
2136 instance->mode = MODE_0D;
2137 else if (instance->BEHa[64]&0x10)
2138 instance->mode = MODE_2D;
2139 else if (instance->BEHa[64]&0x20)
2140 instance->mode = MODE_3D;
2141 } else if (instance->chan == 8) {
2142 if (instance->BEHa[72]&0x8)
2143 instance->mode = MODE_0D;
2144 else if (instance->BEHa[72]&0x10)
2145 instance->mode = MODE_2D;
2146 else if (instance->BEHa[72]&0x20)
2147 instance->mode = MODE_3D;
2148 } else if (instance->chan == 12) {
2151 bits = (instance->BEHa[129]>>5) & 0x7; /* actually Ha */
2153 instance->mode = MODE_0D;
2154 else if (bits == 0x6)
2155 instance->mode = MODE_2D;
2156 else if (bits == 0x7)
2157 instance->mode = MODE_3D;
2160 /* copy the record to the (extra) location in SHMEM */
2162 if (instance->shmem) {
2164 u_char *smp; /* pointer to start of shared mem for Ba/Ea/Ha */
2166 switch(instance->chan) {
2167 case 6: smp = &instance->shmem[instance->shmem_Ba]; break;
2168 case 8: smp = &instance->shmem[instance->shmem_Ea]; break;
2169 case 12: smp = &instance->shmem[instance->shmem_Ha]; break;
2170 default: smp = (u_char) 0; break;
2173 switch (instance->mode) {
2174 case MODE_0D: i = 1; break; /* 0D, Position Hold */
2175 case MODE_2D: i = 2; break; /* 2D, Altitude Hold */
2176 case MODE_3D: i = 3; break; /* 3D fix */
2177 default: i = 0; break;
2183 memcpy(&smp[i+3], buf, (size_t) (len+3));
2188 * check if timer active
2189 * if it hasn't been cleared, then @@Bn/@@En/@@Hn did not respond
2192 if (instance->traim_delay) {
2193 if (instance->traim_delay++ > 5) {
2194 instance->traim = 0;
2195 instance->traim_delay = 0;
2196 cp = "ONCORE: Did not detect TRAIM response, TRAIM = OFF";
2197 record_clock_stats(&(instance->peer->srcadr), cp);
2199 oncore_set_traim(instance);
2205 /* by now should have a @@Ba/@@Ea/@@Ha with good data in it */
2207 if (!instance->have_dH && !instance->traim_delay)
2208 oncore_compute_dH(instance);
2211 * must be ONCORE_RUN if we are here.
2212 * Have # chan and TRAIM by now.
2215 instance->pp->year = buf[6]*256+buf[7];
2216 instance->pp->day = ymd2yd(buf[6]*256+buf[7], buf[4], buf[5]);
2217 instance->pp->hour = buf[8];
2218 instance->pp->minute = buf[9];
2219 instance->pp->second = buf[10];
2222 * Are we doing a Hardware or Software Site Survey?
2225 if (instance->site_survey == ONCORE_SS_HW || instance->site_survey == ONCORE_SS_SW)
2226 oncore_ss(instance);
2228 /* see if we ever saw a response from the @@Ayx above */
2230 if (instance->count2) {
2231 if (instance->count2++ > 5) { /* this delay to check on @@Ay command */
2232 instance->count2 = 0;
2234 /* Have we seen an Ay (1PPS time offset) command response */
2235 /* if not, and non-zero offset, zero the offset, and send message */
2237 if (!instance->saw_Ay && instance->offset) {
2238 cp = "No @@Ay command, PPS OFFSET ignored";
2239 record_clock_stats(&(instance->peer->srcadr), cp);
2240 instance->offset = 0;
2246 * Check the leap second status once per day.
2249 oncore_check_leap_sec(instance);
2252 * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn.
2255 if (instance->shmem && !instance->shmem_bad_Ea && instance->shmem_Posn && (instance->site_survey == ONCORE_SS_DONE))
2256 oncore_shmem_get_3D(instance);
2258 if (!instance->traim) /* NO traim, no BnEnHn, go get tick */
2259 oncore_get_timestamp(instance, instance->offset, instance->offset);
2264 /* Almanac Status */
2268 struct instance *instance,
2275 sprintf(Msg, "Bd: Almanac %s, week = %d, t = %d, %d SVs: %x",
2276 ((buf[4]) ? "LOADED" : "(NONE)"), buf[5], buf[6], buf[7], w32(&buf[8]) );
2277 record_clock_stats(&(instance->peer->srcadr), Msg);
2282 /* get leap-second warning message */
2285 * @@Bj does NOT behave as documented in current Oncore firmware.
2286 * It turns on the LEAP indicator when the data is set, and does not,
2287 * as documented, wait until the beginning of the month when the
2288 * leap second will occur.
2289 * Since this firmware bug will never be fixed in all the outstanding Oncore receivers
2290 * @@Bj is only called in June/December.
2295 struct instance *instance,
2304 instance->peer->leap = LEAP_ADDSECOND;
2305 cp = "Set peer.leap to LEAP_ADDSECOND";
2308 instance->peer->leap = LEAP_DELSECOND;
2309 cp = "Set peer.leap to LEAP_DELSECOND";
2313 instance->peer->leap = LEAP_NOWARNING;
2314 cp = "Set peer.leap to LEAP_NOWARNING";
2317 record_clock_stats(&(instance->peer->srcadr), cp);
2324 struct instance *instance,
2332 if (instance->o_state != ONCORE_RUN)
2335 if (instance->traim_delay) { /* flag that @@Bn/@@En/Hn returned */
2336 instance->traim_ck = 1;
2337 instance->traim_delay = 0;
2338 cp = "ONCORE: Detected TRAIM, TRAIM = ON";
2339 record_clock_stats(&(instance->peer->srcadr), cp);
2341 oncore_set_traim(instance);
2344 memcpy(instance->BEHn, buf, (size_t) len); /* Bn or En or Hn */
2346 /* If Time RAIM doesn't like it, don't trust it */
2348 if (buf[2] == 'H') {
2349 if (instance->BEHn[6]) /* bad TRAIM */
2352 dt1 = instance->saw_tooth + instance->offset; /* dt this time step */
2353 instance->saw_tooth = (s_char) instance->BEHn[10]; /* update for next time Hn[10] */
2354 dt2 = instance->saw_tooth + instance->offset; /* dt next time step */
2356 if (instance->BEHn[21]) /* bad TRAIM */
2359 dt1 = instance->saw_tooth + instance->offset; /* dt this time step */
2360 instance->saw_tooth = (s_char) instance->BEHn[25]; /* update for next time */
2361 dt2 = instance->saw_tooth + instance->offset; /* dt next time step */
2364 oncore_get_timestamp(instance, dt1, dt2);
2369 /* Here for @@Ca, @@Fa and @@Ia messages */
2371 /* These are Self test Commands for 6, 8, and 12 chan receivers.
2372 * There are good reasons NOT to do a @@Ca, @@Fa or @@Ia command with the ONCORE.
2373 * It was found that under some circumstances the following
2374 * command would fail if issued immediately after the return from the
2375 * @@Fa, but a 2sec delay seemed to fix things. Since simply calling
2376 * sleep(2) is wasteful, and may cause trouble for some OS's, repeating
2377 * itimer, we set a flag, and test it at the next POLL. If it hasn't
2378 * been cleared, we reissue the @@Cj that is issued below.
2379 * Note that we do a @@Cj at the beginning, and again here.
2380 * The first is to get the info, the 2nd is just used as a safe command
2381 * after the @@Fa for all Oncores (and it was in this posn in the
2387 struct instance *instance,
2395 if (instance->o_state == ONCORE_TEST_SENT) {
2396 enum antenna_state antenna;
2398 instance->timeout = 0;
2402 printf("ONCORE[%d]: >>@@%ca %x %x %x\n", instance->unit, buf[2], buf[4], buf[5], buf[6]);
2404 printf("ONCORE[%d]: >>@@%ca %x %x\n", instance->unit, buf[2], buf[4], buf[5]);
2407 antenna = (buf[4] & 0xc0) >> 6;
2410 i = buf[4] || buf[5];
2411 if (buf[2] == 'I') i = i || buf[6];
2413 if (buf[2] == 'I') {
2414 msyslog(LOG_ERR, "ONCORE[%d]: self test failed: result %02x %02x %02x",
2415 instance->unit, buf[4], buf[5], buf[6]);
2417 msyslog(LOG_ERR, "ONCORE[%d]: self test failed: result %02x %02x",
2418 instance->unit, buf[4], buf[5]);
2420 cp = "ONCORE: self test failed, shutting down driver";
2421 record_clock_stats(&instance->peer->srcadr, cp);
2423 refclock_report(instance->peer, CEVNT_FAULT);
2424 oncore_shutdown(instance->unit, instance->peer);
2428 /* report the current antenna state */
2430 oncore_antenna_report(instance, antenna);
2432 instance->o_state = ONCORE_INIT;
2433 cp = "state = ONCORE_INIT";
2434 record_clock_stats(&(instance->peer->srcadr), cp);
2436 instance->timeout = 4;
2437 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
2444 * Demultiplex the almanac into shmem
2449 struct instance *instance,
2456 if (instance->shmem == NULL)
2459 if (buf[4] == 5 && buf[5] > 0 && buf[5] < 26)
2461 else if (buf[4] == 4 && buf[5] <= 5)
2463 else if (buf[4] == 4 && buf[5] <= 10)
2465 else if (buf[4] == 4 && buf[5] == 25)
2470 cp = "Cb: Response is NO ALMANAC";
2471 record_clock_stats(&(instance->peer->srcadr), cp);
2476 instance->shmem[instance->shmem_Cb + i + 2]++;
2477 memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3));
2482 sprintf(Msg, "See Cb [%d,%d]", buf[4], buf[5]);
2483 record_clock_stats(&(instance->peer->srcadr), Msg);
2491 * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup
2492 * not so for VP (eeprom) or any unit with a battery
2497 struct instance *instance,
2504 if (instance->o_state == ONCORE_RESET_SENT) {
2505 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */
2506 /* Reset set VP to IDLE */
2507 instance->o_state = ONCORE_TEST_SENT;
2508 cp = "state = ONCORE_TEST_SENT";
2509 record_clock_stats(&(instance->peer->srcadr), cp);
2511 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
2518 * This is the Grand Central Station for the Preliminary Initialization.
2519 * Once done here we move on to oncore_msg_BaEaHa for final Initialization and Running.
2521 * We do an @@Cj whenever we need a safe command for all Oncores.
2522 * The @@Cj gets us back here where we can switch to the next phase of setup.
2524 * o Once at the very beginning (in start) to get the Model number.
2525 * This info is printed, but no longer used.
2526 * o Again after we have determined the number of Channels in the receiver.
2527 * o And once later after we have done a reset and test, (which may hang),
2528 * as we are about to initialize the Oncore and start it running.
2529 * o We have one routine below for each case.
2534 struct instance *instance,
2542 memcpy(instance->Cj, buf, len);
2544 instance->timeout = 0;
2545 if (instance->o_state == ONCORE_CHECK_ID) {
2546 oncore_msg_Cj_id(instance, buf, len);
2547 oncore_chan_test(instance);
2548 } else if (instance->o_state == ONCORE_HAVE_CHAN) {
2549 mode = instance->init_type;
2550 if (mode == 3 || mode == 4) { /* Cf will return here to check for TEST */
2551 instance->o_state = ONCORE_RESET_SENT;
2552 cp = "state = ONCORE_RESET_SENT";
2553 record_clock_stats(&(instance->peer->srcadr), cp);
2554 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cf, sizeof(oncore_cmd_Cf));
2556 instance->o_state = ONCORE_TEST_SENT;
2557 cp = "state = ONCORE_TEST_SENT";
2558 record_clock_stats(&(instance->peer->srcadr), cp);
2562 if (instance->o_state == ONCORE_TEST_SENT) {
2563 if (instance->chan == 6)
2564 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ca, sizeof(oncore_cmd_Ca));
2565 else if (instance->chan == 8)
2566 oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof(oncore_cmd_Fa));
2567 else if (instance->chan == 12)
2568 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ia, sizeof(oncore_cmd_Ia));
2569 } else if (instance->o_state == ONCORE_INIT)
2570 oncore_msg_Cj_init(instance, buf, len);
2575 /* The information on determining a Oncore 'Model', viz VP, UT, etc, from
2576 * the Model Number comes from "Richard M. Hambly" <rick@cnssys.com>
2577 * and from Motorola. Until recently Rick was the only source of
2578 * this information as Motorola didn't give the information out.
2580 * Determine the Type from the Model #, this determines #chan and if TRAIM is
2583 * The Information from this routine is NO LONGER USED.
2584 * The RESULTS are PRINTED, BUT NOT USED, and the routine COULD BE DELETED
2589 struct instance *instance,
2594 char *cp, *cp1, *cp2, Model[21], Msg[160];
2596 /* Write Receiver ID message to clockstats file */
2598 instance->Cj[294] = '\0';
2599 for (cp=(char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) {
2600 cp1 = strchr(cp, '\r');
2602 cp1 = (char *)&instance->Cj[294];
2604 record_clock_stats(&(instance->peer->srcadr), cp);
2609 /* next, the Firmware Version and Revision numbers */
2611 instance->version = atoi(&instance->Cj[83]);
2612 instance->revision = atoi(&instance->Cj[111]);
2614 /* from model number decide which Oncore this is,
2615 and then the number of channels */
2617 for (cp=&instance->Cj[160]; *cp == ' '; cp++) /* start right after 'Model #' */
2621 for (; !isspace((int)*cp) && cp-cp1 < 20; cp++, cp2++)
2626 if (!strncmp(Model, "PVT6", (size_t) 4)) {
2628 instance->model = ONCORE_PVT6;
2629 } else if (Model[0] == 'A') {
2631 instance->model = ONCORE_BASIC;
2632 } else if (Model[0] == 'B' || !strncmp(Model, "T8", (size_t) 2)) {
2634 instance->model = ONCORE_VP;
2635 } else if (Model[0] == 'P') {
2637 instance->model = ONCORE_M12;
2638 } else if (Model[0] == 'R' || Model[0] == 'D' || Model[0] == 'S') {
2639 if (Model[5] == 'N') {
2641 instance->model = ONCORE_GT;
2642 } else if ((Model[1] == '3' || Model[1] == '4') && Model[5] == 'G') {
2644 instance->model = ONCORE_GTPLUS;
2645 } else if ((Model[1] == '5' && Model[5] == 'U') || (Model[1] == '1' && Model[5] == 'A')) {
2647 instance->model = ONCORE_UT;
2648 } else if (Model[1] == '5' && Model[5] == 'G') {
2650 instance->model = ONCORE_UTPLUS;
2651 } else if (Model[1] == '6' && Model[5] == 'G') {
2653 instance->model = ONCORE_SL;
2656 instance->model = ONCORE_UNKNOWN;
2660 instance->model = ONCORE_UNKNOWN;
2663 /* use MODEL to set CHAN and TRAIM and possibly zero SHMEM */
2665 sprintf(Msg, "This looks like an Oncore %s with version %d.%d firmware.", cp, instance->version, instance->revision);
2666 record_clock_stats(&(instance->peer->srcadr), Msg);
2668 instance->chan_id = 8; /* default */
2669 if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
2670 instance->chan_id = 6;
2671 else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS)
2672 instance->chan_id = 8;
2673 else if (instance->model == ONCORE_M12)
2674 instance->chan_id = 12;
2676 instance->traim_id = 0; /* default */
2677 if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
2678 instance->traim_id = 0;
2679 else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS)
2680 instance->traim_id = 1;
2681 else if (instance->model == ONCORE_M12)
2682 instance->traim_id = -1;
2684 sprintf(Msg, "Channels = %d, TRAIM = %s", instance->chan_id,
2685 ((instance->traim_id < 0) ? "UNKNOWN" : ((instance->traim_id > 0) ? "ON" : "OFF")));
2686 record_clock_stats(&(instance->peer->srcadr), Msg);
2691 /* OK, know type of Oncore, have possibly reset it, and have tested it.
2692 * We know the number of channels.
2693 * We will determine whether we have TRAIM before we actually start.
2699 struct instance *instance,
2704 char *cp, Cmd[20], Msg[160];
2708 /* The M12 with 1.3 or 2.0 Firmware, loses track of all Satellites and has to
2709 * start again if we go from 0D -> 3D, then loses them again when we
2710 * go from 3D -> 0D. We do this to get a @@Ea message for SHMEM.
2711 * For NOW we will turn this aspect of filling SHMEM off for the M12
2714 if (instance->chan == 12) {
2715 instance->shmem_bad_Ea = 1;
2716 sprintf(Msg, "*** SHMEM partially enabled for ONCORE M12 s/w v%d.%d ***", instance->version, instance->revision);
2717 record_clock_stats(&(instance->peer->srcadr), Msg);
2720 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */
2721 oncore_sendmsg(instance->ttyfd, oncore_cmd_Bb, sizeof(oncore_cmd_Bb)); /* turn on for shmem (6/8/12) */
2722 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ek, sizeof(oncore_cmd_Ek)); /* turn off (VP) */
2723 oncore_sendmsg(instance->ttyfd, oncore_cmd_Aw, sizeof(oncore_cmd_Aw)); /* UTC time (6/8/12) */
2724 oncore_sendmsg(instance->ttyfd, oncore_cmd_AB, sizeof(oncore_cmd_AB)); /* Appl type static (VP) */
2725 oncore_sendmsg(instance->ttyfd, oncore_cmd_Be, sizeof(oncore_cmd_Be)); /* Tell us the Almanac for shmem (6/8/12) */
2726 oncore_sendmsg(instance->ttyfd, oncore_cmd_Bd, sizeof(oncore_cmd_Bd)); /* Tell us when Almanac changes */
2728 mode = instance->init_type;
2730 /* If there is Position input in the Config file
2731 * and mode = (1,3) set it as posn hold posn, goto 0D mode.
2732 * or mode = (2,4) set it as INITIAL position, and do Site Survey.
2735 if (instance->posn_set) {
2736 record_clock_stats(&(instance->peer->srcadr), "Setting Posn from input data");
2737 oncore_set_posn(instance); /* this should print posn indirectly thru the As cmd */
2738 } else /* must issue an @@At here to check on 6/8 Position Hold, set_posn would have */
2739 if (instance->chan != 12)
2740 oncore_sendmsg(instance->ttyfd, oncore_cmd_Atx, sizeof(oncore_cmd_Atx));
2743 /* cable delay in ns */
2744 memcpy(Cmd, oncore_cmd_Az, (size_t) sizeof(oncore_cmd_Az));
2745 w32_buf(&Cmd[-2+4], instance->delay);
2746 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Az)); /* 6,8,12 */
2748 /* PPS offset in ns */
2749 if (instance->offset) {
2750 memcpy(Cmd, oncore_cmd_Ay, (size_t) sizeof(oncore_cmd_Ay)); /* some have it, some don't */
2751 w32_buf(&Cmd[-2+4], instance->offset); /* will check for hw response */
2752 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ay));
2755 /* Satellite mask angle */
2757 if (instance->Ag != 0xff) { /* will have 0xff in it if not set by user */
2758 memcpy(Cmd, oncore_cmd_Ag, (size_t) sizeof(oncore_cmd_Ag));
2759 Cmd[-2+4] = instance->Ag;
2760 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ag));
2764 /* 6, 8 12 chan - Position/Status/Data Output Message, 1/s
2765 * now we're really running
2766 * these were ALL started in the chan test,
2767 * However, if we had mode=3,4 then commands got turned off, so we turn
2768 * them on again here just in case
2771 if (instance->chan == 6) { /* start 6chan, kill 8,12chan commands, possibly testing VP in 6chan mode */
2772 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0));
2773 oncore_sendmsg(instance->ttyfd, oncore_cmd_En0, sizeof(oncore_cmd_En0));
2774 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0));
2775 oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
2776 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba, sizeof(oncore_cmd_Ba ));
2777 } else if (instance->chan == 8) { /* start 8chan, kill 6,12chan commands */
2778 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0));
2779 oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0));
2780 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0));
2781 oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
2782 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea, sizeof(oncore_cmd_Ea ));
2783 } else if (instance->chan == 12){ /* start 12chan, kill 6,12chan commands */
2784 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0));
2785 oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0));
2786 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0));
2787 oncore_sendmsg(instance->ttyfd, oncore_cmd_En0, sizeof(oncore_cmd_En0));
2788 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha, sizeof(oncore_cmd_Ha ));
2791 instance->count = 1;
2792 instance->o_state = ONCORE_ALMANAC;
2793 cp = "state = ONCORE_ALMANAC";
2794 record_clock_stats(&(instance->peer->srcadr), cp);
2799 /* 12chan position */
2803 struct instance *instance,
2810 double Lat, Lon, Ht;
2813 lat = buf_w32(&buf[4]);
2814 lon = buf_w32(&buf[8]);
2815 ht = buf_w32(&buf[12]); /* GPS ellipsoid */
2826 sprintf(Msg, "Ga Posn Lat = %.7f, Lon = %.7f, Ht = %.2f", Lat, Lon, Ht);
2827 record_clock_stats(&(instance->peer->srcadr), Msg);
2829 instance->ss_lat = lat;
2830 instance->ss_long = lon;
2831 instance->ss_ht = ht;
2833 oncore_print_posn(instance);
2838 /* 12 chan time/date */
2842 struct instance *instance,
2847 char Msg[160], *gmts;
2848 int mo, d, y, h, m, s, gmth, gmtm;
2852 y = 256*buf[6]+buf[7];
2858 gmts = ((buf[11] == 0) ? "+" : "-");
2862 sprintf(Msg, "Date/Time set to: %d%s%d %2d:%02d:%02d GMT (GMT offset is %s%02d:%02d)",
2863 d, Month[mo+1], y, h, m, s, gmts, gmth, gmtm);
2864 record_clock_stats(&(instance->peer->srcadr), Msg);
2870 * Try to use Oncore M12+Timing Auto Survey Feature
2871 * If its not there (M12), set flag to do it ourselves.
2876 struct instance *instance,
2883 if (instance->site_survey == ONCORE_SS_TESTING) {
2885 record_clock_stats(&(instance->peer->srcadr),
2886 "Initiating hardware 3D site survey");
2888 cp = "SSstate = ONCORE_SS_HW";
2889 record_clock_stats(&(instance->peer->srcadr), cp);
2890 instance->site_survey = ONCORE_SS_HW;
2897 /* Leap Second for M12, gives all info from satellite message */
2898 /* also in UT v3.0 */
2902 struct instance *instance,
2910 instance->saw_Gj = 1; /* flag, saw_Gj, dont need to try Bj in check_leap */
2912 /* print the message to verify whats there */
2914 dt = buf[5] - buf[4];
2917 sprintf(Msg, "ONCORE[%d]: Leap Sec Msg: %d %d %d %d %d %d %d %d %d %d",
2919 buf[4], buf[5], 256*buf[6]+buf[7], buf[8], buf[9], buf[10],
2920 (buf[14]+256*(buf[13]+256*(buf[12]+256*buf[11]))),
2921 buf[15], buf[16], buf[17]);
2922 record_clock_stats(&(instance->peer->srcadr), Msg);
2925 sprintf(Msg, "ONCORE[%d]: Leap second (%d) scheduled for %d%s%d at %d:%d:%d",
2927 dt, buf[9], Month[buf[8]], 256*buf[6]+buf[7],
2928 buf[15], buf[16], buf[17]);
2929 record_clock_stats(&(instance->peer->srcadr), Msg);
2932 /* Only raise warning within a month of the leap second */
2934 instance->peer->leap = LEAP_NOWARNING;
2935 cp = "Set peer.leap to LEAP_NOWARNING";
2937 if (buf[6] == instance->BEHa[6] && buf[7] == instance->BEHa[7] && /* year */
2938 buf[8] == instance->BEHa[4]) { /* month */
2941 instance->peer->leap = LEAP_DELSECOND;
2942 cp = "Set peer.leap to LEAP_DELSECOND";
2944 instance->peer->leap = LEAP_ADDSECOND;
2945 cp = "Set peer.leap to LEAP_ADDSECOND";
2949 record_clock_stats(&(instance->peer->srcadr), cp);
2954 /* Power on failure */
2958 struct instance *instance,
2965 cp = "Oncore: System Failure at Power On";
2966 if (instance && instance->peer) {
2967 record_clock_stats(&(instance->peer->srcadr), cp);
2968 oncore_shutdown(instance->unit, instance->peer);
2972 /************** Small Subroutines ***************/
2976 oncore_antenna_report(
2977 struct instance *instance,
2978 enum antenna_state new_state)
2982 if (instance->ant_state == new_state)
2985 switch (new_state) {
2986 case ONCORE_ANTENNA_OK: cp = "GPS antenna: OK"; break;
2987 case ONCORE_ANTENNA_OC: cp = "GPS antenna: short (overcurrent)"; break;
2988 case ONCORE_ANTENNA_UC: cp = "GPS antenna: open (not connected)"; break;
2989 case ONCORE_ANTENNA_NV: cp = "GPS antenna: short (no voltage)"; break;
2990 default: cp = "GPS antenna: ?"; break;
2993 instance->ant_state = new_state;
2994 record_clock_stats(&instance->peer->srcadr, cp);
3001 struct instance *instance
3006 /* subroutine oncore_Cj_id has determined the number of channels from the
3007 * model number of the attached oncore. This is not always correct since
3008 * the oncore could have non-standard firmware. Here we check (independently) by
3009 * trying a 6, 8, and 12 chan command, and see which responds.
3010 * Caution: more than one CAN respond.
3012 * This #chan is used by the code rather than that calculated from the model number.
3015 instance->o_state = ONCORE_CHECK_CHAN;
3016 cp = "state = ONCORE_CHECK_CHAN";
3017 record_clock_stats(&(instance->peer->srcadr), cp);
3019 instance->count3 = 1;
3020 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba, sizeof(oncore_cmd_Ba));
3021 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea, sizeof(oncore_cmd_Ea));
3022 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha, sizeof(oncore_cmd_Ha));
3027 /* check for a GOOD Almanac, have we got one yet? */
3030 oncore_check_almanac(
3031 struct instance *instance
3034 if (instance->chan == 6) {
3035 instance->rsm.bad_almanac = instance->BEHa[64]&0x1;
3036 instance->rsm.bad_fix = instance->BEHa[64]&0x52;
3037 } else if (instance->chan == 8) {
3038 instance->rsm.bad_almanac = instance->BEHa[72]&0x1;
3039 instance->rsm.bad_fix = instance->BEHa[72]&0x52;
3040 } else if (instance->chan == 12) {
3043 bits1 = (instance->BEHa[129]>>5) & 0x7; /* actually Ha */
3044 bits2 = instance->BEHa[130];
3045 instance->rsm.bad_almanac = (bits2 & 0x80);
3046 instance->rsm.bad_fix = (bits2 & 0x8) || (bits1 == 0x2);
3047 /* too few sat Bad Geom */
3049 fprintf(stderr, "ONCORE[%d]: DEBUG BITS: (%x %x), (%x %x), %x %x %x %x %x\n",
3051 instance->BEHa[129], instance->BEHa[130], bits1, bits2, instance->mode == MODE_0D,
3052 instance->mode == MODE_2D, instance->mode == MODE_3D,
3053 instance->rsm.bad_almanac, instance->rsm.bad_fix);
3060 /* check the antenna for changes (did it get unplugged?) */
3063 oncore_check_antenna(
3064 struct instance *instance
3067 enum antenna_state antenna; /* antenna state */
3069 antenna = instance->ant_state;
3070 if (instance->chan == 12)
3071 antenna = (instance->BEHa[130] & 0x6 ) >> 1;
3073 antenna = (instance->BEHa[37] & 0xc0) >> 6; /* prob unset 6, set GT, UT unset VP */
3075 oncore_antenna_report (instance, antenna);
3081 * Check the leap second status once per day.
3083 * Note that the ONCORE firmware for the Bj command is wrong at
3085 * It starts advertising a LEAP SECOND as soon as the GPS satellite
3086 * data message (page 18, subframe 4) is updated to a date in the
3087 * future, and does not wait for the month that it will occur.
3088 * The event will usually be advertised several months in advance.
3089 * Since there is a one bit flag, there is no way to tell if it is
3090 * this month, or when...
3092 * As such, we have the workaround below, of only checking for leap
3093 * seconds with the Bj command in June/December.
3095 * The Gj command gives more information, and we can tell in which
3096 * month to apply the correction.
3098 * Note that with the VP we COULD read the raw data message, and
3099 * interpret it ourselves, but since this is specific to this receiver
3100 * only, and the above workaround is adequate, we don't bother.
3104 oncore_check_leap_sec(
3105 struct instance *instance
3108 if (instance->Bj_day != instance->BEHa[5]) { /* do this 1/day */
3109 instance->Bj_day = instance->BEHa[5];
3111 if (instance->saw_Gj < 0) { /* -1 DONT have Gj use Bj */
3112 if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12))
3113 oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof(oncore_cmd_Bj));
3117 if (instance->saw_Gj == 0) /* 0 is dont know if we have Gj */
3118 instance->count4 = 1;
3120 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gj, sizeof(oncore_cmd_Gj));
3124 /* Gj works for some 6/8 chan UT and the M12 */
3125 /* if no response from Gj in 5 sec, we try Bj */
3126 /* which isnt implemented in all the GT/UT either */
3128 if (instance->count4) { /* delay, waiting for Gj response */
3129 if (instance->saw_Gj == 1)
3130 instance->count4 = 0;
3131 else if (instance->count4++ > 5) { /* delay, waiting for Gj response */
3132 instance->saw_Gj = -1; /* didnt see it, will use Bj */
3133 instance->count4 = 0;
3134 if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12))
3135 oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof(oncore_cmd_Bj));
3142 /* check the message checksum,
3143 * buf points to START of message ( @@ )
3144 * len is length WITH CR/LF.
3156 for (i = 2; i < len-3; i++)
3159 return(j == buf[len-3]);
3166 struct instance *instance
3172 /* Here calculate dH = GPS - MSL for output message */
3173 /* also set Altitude Hold mode if GT */
3175 instance->have_dH = 1;
3176 if (instance->chan == 12) {
3177 GPS = buf_w32(&instance->BEHa[39]);
3178 MSL = buf_w32(&instance->BEHa[43]);
3180 GPS = buf_w32(&instance->BEHa[23]);
3181 MSL = buf_w32(&instance->BEHa[27]);
3183 instance->dH = GPS - MSL;
3184 instance->dH /= 100.;
3186 /* if MSL is not set, the calculation is meaningless */
3188 if (MSL) { /* not set ! */
3189 sprintf(Msg, "dH = (GPS - MSL) = %.2fm", instance->dH);
3190 record_clock_stats(&(instance->peer->srcadr), Msg);
3197 * try loading Almanac from shmem (where it was copied from shmem_old
3201 oncore_load_almanac(
3202 struct instance *instance
3205 u_char *cp, Cmd[20];
3210 if (!instance->shmem)
3214 for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) {
3215 if (!strncmp(cp, "@@Cb", 4) &&
3216 oncore_checksum_ok(cp, 33) &&
3217 (*(cp+4) == 4 || *(cp+4) == 5)) {
3218 write(instance->ttyfd, cp, n);
3220 oncore_print_Cb(instance, cp);
3225 /************DEBUG************/
3226 for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) {
3229 sprintf(Msg, "See %c%c%c%c %d", *(cp), *(cp+1), *(cp+2), *(cp+3), *(cp+4));
3230 record_clock_stats(&(instance->peer->srcadr), Msg);
3232 if (!strncmp(cp, "@@Cb", 4)) {
3233 oncore_print_Cb(instance, cp);
3234 if (oncore_checksum_ok(cp, 33)) {
3235 if (*(cp+4) == 4 || *(cp+4) == 5) {
3236 record_clock_stats(&(instance->peer->srcadr), "GOOD SF");
3237 write(instance->ttyfd, cp, n);
3239 record_clock_stats(&(instance->peer->srcadr), "BAD SF");
3241 record_clock_stats(&(instance->peer->srcadr), "BAD CHECKSUM");
3244 /************DEBUG************/
3247 /* Must load position and time or the Almanac doesn't do us any good */
3249 if (!instance->posn_set) { /* if we input a posn use it, else from SHMEM */
3250 record_clock_stats(&(instance->peer->srcadr), "Loading Posn from SHMEM");
3251 for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) {
3252 if ((instance->chan == 6 && (!strncmp(cp, "@@Ba", 4) && oncore_checksum_ok(cp, 68))) ||
3253 (instance->chan == 8 && (!strncmp(cp, "@@Ea", 4) && oncore_checksum_ok(cp, 76))) ||
3254 (instance->chan == 12 && (!strncmp(cp, "@@Ha", 4) && oncore_checksum_ok(cp, 154)))) {
3257 instance->posn_set = 1;
3258 ii = buf_w32(cp + 15);
3259 jj = buf_w32(cp + 19);
3260 kk = buf_w32(cp + 23);
3263 sprintf(Msg, "SHMEM posn = %d (%d, %d, %d)", cp-instance->shmem, ii, jj, kk);
3264 record_clock_stats(&(instance->peer->srcadr), Msg);
3266 if (ii != 0 || jj != 0 || kk != 0) { /* phk asked for this test */
3267 instance->ss_lat = ii;
3268 instance->ss_long = jj;
3269 instance->ss_ht = kk;
3274 oncore_set_posn(instance);
3276 /* and set time to time from Computer clock */
3278 gettimeofday(&tv, 0);
3279 tm = gmtime((const time_t *) &tv.tv_sec);
3283 sprintf(Msg, "DATE %d %d %d, %d %d %d", 1900+tm->tm_year, tm->tm_mon, tm->tm_mday,
3284 tm->tm_hour, tm->tm_min, tm->tm_sec);
3285 record_clock_stats(&(instance->peer->srcadr), Msg);
3288 if (instance->chan == 12) {
3289 memcpy(Cmd, oncore_cmd_Gb, (size_t) sizeof(oncore_cmd_Gb));
3290 Cmd[-2+4] = tm->tm_mon;
3291 Cmd[-2+5] = tm->tm_mday;
3292 Cmd[-2+6] = (1900+tm->tm_year)/256;
3293 Cmd[-2+7] = (1900+tm->tm_year)%256;
3294 Cmd[-2+8] = tm->tm_hour;
3295 Cmd[-2+9] = tm->tm_min;
3296 Cmd[-2+10] = tm->tm_sec;
3300 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Gb));
3302 /* First set GMT offset to zero */
3304 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ab, sizeof(oncore_cmd_Ab));
3306 memcpy(Cmd, oncore_cmd_Ac, (size_t) sizeof(oncore_cmd_Ac));
3307 Cmd[-2+4] = tm->tm_mon;
3308 Cmd[-2+5] = tm->tm_mday;
3309 Cmd[-2+6] = (1900+tm->tm_year)/256;
3310 Cmd[-2+7] = (1900+tm->tm_year)%256;
3311 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ac));
3313 memcpy(Cmd, oncore_cmd_Aa, (size_t) sizeof(oncore_cmd_Aa));
3314 Cmd[-2+4] = tm->tm_hour;
3315 Cmd[-2+5] = tm->tm_min;
3316 Cmd[-2+6] = tm->tm_sec;
3317 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Aa));
3320 record_clock_stats(&(instance->peer->srcadr), "Setting Posn and Time after Loading Almanac");
3325 /* Almanac data input */
3329 struct instance *instance,
3337 printf("DEBUG: See: %c%c%c%c\n", *(cp), *(cp+1), *(cp+2), *(cp+3));
3338 printf("DEBUG: Cb: [%d,%d]", *(cp+4), *(cp+5));
3339 for(ii=0; ii<33; ii++)
3340 printf(" %d", *(cp+ii));
3343 sprintf(Msg, "Debug: Cb: [%d,%d]", *(cp+4), *(cp+5));
3344 record_clock_stats(&(instance->peer->srcadr), Msg);
3361 for (j=0; j<jj; j++) {
3362 printf("%4d: ", nn);
3364 for (i=0; i<16; i++)
3365 printf(" %o", *cp++);
3374 struct instance *instance
3377 char Msg[120], ew, ns;
3378 double xd, xm, xs, yd, ym, ys, hm, hft;
3379 int idx, idy, is, imx, imy;
3382 record_clock_stats(&(instance->peer->srcadr), "Posn:");
3384 lon = instance->ss_long;
3391 lat = instance->ss_lat;
3397 hm = instance->ss_ht/100.;
3400 xd = lat/3600000.; /* lat, lon in int msec arc, ht in cm. */
3402 sprintf(Msg, "Lat = %c %11.7fdeg, Long = %c %11.7fdeg, Alt = %5.2fm (%5.2fft) GPS", ns, xd, ew, yd, hm, hft);
3403 record_clock_stats(&(instance->peer->srcadr), Msg);
3412 "Lat = %c %3ddeg %7.4fm, Long = %c %3ddeg %8.5fm, Alt = %7.2fm (%7.2fft) GPS", ns, idx, xm, ew, idy, ym, hm, hft);
3413 record_clock_stats(&(instance->peer->srcadr), Msg);
3422 "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);
3423 record_clock_stats(&(instance->peer->srcadr), Msg);
3429 * write message to Oncore.
3442 printf("ONCORE: Send @@%c%c %d\n", ptr[0], ptr[1], (int) len);
3443 write(fd, "@@", (size_t) 2);
3444 write(fd, ptr, len);
3447 write(fd, &cs, (size_t) 1);
3448 write(fd, "\r\n", (size_t) 2);
3455 struct instance *instance
3461 /* Turn OFF position hold, it needs to be off to set position (for some units),
3462 will get set ON in @@Ea later */
3464 if (instance->chan == 12)
3465 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* (12) */
3467 oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* (6/8) */
3468 oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* (6/8) */
3471 mode = instance->init_type;
3473 if (mode != 0) { /* first set posn hold position */
3474 memcpy(Cmd, oncore_cmd_As, (size_t) sizeof(oncore_cmd_As)); /* don't modify static variables */
3475 w32_buf(&Cmd[-2+4], (int) instance->ss_lat);
3476 w32_buf(&Cmd[-2+8], (int) instance->ss_long);
3477 w32_buf(&Cmd[-2+12], (int) instance->ss_ht);
3479 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_As)); /* posn hold 3D posn (6/8/12) */
3481 memcpy(Cmd, oncore_cmd_Au, (size_t) sizeof(oncore_cmd_Au));
3482 w32_buf(&Cmd[-2+4], (int) instance->ss_ht);
3484 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Au)); /* altitude hold (6/8/12 not UT, M12T) */
3486 /* next set current position */
3488 if (instance->chan == 12) {
3489 memcpy(Cmd, oncore_cmd_Ga, (size_t) sizeof(oncore_cmd_Ga));
3490 w32_buf(&Cmd[-2+4], (int) instance->ss_lat);
3491 w32_buf(&Cmd[-2+8], (int) instance->ss_long);
3492 w32_buf(&Cmd[-2+12],(int) instance->ss_ht);
3494 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ga)); /* 3d posn (12) */
3496 memcpy(Cmd, oncore_cmd_Ad, (size_t) sizeof(oncore_cmd_Ad));
3497 w32_buf(&Cmd[-2+4], (int) instance->ss_lat);
3498 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ad)); /* lat (6/8) */
3500 memcpy(Cmd, oncore_cmd_Ae, (size_t) sizeof(oncore_cmd_Ae));
3501 w32_buf(&Cmd[-2+4], (int) instance->ss_long);
3502 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ae)); /* long (6/8) */
3504 memcpy(Cmd, oncore_cmd_Af, (size_t) sizeof(oncore_cmd_Af));
3505 w32_buf(&Cmd[-2+4], (int) instance->ss_ht);
3507 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Af)); /* ht (6/8) */
3510 /* Finally, turn on position hold */
3512 if (instance->chan == 12)
3513 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1));
3515 oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1));
3523 struct instance *instance
3528 if (instance->traim_in != -1) /* set in Input */
3529 instance->traim = instance->traim_in;
3531 instance->traim = instance->traim_ck;
3533 sprintf(Msg, "Input says TRAIM = %d", instance->traim_in);
3534 record_clock_stats(&(instance->peer->srcadr), Msg);
3535 sprintf(Msg, "Model # says TRAIM = %d", instance->traim_id);
3536 record_clock_stats(&(instance->peer->srcadr), Msg);
3537 sprintf(Msg, "Testing says TRAIM = %d", instance->traim_ck);
3538 record_clock_stats(&(instance->peer->srcadr), Msg);
3539 sprintf(Msg, "Using TRAIM = %d", instance->traim);
3540 record_clock_stats(&(instance->peer->srcadr), Msg);
3542 if (instance->traim_ck == 1 && instance->traim == 0) {
3543 /* if it should be off, and I turned it on during testing,
3544 then turn it off again */
3545 if (instance->chan == 6)
3546 oncore_sendmsg(instance->ttyfd, oncore_cmd_Bnx, sizeof(oncore_cmd_Bnx));
3547 else if (instance->chan == 8)
3548 oncore_sendmsg(instance->ttyfd, oncore_cmd_Enx, sizeof(oncore_cmd_Enx));
3549 else /* chan == 12 */
3550 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ge0, sizeof(oncore_cmd_Ge0));
3557 * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn.
3561 oncore_shmem_get_3D(
3562 struct instance *instance
3565 if (instance->pp->second%15 == 3) { /* start the sequence */ /* by changing mode */
3566 instance->shmem_reset = 1;
3567 if (instance->chan == 12) {
3568 if (instance->shmem_Posn == 2)
3569 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd2, sizeof(oncore_cmd_Gd2)); /* 2D */
3571 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* 3D */
3573 if (instance->saw_At) { /* out of 0D -> 3D mode */
3574 oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0));
3575 if (instance->shmem_Posn == 2) /* 3D -> 2D mode */
3576 oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
3578 oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
3580 } else if (instance->shmem_reset || (instance->mode != MODE_0D)) {
3581 instance->shmem_reset = 0;
3582 if (instance->chan == 12)
3583 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); /* 0D */
3585 if (instance->saw_At) {
3586 if (instance->mode == MODE_2D) /* 2D -> 3D or 0D mode */
3587 oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
3588 oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1)); /* to 0D mode */
3590 oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
3598 * Here we do the Software SiteSurvey.
3599 * We have to average our own position for the Position Hold Mode
3600 * We use Heights from the GPS ellipsoid.
3601 * We check for the END of either HW or SW SiteSurvey.
3606 struct instance *instance
3610 double lat, lon, ht;
3613 if (instance->site_survey == ONCORE_SS_HW) {
3616 * Check to see if Hardware SiteSurvey has Finished.
3619 if ((instance->chan == 8 && !(instance->BEHa[37] & 0x20)) ||
3620 (instance->chan == 12 && !(instance->BEHa[130] & 0x10))) {
3621 record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
3623 if (instance->chan == 12)
3624 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gax, sizeof(oncore_cmd_Gax));
3626 oncore_sendmsg(instance->ttyfd, oncore_cmd_Asx, sizeof(oncore_cmd_Asx));
3628 cp = "SSstate = ONCORE_SS_DONE";
3629 record_clock_stats(&(instance->peer->srcadr), cp);
3630 instance->site_survey = ONCORE_SS_DONE;
3634 * Must be a Software Site Survey.
3637 if (instance->rsm.bad_fix) /* Not if poor geometry or less than 3 sats */
3640 if (instance->mode != MODE_3D) /* Use only 3D Fixes */
3643 instance->ss_lat += buf_w32(&instance->BEHa[15]);
3644 instance->ss_long += buf_w32(&instance->BEHa[19]);
3645 instance->ss_ht += buf_w32(&instance->BEHa[23]); /* GPS ellipsoid */
3646 instance->ss_count++;
3648 if (instance->ss_count != POS_HOLD_AVERAGE)
3651 instance->ss_lat /= POS_HOLD_AVERAGE;
3652 instance->ss_long /= POS_HOLD_AVERAGE;
3653 instance->ss_ht /= POS_HOLD_AVERAGE;
3655 sprintf(Msg, "Surveyed posn: lat %.3f (mas) long %.3f (mas) ht %.3f (cm)",
3656 instance->ss_lat, instance->ss_long, instance->ss_ht);
3657 record_clock_stats(&(instance->peer->srcadr), Msg);
3658 lat = instance->ss_lat/3600000.;
3659 lon = instance->ss_long/3600000.;
3660 ht = instance->ss_ht/100;
3661 sprintf(Msg, "Surveyed posn: lat %.7f (deg) long %.7f (deg) ht %.2f (m)",
3663 record_clock_stats(&(instance->peer->srcadr), Msg);
3665 oncore_set_posn(instance);
3667 record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
3669 cp = "SSstate = ONCORE_SS_DONE";
3670 record_clock_stats(&(instance->peer->srcadr), cp);
3671 instance->site_survey = ONCORE_SS_DONE;
3678 oncore_wait_almanac(
3679 struct instance *instance
3682 if (instance->rsm.bad_almanac) {
3684 printf("ONCORE[%d]: waiting for almanac\n", instance->unit);
3687 * If we get here (first time) then we don't have an almanac in memory.
3688 * Check if we have a SHMEM, and if so try to load whatever is there.
3691 if (!instance->almanac_from_shmem) {
3692 instance->almanac_from_shmem = 1;
3693 oncore_load_almanac(instance);
3696 } else { /* Here we have the Almanac, we will be starting the @@Bn/@@En/@@Hn
3697 commands, and can finally check for TRAIM. Again, we set a delay
3698 (5sec) and wait for things to settle down */
3700 if (instance->chan == 6)
3701 oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn, sizeof(oncore_cmd_Bn));
3702 else if (instance->chan == 8)
3703 oncore_sendmsg(instance->ttyfd, oncore_cmd_En, sizeof(oncore_cmd_En));
3704 else if (instance->chan == 12) {
3705 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gc, sizeof(oncore_cmd_Gc)); /* 1PPS on, continuous */
3706 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ge, sizeof(oncore_cmd_Ge)); /* TRAIM on */
3707 oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn, sizeof(oncore_cmd_Hn)); /* TRAIM status 1/s */
3709 instance->traim_delay = 1;
3711 record_clock_stats(&(instance->peer->srcadr), "Have now loaded an ALMANAC");
3713 instance->o_state = ONCORE_RUN;
3714 record_clock_stats(&(instance->peer->srcadr), "state = ONCORE_RUN");
3722 int refclock_oncore_bs;
3723 #endif /* REFCLOCK */