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