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