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