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