xref: /freebsd/contrib/ntp/ntpd/refclock_oncore.c (revision f5f40dd63bc7acbb5312b26ac1ea1103c12352a6)
1c0b746e5SOllivier Robert /*
2c0b746e5SOllivier Robert  * ----------------------------------------------------------------------------
3c0b746e5SOllivier Robert  * "THE BEER-WARE LICENSE" (Revision 42):
4c0b746e5SOllivier Robert  * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
5c0b746e5SOllivier Robert  * can do whatever you want with this stuff. If we meet some day, and you think
6c0b746e5SOllivier Robert  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7c0b746e5SOllivier Robert  * ----------------------------------------------------------------------------
8c0b746e5SOllivier Robert  *
9c0b746e5SOllivier Robert  * refclock_oncore.c
10c0b746e5SOllivier Robert  *
11c0b746e5SOllivier Robert  * Driver for some of the various the Motorola Oncore GPS receivers.
129c2daa00SOllivier Robert  *   should work with Basic, PVT6, VP, UT, UT+, GT, GT+, SL, M12, M12+T
139c2daa00SOllivier Robert  *	The receivers with TRAIM (VP, UT, UT+, M12+T), will be more accurate
149c2daa00SOllivier Robert  *	   than the others.
15224ba2bdSOllivier Robert  *	The receivers without position hold (GT, GT+) will be less accurate.
16c0b746e5SOllivier Robert  *
17c0b746e5SOllivier Robert  * Tested with:
18c0b746e5SOllivier Robert  *
19c0b746e5SOllivier Robert  *		(UT)				   (VP)
20c0b746e5SOllivier Robert  *   COPYRIGHT 1991-1997 MOTOROLA INC.	COPYRIGHT 1991-1996 MOTOROLA INC.
21c0b746e5SOllivier Robert  *   SFTW P/N #     98-P36848P		SFTW P/N # 98-P36830P
22c0b746e5SOllivier Robert  *   SOFTWARE VER # 2			SOFTWARE VER # 8
23c0b746e5SOllivier Robert  *   SOFTWARE REV # 2			SOFTWARE REV # 8
24c0b746e5SOllivier Robert  *   SOFTWARE DATE  APR 24 1998 	SOFTWARE DATE  06 Aug 1996
25c0b746e5SOllivier Robert  *   MODEL #	R1121N1114		MODEL #    B4121P1155
26c0b746e5SOllivier Robert  *   HWDR P/N # 1			HDWR P/N # _
27c0b746e5SOllivier Robert  *   SERIAL #	R0010A			SERIAL #   SSG0226478
28c0b746e5SOllivier Robert  *   MANUFACTUR DATE 6H07		MANUFACTUR DATE 7E02
29c0b746e5SOllivier Robert  *					OPTIONS LIST	IB
30c0b746e5SOllivier Robert  *
31224ba2bdSOllivier Robert  *	      (Basic)				   (M12)
329c2daa00SOllivier Robert  *   COPYRIGHT 1991-1994 MOTOROLA INC.	COPYRIGHT 1991-2000 MOTOROLA INC.
339c2daa00SOllivier Robert  *   SFTW P/N # 98-P39949M		SFTW P/N # 61-G10002A
349c2daa00SOllivier Robert  *   SOFTWARE VER # 5			SOFTWARE VER # 1
359c2daa00SOllivier Robert  *   SOFTWARE REV # 0			SOFTWARE REV # 3
369c2daa00SOllivier Robert  *   SOFTWARE DATE  20 JAN 1994 	SOFTWARE DATE  Mar 13 2000
379c2daa00SOllivier Robert  *   MODEL #	A11121P116		MODEL #    P143T12NR1
38224ba2bdSOllivier Robert  *   HDWR P/N # _			HWDR P/N # 1
399c2daa00SOllivier Robert  *   SERIAL #	SSG0049809		SERIAL #   P003UD
409c2daa00SOllivier Robert  *   MANUFACTUR DATE 417AMA199		MANUFACTUR DATE 0C27
419c2daa00SOllivier Robert  *   OPTIONS LIST    AB
42224ba2bdSOllivier Robert  *
43ea906c41SOllivier Robert  *	      (M12+T)				  (M12+T later version)
44ea906c41SOllivier Robert  *   COPYRIGHT 1991-2002 MOTOROLA INC.	COPYRIGHT 1991-2003 MOTOROLA INC.
45ea906c41SOllivier Robert  *   SFTW P/N #     61-G10268A		SFTW P/N #     61-G10268A
46ea906c41SOllivier Robert  *   SOFTWARE VER # 2			SOFTWARE VER # 2
47ea906c41SOllivier Robert  *   SOFTWARE REV # 0			SOFTWARE REV # 1
48ea906c41SOllivier Robert  *   SOFTWARE DATE  AUG 14 2002 	SOFTWARE DATE  APR 16 2003
49ea906c41SOllivier Robert  *   MODEL #	P283T12T11		MODEL #    P273T12T12
50ea906c41SOllivier Robert  *   HWDR P/N # 2			HWDR P/N # 2
51ea906c41SOllivier Robert  *   SERIAL #	P04DC2			SERIAL #   P05Z7Z
52ea906c41SOllivier Robert  *   MANUFACTUR DATE 2J17		MANUFACTUR DATE 3G15
53ea906c41SOllivier Robert  *
54ea906c41SOllivier Robert  * --------------------------------------------------------------------------
552b15cb3dSCy Schubert  * Reg Clemens (June 2009)
562b15cb3dSCy Schubert  * BUG[1220] OK, big patch, but mostly done mechanically.  Change direct calls to write
572b15cb3dSCy Schubert  * to clockstats to a call to oncore_log, which now calls the old routine plus msyslog.
582b15cb3dSCy Schubert  * Have to set the LOG_LEVELS of the calls for msyslog, and this was done by hand. New
592b15cb3dSCy Schubert  * routine oncore_log.
602b15cb3dSCy Schubert  * --------------------------------------------------------------------------
612b15cb3dSCy Schubert  * Reg Clemens (June 2009)
622b15cb3dSCy Schubert  * BUG[1218] The comment on where the oncore driver gets its input file does not
632b15cb3dSCy Schubert  * agree with the code.  Change the comment.
642b15cb3dSCy Schubert  * --------------------------------------------------------------------------
652b15cb3dSCy Schubert  * Reg Clemens (June 2009)
662b15cb3dSCy Schubert  * change exit statements to return(0) in main program.  I had assumed that if the
672b15cb3dSCy Schubert  * PPS driver did not start for some reason, we shuould stop NTPD itelf.  Others
682b15cb3dSCy Schubert  * disagree.  We now give an ERR log message and stop this driver.
692b15cb3dSCy Schubert  * --------------------------------------------------------------------------
702b15cb3dSCy Schubert  * Reg Clemens (June 2009)
712b15cb3dSCy Schubert  * A bytes available message for the input subsystem (Debug message).
722b15cb3dSCy Schubert  * --------------------------------------------------------------------------
732b15cb3dSCy Schubert  * Reg Clemens (Nov 2008)
742b15cb3dSCy Schubert  * This code adds a message for TRAIM messages.  Users often worry about the
752b15cb3dSCy Schubert  * driver not starting up, and it is often because of signal strength being low.
762b15cb3dSCy Schubert  * Low signal strength will give TRAIM messages.
772b15cb3dSCy Schubert  * --------------------------------------------------------------------------
782b15cb3dSCy Schubert  * Reg Clemens (Nov 2008)
792b15cb3dSCy Schubert  * Add waiting on Almanac Message.
802b15cb3dSCy Schubert  * --------------------------------------------------------------------------
812b15cb3dSCy Schubert  * Reg Clemens (Nov 2008)
822b15cb3dSCy Schubert  * Add back in @@Bl code to do the @@Bj/@@Gj that is in later ONCOREs
832b15cb3dSCy Schubert  * LEAP SECONDS: All of the ONCORE receivers, VP -> M12T have the @@Bj command
842b15cb3dSCy Schubert  * that says 'Leap Pending'.  As documented it only becomes true in the month
852b15cb3dSCy Schubert  * before the leap second is to be applied, but in practice at least some of
862b15cb3dSCy Schubert  * the receivers turn this indicator on as soon as the message is posted, which
872b15cb3dSCy Schubert  * can be 6months early.  As such, we use the Bj command to turn on the
882b15cb3dSCy Schubert  * instance->pp->leap indicator but only run this test in December and June for
892b15cb3dSCy Schubert  * updates on 1Jan and 1July.
902b15cb3dSCy Schubert  *
912b15cb3dSCy Schubert  * The @@Gj command exists in later ONCOREs, and it gives the exact date
922b15cb3dSCy Schubert  * and size of the Leap Update.  It can be emulated in the VP using the @@Bl
932b15cb3dSCy Schubert  * command which reads the raw Satellite Broadcast Messages.
942b15cb3dSCy Schubert  * We use these two commands to print informative messages in the clockstats
952b15cb3dSCy Schubert  * file once per day as soon as the message appears on the satellites.
962b15cb3dSCy Schubert  * --------------------------------------------------------------------------
97ea906c41SOllivier Robert  * Reg Clemens (Feb 2006)
98ea906c41SOllivier Robert  * Fix some gcc4 compiler complaints
99ea906c41SOllivier Robert  * Fix possible segfault in oncore_init_shmem
100ea906c41SOllivier Robert  * change all (possible) fprintf(stderr, to record_clock_stats
101ea906c41SOllivier Robert  * Apply patch from Russell J. Yount <rjy@cmu.edu> Fixed (new) MT12+T UTC not correct
102ea906c41SOllivier Robert  *   immediately after new Almanac Read.
103ea906c41SOllivier Robert  * Apply patch for new PPS implementation by Rodolfo Giometti <giometti@linux.it>
104ea906c41SOllivier Robert  *   now code can use old Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de> or
105ea906c41SOllivier Robert  *   the new one.  Compiles depending on timepps.h seen.
106ea906c41SOllivier Robert  * --------------------------------------------------------------------------
107ea906c41SOllivier Robert  * Luis Batanero Guerrero <luisba@rao.es> (Dec 2005) Patch for leap seconds
108ea906c41SOllivier Robert  * (the oncore driver was setting the wrong ntpd variable)
109ea906c41SOllivier Robert  * --------------------------------------------------------------------------
110ea906c41SOllivier Robert  * Reg.Clemens (Mar 2004)
111ea906c41SOllivier Robert  * Support for interfaces other than PPSAPI removed, for Solaris, SunOS,
112ea906c41SOllivier Robert  * SCO, you now need to use one of the timepps.h files in the root dir.
113ea906c41SOllivier Robert  * this driver will 'grab' it for you if you dont have one in /usr/include
114c0b746e5SOllivier Robert  * --------------------------------------------------------------------------
115c0b746e5SOllivier Robert  * This code uses the two devices
116c0b746e5SOllivier Robert  *	/dev/oncore.serial.n
117c0b746e5SOllivier Robert  *	/dev/oncore.pps.n
118c0b746e5SOllivier Robert  * which may be linked to the same device.
119c0b746e5SOllivier Robert  * and can read initialization data from the file
120224ba2bdSOllivier Robert  *	/etc/ntp.oncoreN, /etc/ntp.oncore.N, or /etc/ntp.oncore, where
121224ba2bdSOllivier Robert  *	n or N are the unit number, viz 127.127.30.N.
122c0b746e5SOllivier Robert  * --------------------------------------------------------------------------
123c0b746e5SOllivier Robert  * Reg.Clemens <reg@dwf.com> Sep98.
124c0b746e5SOllivier Robert  *  Original code written for FreeBSD.
125224ba2bdSOllivier Robert  *  With these mods it works on FreeBSD, SunOS, Solaris and Linux
126224ba2bdSOllivier Robert  *    (SunOS 4.1.3 + ppsclock)
127224ba2bdSOllivier Robert  *    (Solaris7 + MU4)
128224ba2bdSOllivier Robert  *    (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + or later).
129c0b746e5SOllivier Robert  *
130c0b746e5SOllivier Robert  *  Lat,Long,Ht, cable-delay, offset, and the ReceiverID (along with the
131c0b746e5SOllivier Robert  *  state machine state) are printed to CLOCKSTATS if that file is enabled
132c0b746e5SOllivier Robert  *  in /etc/ntp.conf.
133c0b746e5SOllivier Robert  *
134c0b746e5SOllivier Robert  * --------------------------------------------------------------------------
135224ba2bdSOllivier Robert  *
136c0b746e5SOllivier Robert  * According to the ONCORE manual (TRM0003, Rev 3.2, June 1998, page 3.13)
137c0b746e5SOllivier Robert  * doing an average of 10000 valid 2D and 3D fixes is what the automatic
138c0b746e5SOllivier Robert  * site survey mode does.  Looking at the output from the receiver
139c0b746e5SOllivier Robert  * it seems like it is only using 3D fixes.
140c0b746e5SOllivier Robert  * When we do it ourselves, take 10000 3D fixes.
141c0b746e5SOllivier Robert  */
142c0b746e5SOllivier Robert 
143c0b746e5SOllivier Robert #define POS_HOLD_AVERAGE	10000	/* nb, 10000s ~= 2h45m */
144c0b746e5SOllivier Robert 
145a151a66cSOllivier Robert /*
146a151a66cSOllivier Robert  * ONCORE_SHMEM_STATUS will create a mmap(2)'ed file named according to a
147a151a66cSOllivier Robert  * "STATUS" line in the oncore config file, which contains the most recent
148a151a66cSOllivier Robert  * copy of all types of messages we recognize.	This file can be mmap(2)'ed
149a151a66cSOllivier Robert  * by monitoring and statistics programs.
150224ba2bdSOllivier Robert  *
151224ba2bdSOllivier Robert  * See separate HTML documentation for this option.
152a151a66cSOllivier Robert  */
153a151a66cSOllivier Robert 
154c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H
155c0b746e5SOllivier Robert #include <config.h>
156c0b746e5SOllivier Robert #endif
157c0b746e5SOllivier Robert 
158ea906c41SOllivier Robert #if defined(REFCLOCK) && defined(CLOCK_ONCORE)
159224ba2bdSOllivier Robert 
160224ba2bdSOllivier Robert #include "ntpd.h"
161224ba2bdSOllivier Robert #include "ntp_io.h"
162224ba2bdSOllivier Robert #include "ntp_unixtime.h"
163224ba2bdSOllivier Robert #include "ntp_refclock.h"
1642b15cb3dSCy Schubert #include "ntp_calendar.h"
1652d4e511cSCy Schubert #include "ntp_calgps.h"
166224ba2bdSOllivier Robert #include "ntp_stdlib.h"
167c0b746e5SOllivier Robert 
168c0b746e5SOllivier Robert #include <stdio.h>
1692b15cb3dSCy Schubert #include <stdarg.h>
170c0b746e5SOllivier Robert #include <ctype.h>
171c0b746e5SOllivier Robert #include <sys/stat.h>
172a151a66cSOllivier Robert #ifdef ONCORE_SHMEM_STATUS
173a151a66cSOllivier Robert # ifdef HAVE_SYS_MMAN_H
174a151a66cSOllivier Robert #  include <sys/mman.h>
175a151a66cSOllivier Robert #  ifndef MAP_FAILED
176a151a66cSOllivier Robert #   define MAP_FAILED ((u_char *) -1)
177ea906c41SOllivier Robert #  endif  /* MAP_FAILED */
178a151a66cSOllivier Robert # endif /* HAVE_SYS_MMAN_H */
179a151a66cSOllivier Robert #endif /* ONCORE_SHMEM_STATUS */
180c0b746e5SOllivier Robert 
181c0b746e5SOllivier Robert #ifdef HAVE_PPSAPI
182ea906c41SOllivier Robert # include "ppsapi_timepps.h"
183c0b746e5SOllivier Robert #endif
184c0b746e5SOllivier Robert 
1852b15cb3dSCy Schubert struct Bl {
1862b15cb3dSCy Schubert 	int	dt_ls;
1872b15cb3dSCy Schubert 	int	dt_lsf;
1882b15cb3dSCy Schubert 	int	WN;
1892b15cb3dSCy Schubert 	int	DN;
1902b15cb3dSCy Schubert 	int	WN_lsf;
1912b15cb3dSCy Schubert 	int	DN_lsf;
1922b15cb3dSCy Schubert 	int	wn_flg;
1932b15cb3dSCy Schubert 	int	lsf_flg;
1942b15cb3dSCy Schubert 	int	Bl_day;
1952b15cb3dSCy Schubert } Bl;
196a151a66cSOllivier Robert 
197c0b746e5SOllivier Robert enum receive_state {
198c0b746e5SOllivier Robert 	ONCORE_NO_IDEA,
1999c2daa00SOllivier Robert 	ONCORE_CHECK_ID,
2009c2daa00SOllivier Robert 	ONCORE_CHECK_CHAN,
2019c2daa00SOllivier Robert 	ONCORE_HAVE_CHAN,
202c0b746e5SOllivier Robert 	ONCORE_RESET_SENT,
203c0b746e5SOllivier Robert 	ONCORE_TEST_SENT,
204224ba2bdSOllivier Robert 	ONCORE_INIT,
205c0b746e5SOllivier Robert 	ONCORE_ALMANAC,
206c0b746e5SOllivier Robert 	ONCORE_RUN
207c0b746e5SOllivier Robert };
208c0b746e5SOllivier Robert 
209c0b746e5SOllivier Robert enum site_survey_state {
210c0b746e5SOllivier Robert 	ONCORE_SS_UNKNOWN,
211224ba2bdSOllivier Robert 	ONCORE_SS_TESTING,
212c0b746e5SOllivier Robert 	ONCORE_SS_HW,
213c0b746e5SOllivier Robert 	ONCORE_SS_SW,
214c0b746e5SOllivier Robert 	ONCORE_SS_DONE
215c0b746e5SOllivier Robert };
216c0b746e5SOllivier Robert 
2179c2daa00SOllivier Robert enum antenna_state {
2189c2daa00SOllivier Robert       ONCORE_ANTENNA_UNKNOWN = -1,
2199c2daa00SOllivier Robert       ONCORE_ANTENNA_OK      =	0,
2209c2daa00SOllivier Robert       ONCORE_ANTENNA_OC      =	1,
2219c2daa00SOllivier Robert       ONCORE_ANTENNA_UC      =	2,
2229c2daa00SOllivier Robert       ONCORE_ANTENNA_NV      =	3
2239c2daa00SOllivier Robert };
2249c2daa00SOllivier Robert 
225224ba2bdSOllivier Robert /* Model Name, derived from the @@Cj message.
226224ba2bdSOllivier Robert  * Used to initialize some variables.
227224ba2bdSOllivier Robert  */
228224ba2bdSOllivier Robert 
229224ba2bdSOllivier Robert enum oncore_model {
230224ba2bdSOllivier Robert 	ONCORE_BASIC,
231224ba2bdSOllivier Robert 	ONCORE_PVT6,
232224ba2bdSOllivier Robert 	ONCORE_VP,
233224ba2bdSOllivier Robert 	ONCORE_UT,
234224ba2bdSOllivier Robert 	ONCORE_UTPLUS,
235224ba2bdSOllivier Robert 	ONCORE_GT,
236224ba2bdSOllivier Robert 	ONCORE_GTPLUS,
237224ba2bdSOllivier Robert 	ONCORE_SL,
238224ba2bdSOllivier Robert 	ONCORE_M12,
239224ba2bdSOllivier Robert 	ONCORE_UNKNOWN
240224ba2bdSOllivier Robert };
241224ba2bdSOllivier Robert 
242224ba2bdSOllivier Robert /* the bits that describe these properties are in the same place
243224ba2bdSOllivier Robert  * on the VP/UT, but have moved on the M12.  As such we extract
244224ba2bdSOllivier Robert  * them, and use them from this struct.
245224ba2bdSOllivier Robert  *
246224ba2bdSOllivier Robert  */
247224ba2bdSOllivier Robert 
248224ba2bdSOllivier Robert struct RSM {
249224ba2bdSOllivier Robert 	u_char	posn0D;
250224ba2bdSOllivier Robert 	u_char	posn2D;
251224ba2bdSOllivier Robert 	u_char	posn3D;
252224ba2bdSOllivier Robert 	u_char	bad_almanac;
253224ba2bdSOllivier Robert 	u_char	bad_fix;
254224ba2bdSOllivier Robert };
255224ba2bdSOllivier Robert 
256224ba2bdSOllivier Robert /* It is possible to test the VP/UT each cycle (@@Ea or equivalent) to
257224ba2bdSOllivier Robert  * see what mode it is in.  The bits on the M12 are multiplexed with
258224ba2bdSOllivier Robert  * other messages, so we have to 'keep' the last known mode here.
259224ba2bdSOllivier Robert  */
260224ba2bdSOllivier Robert 
261224ba2bdSOllivier Robert enum posn_mode {
262224ba2bdSOllivier Robert 	MODE_UNKNOWN,
263224ba2bdSOllivier Robert 	MODE_0D,
264224ba2bdSOllivier Robert 	MODE_2D,
265224ba2bdSOllivier Robert 	MODE_3D
266224ba2bdSOllivier Robert };
267224ba2bdSOllivier Robert 
268c0b746e5SOllivier Robert struct instance {
269c0b746e5SOllivier Robert 	int	unit;		/* 127.127.30.unit */
270224ba2bdSOllivier Robert 	struct	refclockproc *pp;
271224ba2bdSOllivier Robert 	struct	peer *peer;
272224ba2bdSOllivier Robert 
273c0b746e5SOllivier Robert 	int	ttyfd;		/* TTY file descriptor */
274c0b746e5SOllivier Robert 	int	ppsfd;		/* PPS file descriptor */
2759c2daa00SOllivier Robert 	int	shmemfd;	/* Status shm descriptor */
276c0b746e5SOllivier Robert 	pps_handle_t pps_h;
277c0b746e5SOllivier Robert 	pps_params_t pps_p;
278c0b746e5SOllivier Robert 	enum receive_state o_state;		/* Receive state */
279224ba2bdSOllivier Robert 	enum posn_mode mode;			/* 0D, 2D, 3D */
280c0b746e5SOllivier Robert 	enum site_survey_state site_survey;	/* Site Survey state */
2819c2daa00SOllivier Robert 	enum antenna_state ant_state;		/* antenna state */
282c0b746e5SOllivier Robert 
283c0b746e5SOllivier Robert 	int	Bj_day;
284c0b746e5SOllivier Robert 
285224ba2bdSOllivier Robert 	u_long	delay;		/* ns */
286c0b746e5SOllivier Robert 	long	offset; 	/* ns */
287c0b746e5SOllivier Robert 
288224ba2bdSOllivier Robert 	u_char	*shmem;
289224ba2bdSOllivier Robert 	char	*shmem_fname;
290224ba2bdSOllivier Robert 	u_int	shmem_Cb;
291224ba2bdSOllivier Robert 	u_int	shmem_Ba;
292224ba2bdSOllivier Robert 	u_int	shmem_Ea;
293224ba2bdSOllivier Robert 	u_int	shmem_Ha;
294224ba2bdSOllivier Robert 	u_char	shmem_reset;
295224ba2bdSOllivier Robert 	u_char	shmem_Posn;
2969c2daa00SOllivier Robert 	u_char	shmem_bad_Ea;
2979c2daa00SOllivier Robert 	u_char	almanac_from_shmem;
298224ba2bdSOllivier Robert 
299c0b746e5SOllivier Robert 	double	ss_lat;
300c0b746e5SOllivier Robert 	double	ss_long;
301c0b746e5SOllivier Robert 	double	ss_ht;
302224ba2bdSOllivier Robert 	double	dH;
303c0b746e5SOllivier Robert 	int	ss_count;
304a151a66cSOllivier Robert 	u_char	posn_set;
305c0b746e5SOllivier Robert 
306224ba2bdSOllivier Robert 	enum oncore_model model;
307224ba2bdSOllivier Robert 	u_int	version;
308224ba2bdSOllivier Robert 	u_int	revision;
309224ba2bdSOllivier Robert 
310224ba2bdSOllivier Robert 	u_char	chan;		/* 6 for PVT6 or BASIC, 8 for UT/VP, 12 for m12, 0 if unknown */
311ea906c41SOllivier Robert 	s_char	traim;		/* do we have traim? yes UT/VP, M12+T, no BASIC, GT, M12, -1 unknown, 0 no, +1 yes */
3129c2daa00SOllivier Robert 				/* the following 7 are all timing counters */
313224ba2bdSOllivier Robert 	u_char	traim_delay;	/* seconds counter, waiting for reply */
3149c2daa00SOllivier Robert 	u_char	count;		/* cycles thru Ea before starting */
3159c2daa00SOllivier Robert 	u_char	count1; 	/* cycles thru Ea after SS_TESTING, waiting for SS_HW */
3169c2daa00SOllivier Robert 	u_char	count2; 	/* cycles thru Ea after count, to check for @@Ea */
3179c2daa00SOllivier Robert 	u_char	count3; 	/* cycles thru Ea checking for # channels */
3189c2daa00SOllivier Robert 	u_char	count4; 	/* cycles thru leap after Gj to issue Bj */
319ea906c41SOllivier Robert 	u_char	count5; 	/* cycles thru get_timestamp waiting for valid UTC correction */
320ea906c41SOllivier Robert 	u_char	count5_set;	/* only set count5 once */
3212b15cb3dSCy Schubert 	u_char	counta; 	/* count for waiting on almanac message */
3229c2daa00SOllivier Robert 	u_char	pollcnt;
3239c2daa00SOllivier Robert 	u_char	timeout;	/* count to retry Cj after Fa self-test */
3242b15cb3dSCy Schubert 	u_char	max_len;	/* max length message seen by oncore_log, for debugging */
3252b15cb3dSCy Schubert 	u_char	max_count;	/* count for message statistics */
326224ba2bdSOllivier Robert 
327224ba2bdSOllivier Robert 	struct	RSM rsm;	/* bits extracted from Receiver Status Msg in @@Ea */
3282b15cb3dSCy Schubert 	struct	Bl Bl;		/* Satellite Broadcast Data Message */
329a151a66cSOllivier Robert 	u_char	printed;
330a151a66cSOllivier Robert 	u_char	polled;
3319c2daa00SOllivier Robert 	u_long	ev_serial;
3322b15cb3dSCy Schubert 	unsigned	Rcvptr;
333c0b746e5SOllivier Robert 	u_char	Rcvbuf[500];
3349c2daa00SOllivier Robert 	u_char	BEHa[160];	/* Ba, Ea or Ha */
3359c2daa00SOllivier Robert 	u_char	BEHn[80];	/* Bn , En , or Hn */
336c0b746e5SOllivier Robert 	u_char	Cj[300];
3379c2daa00SOllivier Robert 	u_char	Ag;		/* Satellite mask angle */
3389c2daa00SOllivier Robert 	u_char	saw_At;
3399c2daa00SOllivier Robert 	u_char	saw_Ay;
3409c2daa00SOllivier Robert 	u_char	saw_Az;
3412b15cb3dSCy Schubert 	s_char	saw_Bj;
3429c2daa00SOllivier Robert 	s_char	saw_Gj;
343224ba2bdSOllivier Robert 	u_char	have_dH;
344c0b746e5SOllivier Robert 	u_char	init_type;
345c0b746e5SOllivier Robert 	s_char	saw_tooth;
3469c2daa00SOllivier Robert 	s_char	chan_in;	/* chan number from INPUT, will always use it */
3479c2daa00SOllivier Robert 	u_char	chan_id;	/* chan number determined from part number */
3489c2daa00SOllivier Robert 	u_char	chan_ck;	/* chan number determined by sending commands to hardware */
349ea906c41SOllivier Robert 	s_char	traim_in;	/* TRAIM from INPUT, will always use ON/OFF specified */
3509c2daa00SOllivier Robert 	s_char	traim_id;	/* TRAIM determined from part number */
3519c2daa00SOllivier Robert 	u_char	traim_ck;	/* TRAIM determined by sending commands to hardware */
3529c2daa00SOllivier Robert 	u_char	once;		/* one pass code at top of BaEaHa */
353a151a66cSOllivier Robert 	s_char	assert;
3549c2daa00SOllivier Robert 	u_char	hardpps;
3552b15cb3dSCy Schubert 	s_char	pps_control;	/* PPS control, M12 only */
3562b15cb3dSCy Schubert 	s_char	pps_control_msg_seen;
357c0b746e5SOllivier Robert };
358c0b746e5SOllivier Robert 
359c0b746e5SOllivier Robert #define rcvbuf	instance->Rcvbuf
360c0b746e5SOllivier Robert #define rcvptr	instance->Rcvptr
361c0b746e5SOllivier Robert 
3622b15cb3dSCy Schubert static	int	oncore_start	      (int, struct peer *);
3632b15cb3dSCy Schubert static	void	oncore_poll	      (int, struct peer *);
3642b15cb3dSCy Schubert static	void	oncore_shutdown       (int, struct peer *);
3652b15cb3dSCy Schubert static	void	oncore_consume	      (struct instance *);
3662b15cb3dSCy Schubert static	void	oncore_read_config    (struct instance *);
3672b15cb3dSCy Schubert static	void	oncore_receive	      (struct recvbuf *);
3682b15cb3dSCy Schubert static	int	oncore_ppsapi	      (struct instance *);
3692b15cb3dSCy Schubert static	void	oncore_get_timestamp  (struct instance *, long, long);
3702b15cb3dSCy Schubert static	void	oncore_init_shmem     (struct instance *);
3719c2daa00SOllivier Robert 
3722b15cb3dSCy Schubert static	void	oncore_antenna_report (struct instance *, enum antenna_state);
3732b15cb3dSCy Schubert static	void	oncore_chan_test      (struct instance *);
3742b15cb3dSCy Schubert static	void	oncore_check_almanac  (struct instance *);
3752b15cb3dSCy Schubert static	void	oncore_check_antenna  (struct instance *);
3762b15cb3dSCy Schubert static	void	oncore_check_leap_sec (struct instance *);
3772b15cb3dSCy Schubert static	int	oncore_checksum_ok    (u_char *, int);
3782b15cb3dSCy Schubert static	void	oncore_compute_dH     (struct instance *);
3792b15cb3dSCy Schubert static	void	oncore_load_almanac   (struct instance *);
3802b15cb3dSCy Schubert static	void	oncore_log	      (struct instance *, int, const char *);
3812b15cb3dSCy Schubert static	int	oncore_log_f	      (struct instance *, int, const char *, ...)
3822b15cb3dSCy Schubert 		NTP_PRINTF(3, 4);
3832b15cb3dSCy Schubert static	void	oncore_print_Cb       (struct instance *, u_char *);
3842b15cb3dSCy Schubert /* static  void    oncore_print_array	 (u_char *, int);	*/
3852b15cb3dSCy Schubert static	void	oncore_print_posn     (struct instance *);
3862b15cb3dSCy Schubert static	void	oncore_sendmsg	      (struct instance *, u_char *, size_t);
3872b15cb3dSCy Schubert static	void	oncore_set_posn       (struct instance *);
3882b15cb3dSCy Schubert static	void	oncore_set_traim      (struct instance *);
3892b15cb3dSCy Schubert static	void	oncore_shmem_get_3D   (struct instance *);
3902b15cb3dSCy Schubert static	void	oncore_ss	      (struct instance *);
3912b15cb3dSCy Schubert static	int	oncore_wait_almanac   (struct instance *);
3922d4e511cSCy Schubert static	void	oncore_feed_clockproc (struct instance *);
393c0b746e5SOllivier Robert 
3942b15cb3dSCy Schubert static	void	oncore_msg_any	   (struct instance *, u_char *, size_t, int);
3952b15cb3dSCy Schubert static	void	oncore_msg_Adef    (struct instance *, u_char *, size_t);
3962b15cb3dSCy Schubert static	void	oncore_msg_Ag	   (struct instance *, u_char *, size_t);
3972b15cb3dSCy Schubert static	void	oncore_msg_As	   (struct instance *, u_char *, size_t);
3982b15cb3dSCy Schubert static	void	oncore_msg_At	   (struct instance *, u_char *, size_t);
3992b15cb3dSCy Schubert static	void	oncore_msg_Ay	   (struct instance *, u_char *, size_t);
4002b15cb3dSCy Schubert static	void	oncore_msg_Az	   (struct instance *, u_char *, size_t);
4012b15cb3dSCy Schubert static	void	oncore_msg_BaEaHa  (struct instance *, u_char *, size_t);
4022b15cb3dSCy Schubert static	void	oncore_msg_Bd	   (struct instance *, u_char *, size_t);
4032b15cb3dSCy Schubert static	void	oncore_msg_Bj	   (struct instance *, u_char *, size_t);
4042b15cb3dSCy Schubert static	void	oncore_msg_Bl	   (struct instance *, u_char *, size_t);
4052b15cb3dSCy Schubert static	void	oncore_msg_BnEnHn  (struct instance *, u_char *, size_t);
4062b15cb3dSCy Schubert static	void	oncore_msg_CaFaIa  (struct instance *, u_char *, size_t);
4072b15cb3dSCy Schubert static	void	oncore_msg_Cb	   (struct instance *, u_char *, size_t);
4082b15cb3dSCy Schubert static	void	oncore_msg_Cf	   (struct instance *, u_char *, size_t);
4092b15cb3dSCy Schubert static	void	oncore_msg_Cj	   (struct instance *, u_char *, size_t);
4102b15cb3dSCy Schubert static	void	oncore_msg_Cj_id   (struct instance *, u_char *, size_t);
4112b15cb3dSCy Schubert static	void	oncore_msg_Cj_init (struct instance *, u_char *, size_t);
4122b15cb3dSCy Schubert static	void	oncore_msg_Ga	   (struct instance *, u_char *, size_t);
4132b15cb3dSCy Schubert static	void	oncore_msg_Gb	   (struct instance *, u_char *, size_t);
4142b15cb3dSCy Schubert static	void	oncore_msg_Gc	   (struct instance *, u_char *, size_t);
4152b15cb3dSCy Schubert static	void	oncore_msg_Gj	   (struct instance *, u_char *, size_t);
4162b15cb3dSCy Schubert static	void	oncore_msg_Sz	   (struct instance *, u_char *, size_t);
417c0b746e5SOllivier Robert 
418c0b746e5SOllivier Robert struct	refclock refclock_oncore = {
419c0b746e5SOllivier Robert 	oncore_start,		/* start up driver */
420c0b746e5SOllivier Robert 	oncore_shutdown,	/* shut down driver */
421c0b746e5SOllivier Robert 	oncore_poll,		/* transmit poll message */
422ea906c41SOllivier Robert 	noentry,		/* not used */
423c0b746e5SOllivier Robert 	noentry,		/* not used */
424c0b746e5SOllivier Robert 	noentry,		/* not used */
425c0b746e5SOllivier Robert 	NOFLAGS 		/* not used */
426c0b746e5SOllivier Robert };
427c0b746e5SOllivier Robert 
428c0b746e5SOllivier Robert /*
429c0b746e5SOllivier Robert  * Understanding the next bit here is not easy unless you have a manual
430224ba2bdSOllivier Robert  * for the the various Oncore Models.
431c0b746e5SOllivier Robert  */
432c0b746e5SOllivier Robert 
433a151a66cSOllivier Robert static struct msg_desc {
434c0b746e5SOllivier Robert 	const char	flag[3];
435c0b746e5SOllivier Robert 	const int	len;
4362b15cb3dSCy Schubert 	void		(*handler) (struct instance *, u_char *, size_t);
437c0b746e5SOllivier Robert 	const char	*fmt;
438a151a66cSOllivier Robert 	int		shmem;
439c0b746e5SOllivier Robert } oncore_messages[] = {
440c0b746e5SOllivier Robert 			/* Ea and En first since they're most common */
4412b15cb3dSCy Schubert 	{ "Ea",  76,    oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC", 0 },
4422b15cb3dSCy Schubert 	{ "Ba",  68,    oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC", 0 },
4432b15cb3dSCy Schubert 	{ "Ha", 154,    oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC", 0 },
4442b15cb3dSCy Schubert 	{ "Bn",  59,    oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC", 0 },
4452b15cb3dSCy Schubert 	{ "En",  69,    oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC", 0 },
4462b15cb3dSCy Schubert 	{ "Hn",  78,    oncore_msg_BnEnHn, "", 0 },
4472b15cb3dSCy Schubert 	{ "Ab",  10,    0,                 "", 0 },
4482b15cb3dSCy Schubert 	{ "Ac",  11,    0,                 "", 0 },
4492b15cb3dSCy Schubert 	{ "Ad",  11,    oncore_msg_Adef,   "", 0 },
4502b15cb3dSCy Schubert 	{ "Ae",  11,    oncore_msg_Adef,   "", 0 },
4512b15cb3dSCy Schubert 	{ "Af",  15,    oncore_msg_Adef,   "", 0 },
4522b15cb3dSCy Schubert 	{ "Ag",   8,    oncore_msg_Ag,     "", 0 }, /* Satellite mask angle */
4532b15cb3dSCy Schubert 	{ "As",  20,    oncore_msg_As,     "", 0 },
4542b15cb3dSCy Schubert 	{ "At",   8,    oncore_msg_At,     "", 0 },
4552b15cb3dSCy Schubert 	{ "Au",  12,    0,                 "", 0 },
4562b15cb3dSCy Schubert 	{ "Av",   8,    0,                 "", 0 },
4572b15cb3dSCy Schubert 	{ "Aw",   8,    0,                 "", 0 },
4582b15cb3dSCy Schubert 	{ "Ay",  11,    oncore_msg_Ay,     "", 0 },
4592b15cb3dSCy Schubert 	{ "Az",  11,    oncore_msg_Az,     "", 0 },
4602b15cb3dSCy Schubert 	{ "AB",   8,    0,                 "", 0 },
4612b15cb3dSCy Schubert 	{ "Bb",  92,    0,                 "", 0 },
4622b15cb3dSCy Schubert 	{ "Bd",  23,    oncore_msg_Bd,     "", 0 },
4632b15cb3dSCy Schubert 	{ "Bj",   8,    oncore_msg_Bj,     "", 0 },
4642b15cb3dSCy Schubert 	{ "Bl",  41,    oncore_msg_Bl,     "", 0 },
4652b15cb3dSCy Schubert 	{ "Ca",   9,    oncore_msg_CaFaIa, "", 0 },
4662b15cb3dSCy Schubert 	{ "Cb",  33,    oncore_msg_Cb,     "", 0 },
4672b15cb3dSCy Schubert 	{ "Cf",   7,    oncore_msg_Cf,     "", 0 },
4682b15cb3dSCy Schubert 	{ "Cg",   8,    0,                 "", 0 },
4692b15cb3dSCy Schubert 	{ "Ch",   9,    0,                 "", 0 },
4702b15cb3dSCy Schubert 	{ "Cj", 294,    oncore_msg_Cj,     "", 0 },
4712b15cb3dSCy Schubert 	{ "Ek",  71,    0,                 "", 0 },
4722b15cb3dSCy Schubert 	{ "Fa",   9,    oncore_msg_CaFaIa, "", 0 },
4732b15cb3dSCy Schubert 	{ "Ga",  20,    oncore_msg_Ga,     "", 0 },
4742b15cb3dSCy Schubert 	{ "Gb",  17,    oncore_msg_Gb,     "", 0 },
4752b15cb3dSCy Schubert 	{ "Gc",   8,    oncore_msg_Gc,     "", 0 },
4762b15cb3dSCy Schubert 	{ "Gd",   8,    0,                 "", 0 },
4772b15cb3dSCy Schubert 	{ "Ge",   8,    0,                 "", 0 },
4782b15cb3dSCy Schubert 	{ "Gj",  21,    oncore_msg_Gj,     "", 0 },
4792b15cb3dSCy Schubert 	{ "Ia",  10,    oncore_msg_CaFaIa, "", 0 },
4802b15cb3dSCy Schubert 	{ "Sz",   8,    oncore_msg_Sz,     "", 0 },
4812b15cb3dSCy Schubert 	{ {0},	  7,	0,		   "", 0 }
482c0b746e5SOllivier Robert };
483c0b746e5SOllivier Robert 
4849c2daa00SOllivier Robert 
4859c2daa00SOllivier Robert static u_char oncore_cmd_Aa[]  = { 'A', 'a', 0, 0, 0 }; 			    /* 6/8	Time of Day				*/
4869c2daa00SOllivier Robert static u_char oncore_cmd_Ab[]  = { 'A', 'b', 0, 0, 0 }; 			    /* 6/8	GMT Correction				*/
4879c2daa00SOllivier Robert static u_char oncore_cmd_AB[]  = { 'A', 'B', 4 };				    /* VP	Application Type: Static		*/
4889c2daa00SOllivier Robert static u_char oncore_cmd_Ac[]  = { 'A', 'c', 0, 0, 0, 0 };			    /* 6/8	Date					*/
4899c2daa00SOllivier Robert static u_char oncore_cmd_Ad[]  = { 'A', 'd', 0,0,0,0 }; 			    /* 6/8	Latitude				*/
4909c2daa00SOllivier Robert static u_char oncore_cmd_Ae[]  = { 'A', 'e', 0,0,0,0 }; 			    /* 6/8	Longitude				*/
4919c2daa00SOllivier Robert static u_char oncore_cmd_Af[]  = { 'A', 'f', 0,0,0,0, 0 };			    /* 6/8	Height					*/
4929c2daa00SOllivier Robert static u_char oncore_cmd_Ag[]  = { 'A', 'g', 0 };				    /* 6/8/12	Satellite Mask Angle			*/
4939c2daa00SOllivier Robert static u_char oncore_cmd_Agx[] = { 'A', 'g', 0xff };				    /* 6/8/12	Satellite Mask Angle: read		*/
4949c2daa00SOllivier Robert static u_char oncore_cmd_As[]  = { 'A', 's', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 };	    /* 6/8/12	Posn Hold Parameters			*/
4959c2daa00SOllivier Robert static u_char oncore_cmd_Asx[] = { 'A', 's', 0x7f,0xff,0xff,0xff,		    /* 6/8/12	Posn Hold Readback			*/
4969c2daa00SOllivier Robert 					     0x7f,0xff,0xff,0xff,		    /*		 on UT+ this doesnt work with 0xff	*/
4979c2daa00SOllivier Robert 					     0x7f,0xff,0xff,0xff, 0xff };	    /*		 but does work with 0x7f (sigh).	*/
4989c2daa00SOllivier Robert static u_char oncore_cmd_At0[] = { 'A', 't', 0 };				    /* 6/8	Posn Hold: off				*/
4999c2daa00SOllivier Robert static u_char oncore_cmd_At1[] = { 'A', 't', 1 };				    /* 6/8	Posn Hold: on				*/
5009c2daa00SOllivier Robert static u_char oncore_cmd_At2[] = { 'A', 't', 2 };				    /* 6/8	Posn Hold: Start Site Survey		*/
5019c2daa00SOllivier Robert static u_char oncore_cmd_Atx[] = { 'A', 't', 0xff };				    /* 6/8	Posn Hold: Read Back			*/
5029c2daa00SOllivier Robert static u_char oncore_cmd_Au[]  = { 'A', 'u', 0,0,0,0, 0 };			    /* GT/M12	Altitude Hold Ht.			*/
5039c2daa00SOllivier Robert static u_char oncore_cmd_Av0[] = { 'A', 'v', 0 };				    /* VP/GT	Altitude Hold: off			*/
5049c2daa00SOllivier Robert static u_char oncore_cmd_Av1[] = { 'A', 'v', 1 };				    /* VP/GT	Altitude Hold: on			*/
5059c2daa00SOllivier Robert static u_char oncore_cmd_Aw[]  = { 'A', 'w', 1 };				    /* 6/8/12	UTC/GPS time selection			*/
5069c2daa00SOllivier Robert static u_char oncore_cmd_Ay[]  = { 'A', 'y', 0, 0, 0, 0 };			    /* Timing	1PPS time offset: set			*/
5079c2daa00SOllivier Robert static u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff };		    /* Timing	1PPS time offset: Read			*/
5089c2daa00SOllivier Robert static u_char oncore_cmd_Az[]  = { 'A', 'z', 0, 0, 0, 0 };			    /* 6/8UT/12 1PPS Cable Delay: set			*/
5099c2daa00SOllivier Robert static u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff };		    /* 6/8UT/12 1PPS Cable Delay: Read			*/
5109c2daa00SOllivier Robert static u_char oncore_cmd_Ba0[] = { 'B', 'a', 0 };				    /* 6	Position/Data/Status: off		*/
5119c2daa00SOllivier Robert static u_char oncore_cmd_Ba[]  = { 'B', 'a', 1 };				    /* 6	Position/Data/Status: on		*/
5129c2daa00SOllivier Robert static u_char oncore_cmd_Bb[]  = { 'B', 'b', 1 };				    /* 6/8/12	Visible Satellites			*/
5139c2daa00SOllivier Robert static u_char oncore_cmd_Bd[]  = { 'B', 'd', 1 };				    /* 6/8/12?	Almanac Status Msg.			*/
5149c2daa00SOllivier Robert static u_char oncore_cmd_Be[]  = { 'B', 'e', 1 };				    /* 6/8/12	Request Almanac Data			*/
5159c2daa00SOllivier Robert static u_char oncore_cmd_Bj[]  = { 'B', 'j', 0 };				    /* 6/8	Leap Second Pending			*/
5162b15cb3dSCy Schubert static u_char oncore_cmd_Bl[]  = { 'B', 'l', 1 };				    /* VP	Satellite Broadcast Data Msg		*/
5179c2daa00SOllivier Robert static u_char oncore_cmd_Bn0[] = { 'B', 'n', 0, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6	TRAIM setup/status: msg off, traim on	*/
518ea906c41SOllivier Robert static u_char oncore_cmd_Bn[]  = { 'B', 'n', 1, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6	TRAIM setup/status: msg on,  traim on	*/
519ea906c41SOllivier Robert static u_char oncore_cmd_Bnx[] = { 'B', 'n', 0, 0, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6	TRAIM setup/status: msg off, traim off	*/
5209c2daa00SOllivier Robert static u_char oncore_cmd_Ca[]  = { 'C', 'a' };					    /* 6	Self Test				*/
5219c2daa00SOllivier Robert static u_char oncore_cmd_Cf[]  = { 'C', 'f' };					    /* 6/8/12	Set to Defaults 			*/
5229c2daa00SOllivier Robert static u_char oncore_cmd_Cg[]  = { 'C', 'g', 1 };				    /* VP	Posn Fix/Idle Mode			*/
5239c2daa00SOllivier Robert static u_char oncore_cmd_Cj[]  = { 'C', 'j' };					    /* 6/8/12	Receiver ID				*/
5249c2daa00SOllivier Robert static u_char oncore_cmd_Ea0[] = { 'E', 'a', 0 };				    /* 8	Position/Data/Status: off		*/
5259c2daa00SOllivier Robert static u_char oncore_cmd_Ea[]  = { 'E', 'a', 1 };				    /* 8	Position/Data/Status: on		*/
5269c2daa00SOllivier Robert static u_char oncore_cmd_Ek[]  = { 'E', 'k', 0 }; /* just turn off */		    /* 8	Posn/Status/Data - extension		*/
5279c2daa00SOllivier Robert static u_char oncore_cmd_En0[] = { 'E', 'n', 0, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT	TRAIM setup/status: msg off, traim on	*/
528ea906c41SOllivier Robert static u_char oncore_cmd_En[]  = { 'E', 'n', 1, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT	TRAIM setup/status: msg on,  traim on	*/
529ea906c41SOllivier Robert static u_char oncore_cmd_Enx[] = { 'E', 'n', 0, 0, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT	TRAIM setup/status: msg off, traim off	*/
5309c2daa00SOllivier Robert static u_char oncore_cmd_Fa[]  = { 'F', 'a' };					    /* 8	Self Test				*/
5319c2daa00SOllivier Robert static u_char oncore_cmd_Ga[]  = { 'G', 'a', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 };	    /* 12	Position Set				*/
5329c2daa00SOllivier Robert static u_char oncore_cmd_Gax[] = { 'G', 'a', 0xff, 0xff, 0xff, 0xff,		    /* 12	Position Set: Read			*/
5339c2daa00SOllivier Robert 					     0xff, 0xff, 0xff, 0xff,		    /*							*/
5349c2daa00SOllivier Robert 					     0xff, 0xff, 0xff, 0xff, 0xff };	    /*							*/
5359c2daa00SOllivier Robert static u_char oncore_cmd_Gb[]  = { 'G', 'b', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };	    /* 12	set Date/Time				*/
5362b15cb3dSCy Schubert static u_char oncore_cmd_Gc[]  = { 'G', 'c', 0 };				    /* 12	PPS Control: Off, On, 1+satellite,TRAIM */
5379c2daa00SOllivier Robert static u_char oncore_cmd_Gd0[] = { 'G', 'd', 0 };				    /* 12	Position Control: 3D (no hold)		*/
5389c2daa00SOllivier Robert static u_char oncore_cmd_Gd1[] = { 'G', 'd', 1 };				    /* 12	Position Control: 0D (3D hold)		*/
5399c2daa00SOllivier Robert static u_char oncore_cmd_Gd2[] = { 'G', 'd', 2 };				    /* 12	Position Control: 2D (Alt Hold) 	*/
5409c2daa00SOllivier Robert static u_char oncore_cmd_Gd3[] = { 'G', 'd', 3 };				    /* 12	Position Coltrol: Start Site Survey	*/
5419c2daa00SOllivier Robert static u_char oncore_cmd_Ge0[] = { 'G', 'e', 0 };				    /* M12+T	TRAIM: off				*/
5429c2daa00SOllivier Robert static u_char oncore_cmd_Ge[]  = { 'G', 'e', 1 };				    /* M12+T	TRAIM: on				*/
5439c2daa00SOllivier Robert static u_char oncore_cmd_Gj[]  = { 'G', 'j' };					    /* 8?/12	Leap Second Pending			*/
5449c2daa00SOllivier Robert static u_char oncore_cmd_Ha0[] = { 'H', 'a', 0 };				    /* 12	Position/Data/Status: off		*/
5459c2daa00SOllivier Robert static u_char oncore_cmd_Ha[]  = { 'H', 'a', 1 };				    /* 12	Position/Data/Status: on		*/
5469c2daa00SOllivier Robert static u_char oncore_cmd_Hn0[] = { 'H', 'n', 0 };				    /* 12	TRAIM Status: off			*/
5479c2daa00SOllivier Robert static u_char oncore_cmd_Hn[]  = { 'H', 'n', 1 };				    /* 12	TRAIM Status: on			*/
5489c2daa00SOllivier Robert static u_char oncore_cmd_Ia[]  = { 'I', 'a' };					    /* 12	Self Test				*/
5499c2daa00SOllivier Robert 
5509c2daa00SOllivier Robert /* it appears that as of 1997/1998, the UT had As,At, but not Au,Av
5519c2daa00SOllivier Robert  *				    the GT had Au,Av, but not As,At
5529c2daa00SOllivier Robert  * This was as of v2.0 of both firmware sets. possibly 1.3 for UT.
5539c2daa00SOllivier Robert  * Bj in UT at v1.3
5549c2daa00SOllivier Robert  * dont see Bd in UT/GT thru 1999
5559c2daa00SOllivier Robert  * Gj in UT as of 3.0, 1999 , Bj as of 1.3
556c0b746e5SOllivier Robert  */
557c0b746e5SOllivier Robert 
558c0b746e5SOllivier Robert #define DEVICE1 	"/dev/oncore.serial.%d" /* name of serial device */
559c0b746e5SOllivier Robert #define DEVICE2 	"/dev/oncore.pps.%d"    /* name of pps device */
560c0b746e5SOllivier Robert 
561c0b746e5SOllivier Robert #define SPEED		B9600		/* Oncore Binary speed (9600 bps) */
562c0b746e5SOllivier Robert 
563c0b746e5SOllivier Robert /*
564c0b746e5SOllivier Robert  * Assemble and disassemble 32bit signed quantities from a buffer.
565c0b746e5SOllivier Robert  *
566c0b746e5SOllivier Robert  */
567c0b746e5SOllivier Robert 
568c0b746e5SOllivier Robert 	/* to buffer, int w, u_char *buf */
569224ba2bdSOllivier Robert #define w32_buf(buf,w)	{ u_int i_tmp;			   \
570c0b746e5SOllivier Robert 			  i_tmp = (w<0) ? (~(-w)+1) : (w); \
571c0b746e5SOllivier Robert 			  (buf)[0] = (i_tmp >> 24) & 0xff; \
572c0b746e5SOllivier Robert 			  (buf)[1] = (i_tmp >> 16) & 0xff; \
573c0b746e5SOllivier Robert 			  (buf)[2] = (i_tmp >>	8) & 0xff; \
574c0b746e5SOllivier Robert 			  (buf)[3] = (i_tmp	 ) & 0xff; \
575c0b746e5SOllivier Robert 			}
576c0b746e5SOllivier Robert 
577c0b746e5SOllivier Robert #define w32(buf)      (((buf)[0]&0xff) << 24 | \
578c0b746e5SOllivier Robert 		       ((buf)[1]&0xff) << 16 | \
579c0b746e5SOllivier Robert 		       ((buf)[2]&0xff) <<  8 | \
580c0b746e5SOllivier Robert 		       ((buf)[3]&0xff) )
581c0b746e5SOllivier Robert 
582c0b746e5SOllivier Robert 	/* from buffer, char *buf, result to an int */
583c0b746e5SOllivier Robert #define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf))
584c0b746e5SOllivier Robert 
585224ba2bdSOllivier Robert 
586c0b746e5SOllivier Robert /*
587c0b746e5SOllivier Robert  * oncore_start - initialize data for processing
588c0b746e5SOllivier Robert  */
589224ba2bdSOllivier Robert 
590c0b746e5SOllivier Robert static int
591c0b746e5SOllivier Robert oncore_start(
592c0b746e5SOllivier Robert 	int unit,
593c0b746e5SOllivier Robert 	struct peer *peer
594c0b746e5SOllivier Robert 	)
595c0b746e5SOllivier Robert {
596ea906c41SOllivier Robert #define STRING_LEN	32
597c0b746e5SOllivier Robert 	register struct instance *instance;
598c0b746e5SOllivier Robert 	struct refclockproc *pp;
5992b15cb3dSCy Schubert 	int fd1, fd2;
6002b15cb3dSCy Schubert 	char device1[STRING_LEN], device2[STRING_LEN];
6012b15cb3dSCy Schubert #ifndef SYS_WINNT
602c0b746e5SOllivier Robert 	struct stat stat1, stat2;
6032b15cb3dSCy Schubert #endif
604c0b746e5SOllivier Robert 
6059c2daa00SOllivier Robert 	/* create instance structure for this unit */
6069c2daa00SOllivier Robert 
6072b15cb3dSCy Schubert 	instance = emalloc(sizeof(*instance));
6082b15cb3dSCy Schubert 	memset(instance, 0, sizeof(*instance));
6099c2daa00SOllivier Robert 
6109c2daa00SOllivier Robert 	/* initialize miscellaneous variables */
611224ba2bdSOllivier Robert 
612c0b746e5SOllivier Robert 	pp = peer->procptr;
613224ba2bdSOllivier Robert 	instance->pp   = pp;
614c0b746e5SOllivier Robert 	instance->unit = unit;
615224ba2bdSOllivier Robert 	instance->peer = peer;
6169c2daa00SOllivier Robert 	instance->assert = 1;
6179c2daa00SOllivier Robert 	instance->once = 1;
618224ba2bdSOllivier Robert 
619c0b746e5SOllivier Robert 	instance->Bj_day = -1;
620224ba2bdSOllivier Robert 	instance->traim = -1;
6219c2daa00SOllivier Robert 	instance->traim_in = -1;
6229c2daa00SOllivier Robert 	instance->chan_in = -1;
6232b15cb3dSCy Schubert 	instance->pps_control = -1;	/* PPS control, M12 only */
6242b15cb3dSCy Schubert 	instance->pps_control_msg_seen = -1;	/* Have seen response to Gc msg */
625224ba2bdSOllivier Robert 	instance->model = ONCORE_UNKNOWN;
626224ba2bdSOllivier Robert 	instance->mode = MODE_UNKNOWN;
627224ba2bdSOllivier Robert 	instance->site_survey = ONCORE_SS_UNKNOWN;
6289c2daa00SOllivier Robert 	instance->Ag = 0xff;		/* Satellite mask angle, unset by user */
6299c2daa00SOllivier Robert 	instance->ant_state = ONCORE_ANTENNA_UNKNOWN;
630224ba2bdSOllivier Robert 
6312b15cb3dSCy Schubert 	peer->flags &= ~FLAG_PPS;	/* PPS not active yet */
632224ba2bdSOllivier Robert 	peer->precision = -26;
633224ba2bdSOllivier Robert 	peer->minpoll = 4;
634224ba2bdSOllivier Robert 	peer->maxpoll = 4;
635224ba2bdSOllivier Robert 	pp->clockdesc = "Motorola Oncore GPS Receiver";
636224ba2bdSOllivier Robert 	memcpy((char *)&pp->refid, "GPS\0", (size_t) 4);
637c0b746e5SOllivier Robert 
6382b15cb3dSCy Schubert 	oncore_log(instance, LOG_NOTICE, "ONCORE DRIVER -- CONFIGURING");
639ea906c41SOllivier Robert 	instance->o_state = ONCORE_NO_IDEA;
6402b15cb3dSCy Schubert 	oncore_log(instance, LOG_NOTICE, "state = ONCORE_NO_IDEA");
641ea906c41SOllivier Robert 
642ea906c41SOllivier Robert 	/* Now open files.
643ea906c41SOllivier Robert 	 * This is a bit complicated, a we dont want to open the same file twice
644ea906c41SOllivier Robert 	 * (its a problem on some OS), and device2 may not exist for the new PPS
645ea906c41SOllivier Robert 	 */
646ea906c41SOllivier Robert 
6472b15cb3dSCy Schubert 	(void)snprintf(device1, sizeof(device1), DEVICE1, unit);
6482b15cb3dSCy Schubert 	(void)snprintf(device2, sizeof(device2), DEVICE2, unit);
649ea906c41SOllivier Robert 
650ea906c41SOllivier Robert 	/* OPEN DEVICES */
651ea906c41SOllivier Robert 	/* opening different devices for fd1 and fd2 presents no problems */
652ea906c41SOllivier Robert 	/* opening the SAME device twice, seems to be OS dependent.
653ea906c41SOllivier Robert 		(a) on Linux (no streams) no problem
654ea906c41SOllivier Robert 		(b) on SunOS (and possibly Solaris, untested), (streams)
655ea906c41SOllivier Robert 			never see the line discipline.
656ea906c41SOllivier Robert 	   Since things ALWAYS work if we only open the device once, we check
657ea906c41SOllivier Robert 	     to see if the two devices are in fact the same, then proceed to
658ea906c41SOllivier Robert 	     do one open or two.
659ea906c41SOllivier Robert 
6602b15cb3dSCy Schubert 	   For use with linuxPPS we assume that the N_TTY file has been opened
6612b15cb3dSCy Schubert 	     and that the line discipline has been changed to N_PPS by another
6622b15cb3dSCy Schubert 	     program (say ppsldisc) so that the two files expected by the oncore
6632b15cb3dSCy Schubert 	     driver can be opened.
6642b15cb3dSCy Schubert 
6652b15cb3dSCy Schubert 	   Note that the linuxPPS N_PPS file is just like a N_TTY, so we can do
6662b15cb3dSCy Schubert 	     the stat below without error even though the file has already had its
6672b15cb3dSCy Schubert 	     line discipline changed by another process.
6682b15cb3dSCy Schubert 
6692b15cb3dSCy Schubert 	   The Windows port of ntpd arranges to return duplicate handles for
6702b15cb3dSCy Schubert 	     multiple opens of the same serial device, and doesn't have inodes
6712b15cb3dSCy Schubert 	     for serial handles, so we just open both on Windows.
6722b15cb3dSCy Schubert 	*/
6732b15cb3dSCy Schubert #ifndef SYS_WINNT
674ea906c41SOllivier Robert 	if (stat(device1, &stat1)) {
6752b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_ERR, "Can't stat fd1 (%s)",
6762b15cb3dSCy Schubert 			     device1);
6772b15cb3dSCy Schubert 		return(0);			/* exit, no file, can't start driver */
678ea906c41SOllivier Robert 	}
679ea906c41SOllivier Robert 
680ea906c41SOllivier Robert 	if (stat(device2, &stat2)) {
6812b15cb3dSCy Schubert 		stat2.st_dev = stat2.st_ino = -2;
6822b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_ERR, "Can't stat fd2 (%s) %d %m",
6832b15cb3dSCy Schubert 			     device2, errno);
6842b15cb3dSCy Schubert 	}
6852b15cb3dSCy Schubert #endif	/* !SYS_WINNT */
6862b15cb3dSCy Schubert 
687a466cc55SCy Schubert 	fd1 = refclock_open(&peer->srcadr, device1, SPEED, LDISC_RAW);
6882b15cb3dSCy Schubert 	if (fd1 <= 0) {
6892b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_ERR, "Can't open fd1 (%s)",
6902b15cb3dSCy Schubert 			     device1);
6912b15cb3dSCy Schubert 		return(0);			/* exit, can't open file, can't start driver */
692ea906c41SOllivier Robert 	}
693ea906c41SOllivier Robert 
6942b15cb3dSCy Schubert 	/* for LINUX the PPS device is the result of a line discipline.
6952b15cb3dSCy Schubert 	   It seems simplest to let an external program create the appropriate
6962b15cb3dSCy Schubert 	   /dev/pps<n> file, and only check (carefully) for its existance here
6972b15cb3dSCy Schubert 	 */
698ea906c41SOllivier Robert 
6992b15cb3dSCy Schubert #ifndef SYS_WINNT
700ea906c41SOllivier Robert 	if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino))	/* same device here */
701ea906c41SOllivier Robert 		fd2 = fd1;
7022b15cb3dSCy Schubert 	else
7032b15cb3dSCy Schubert #endif	/* !SYS_WINNT */
7042b15cb3dSCy Schubert 	{	/* different devices here */
7052b15cb3dSCy Schubert 		if ((fd2=tty_open(device2, O_RDWR, 0777)) < 0) {
7062b15cb3dSCy Schubert 			oncore_log_f(instance, LOG_ERR,
7072b15cb3dSCy Schubert 				     "Can't open fd2 (%s)", device2);
7082b15cb3dSCy Schubert 			return(0);		/* exit, can't open PPS file, can't start driver */
709ea906c41SOllivier Robert 		}
710ea906c41SOllivier Robert 	}
711ea906c41SOllivier Robert 
7122b15cb3dSCy Schubert 	/* open ppsapi source */
713ea906c41SOllivier Robert 
7142b15cb3dSCy Schubert 	if (time_pps_create(fd2, &instance->pps_h) < 0) {
7152b15cb3dSCy Schubert 		oncore_log(instance, LOG_ERR, "exit, PPSAPI not found in kernel");
7162b15cb3dSCy Schubert 		return(0);			/* exit, don't find PPSAPI in kernel */
717ea906c41SOllivier Robert 	}
718ea906c41SOllivier Robert 
719ea906c41SOllivier Robert 	/* continue initialization */
720ea906c41SOllivier Robert 
721ea906c41SOllivier Robert 	instance->ttyfd = fd1;
722ea906c41SOllivier Robert 	instance->ppsfd = fd2;
723ea906c41SOllivier Robert 
7249c2daa00SOllivier Robert 	/* go read any input data in /etc/ntp.oncoreX or /etc/ntp/oncore.X */
725c0b746e5SOllivier Robert 
726c0b746e5SOllivier Robert 	oncore_read_config(instance);
727c0b746e5SOllivier Robert 
7289c2daa00SOllivier Robert 	if (!oncore_ppsapi(instance))
7299c2daa00SOllivier Robert 		return(0);
7309c2daa00SOllivier Robert 
7319c2daa00SOllivier Robert 	pp->io.clock_recv = oncore_receive;
7322b15cb3dSCy Schubert 	pp->io.srcclock = peer;
7339c2daa00SOllivier Robert 	pp->io.datalen = 0;
7349c2daa00SOllivier Robert 	pp->io.fd = fd1;
7359c2daa00SOllivier Robert 	if (!io_addclock(&pp->io)) {
7362b15cb3dSCy Schubert 		oncore_log(instance, LOG_ERR, "can't do io_addclock");
7372b15cb3dSCy Schubert 		close(fd1);
7382b15cb3dSCy Schubert 		pp->io.fd = -1;
7399c2daa00SOllivier Robert 		free(instance);
7409c2daa00SOllivier Robert 		return (0);
7419c2daa00SOllivier Robert 	}
7422b15cb3dSCy Schubert 	pp->unitptr = instance;
7439c2daa00SOllivier Robert 
7449c2daa00SOllivier Robert #ifdef ONCORE_SHMEM_STATUS
7459c2daa00SOllivier Robert 	/*
7469c2daa00SOllivier Robert 	 * Before starting ONCORE, lets setup SHMEM
7479c2daa00SOllivier Robert 	 * This will include merging an old SHMEM into the new one if
7489c2daa00SOllivier Robert 	 * an old one is found.
7499c2daa00SOllivier Robert 	 */
7509c2daa00SOllivier Robert 
7519c2daa00SOllivier Robert 	oncore_init_shmem(instance);
7529c2daa00SOllivier Robert #endif
7539c2daa00SOllivier Robert 
7549c2daa00SOllivier Robert 	/*
7559c2daa00SOllivier Robert 	 * This will return the Model of the Oncore receiver.
7569c2daa00SOllivier Robert 	 * and start the Initialization loop in oncore_msg_Cj.
7579c2daa00SOllivier Robert 	 */
7589c2daa00SOllivier Robert 
7599c2daa00SOllivier Robert 	instance->o_state = ONCORE_CHECK_ID;
7602b15cb3dSCy Schubert 	oncore_log(instance, LOG_NOTICE, "state = ONCORE_CHECK_ID");
7619c2daa00SOllivier Robert 
7629c2daa00SOllivier Robert 	instance->timeout = 4;
7632b15cb3dSCy Schubert 	oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Set Posn Fix mode (not Idle (VP)) */
7642b15cb3dSCy Schubert 	oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
7659c2daa00SOllivier Robert 
7669c2daa00SOllivier Robert 	instance->pollcnt = 2;
7679c2daa00SOllivier Robert 	return (1);
7689c2daa00SOllivier Robert }
7699c2daa00SOllivier Robert 
7709c2daa00SOllivier Robert 
7719c2daa00SOllivier Robert /*
7729c2daa00SOllivier Robert  * oncore_shutdown - shut down the clock
7739c2daa00SOllivier Robert  */
7749c2daa00SOllivier Robert 
7759c2daa00SOllivier Robert static void
7769c2daa00SOllivier Robert oncore_shutdown(
7779c2daa00SOllivier Robert 	int unit,
7789c2daa00SOllivier Robert 	struct peer *peer
7799c2daa00SOllivier Robert 	)
7809c2daa00SOllivier Robert {
7819c2daa00SOllivier Robert 	register struct instance *instance;
7829c2daa00SOllivier Robert 	struct refclockproc *pp;
7839c2daa00SOllivier Robert 
7849c2daa00SOllivier Robert 	pp = peer->procptr;
7852b15cb3dSCy Schubert 	instance = pp->unitptr;
7869c2daa00SOllivier Robert 
7872b15cb3dSCy Schubert 	if (pp->io.fd != -1)
7889c2daa00SOllivier Robert 		io_closeclock(&pp->io);
7899c2daa00SOllivier Robert 
7902b15cb3dSCy Schubert 	if (instance != NULL) {
791ea906c41SOllivier Robert 		time_pps_destroy (instance->pps_h);
792ea906c41SOllivier Robert 
7939c2daa00SOllivier Robert 		close(instance->ttyfd);
794ea906c41SOllivier Robert 
795ea906c41SOllivier Robert 		if ((instance->ppsfd != -1) && (instance->ppsfd != instance->ttyfd))
7969c2daa00SOllivier Robert 			close(instance->ppsfd);
797ea906c41SOllivier Robert 
7989c2daa00SOllivier Robert 		if (instance->shmemfd)
7999c2daa00SOllivier Robert 			close(instance->shmemfd);
800ea906c41SOllivier Robert 
8019c2daa00SOllivier Robert 		free(instance);
8029c2daa00SOllivier Robert 	}
8032b15cb3dSCy Schubert }
8049c2daa00SOllivier Robert 
8059c2daa00SOllivier Robert 
8069c2daa00SOllivier Robert 
8079c2daa00SOllivier Robert /*
8089c2daa00SOllivier Robert  * oncore_poll - called by the transmit procedure
8099c2daa00SOllivier Robert  */
8109c2daa00SOllivier Robert 
8119c2daa00SOllivier Robert static void
8129c2daa00SOllivier Robert oncore_poll(
8139c2daa00SOllivier Robert 	int unit,
8149c2daa00SOllivier Robert 	struct peer *peer
8159c2daa00SOllivier Robert 	)
8169c2daa00SOllivier Robert {
8179c2daa00SOllivier Robert 	struct instance *instance;
8189c2daa00SOllivier Robert 
8192b15cb3dSCy Schubert 	instance = peer->procptr->unitptr;
8209c2daa00SOllivier Robert 	if (instance->timeout) {
8219c2daa00SOllivier Robert 		instance->timeout--;
8229c2daa00SOllivier Robert 		if (instance->timeout == 0) {
8232b15cb3dSCy Schubert 			oncore_log(instance, LOG_ERR,
8242b15cb3dSCy Schubert 			    "Oncore: No response from @@Cj, shutting down driver");
8259c2daa00SOllivier Robert 			oncore_shutdown(unit, peer);
8269c2daa00SOllivier Robert 		} else {
8272b15cb3dSCy Schubert 			oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
8282b15cb3dSCy Schubert 			oncore_log(instance, LOG_WARNING, "Oncore: Resend @@Cj");
8299c2daa00SOllivier Robert 		}
8309c2daa00SOllivier Robert 		return;
8319c2daa00SOllivier Robert 	}
8329c2daa00SOllivier Robert 
8339c2daa00SOllivier Robert 	if (!instance->pollcnt)
8349c2daa00SOllivier Robert 		refclock_report(peer, CEVNT_TIMEOUT);
8359c2daa00SOllivier Robert 	else
8369c2daa00SOllivier Robert 		instance->pollcnt--;
8379c2daa00SOllivier Robert 	peer->procptr->polls++;
8389c2daa00SOllivier Robert 	instance->polled = 1;
8399c2daa00SOllivier Robert }
8409c2daa00SOllivier Robert 
8419c2daa00SOllivier Robert 
8429c2daa00SOllivier Robert 
8439c2daa00SOllivier Robert /*
8449c2daa00SOllivier Robert  * Initialize PPSAPI
8459c2daa00SOllivier Robert  */
8469c2daa00SOllivier Robert 
8479c2daa00SOllivier Robert static int
8489c2daa00SOllivier Robert oncore_ppsapi(
8499c2daa00SOllivier Robert 	struct instance *instance
8509c2daa00SOllivier Robert 	)
8519c2daa00SOllivier Robert {
852ea906c41SOllivier Robert 	int cap, mode, mode1;
8532b15cb3dSCy Schubert 	const char *cp;
8549c2daa00SOllivier Robert 
855ea906c41SOllivier Robert 	if (time_pps_getcap(instance->pps_h, &cap) < 0) {
8562b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_ERR, "time_pps_getcap failed: %m");
857a151a66cSOllivier Robert 		return (0);
858a151a66cSOllivier Robert 	}
859a151a66cSOllivier Robert 
860a151a66cSOllivier Robert 	if (time_pps_getparams(instance->pps_h, &instance->pps_p) < 0) {
8612b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_ERR, "time_pps_getparams failed: %m");
862a151a66cSOllivier Robert 		return (0);
863a151a66cSOllivier Robert 	}
864a151a66cSOllivier Robert 
865a151a66cSOllivier Robert 	/* nb. only turn things on, if someone else has turned something
866a151a66cSOllivier Robert 	 *	on before we get here, leave it alone!
867a151a66cSOllivier Robert 	 */
868a151a66cSOllivier Robert 
869ea906c41SOllivier Robert 	if (instance->assert) {
8702b15cb3dSCy Schubert 		cp = "Assert";
871ea906c41SOllivier Robert 		mode = PPS_CAPTUREASSERT;
872ea906c41SOllivier Robert 		mode1 = PPS_OFFSETASSERT;
873c0b746e5SOllivier Robert 	} else {
8742b15cb3dSCy Schubert 		cp = "Clear";
875ea906c41SOllivier Robert 		mode = PPS_CAPTURECLEAR;
876ea906c41SOllivier Robert 		mode1 = PPS_OFFSETCLEAR;
877c0b746e5SOllivier Robert 	}
8782b15cb3dSCy Schubert 	oncore_log_f(instance, LOG_INFO, "Initializing timing to %s.",
8792b15cb3dSCy Schubert 		     cp);
880ea906c41SOllivier Robert 
881ea906c41SOllivier Robert 	if (!(mode & cap)) {
8822b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_ERR,
8832b15cb3dSCy Schubert 			     "Can't set timing to %s, exiting...", cp);
884ea906c41SOllivier Robert 		return(0);
885ea906c41SOllivier Robert 	}
886ea906c41SOllivier Robert 
887ea906c41SOllivier Robert 	if (!(mode1 & cap)) {
8882b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_NOTICE,
8892b15cb3dSCy Schubert 			     "Can't set %s, this will increase jitter.",
8902b15cb3dSCy Schubert 			     cp);
891ea906c41SOllivier Robert 		mode1 = 0;
892ea906c41SOllivier Robert 	}
893ea906c41SOllivier Robert 
894ea906c41SOllivier Robert 	/* only set what is legal */
895ea906c41SOllivier Robert 
896ea906c41SOllivier Robert 	instance->pps_p.mode = (mode | mode1 | PPS_TSFMT_TSPEC) & cap;
897a151a66cSOllivier Robert 
898c0b746e5SOllivier Robert 	if (time_pps_setparams(instance->pps_h, &instance->pps_p) < 0) {
8992b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_ERR, "ONCORE: time_pps_setparams fails %m");
9002b15cb3dSCy Schubert 		return(0);		/* exit, can't do time_pps_setparans on PPS file */
901c0b746e5SOllivier Robert 	}
902a151a66cSOllivier Robert 
9039c2daa00SOllivier Robert 	/* If HARDPPS is on, we tell kernel */
904a151a66cSOllivier Robert 
9059c2daa00SOllivier Robert 	if (instance->hardpps) {
906a151a66cSOllivier Robert 		int	i;
907a151a66cSOllivier Robert 
9082b15cb3dSCy Schubert 		oncore_log(instance, LOG_INFO, "HARDPPS Set.");
909ea906c41SOllivier Robert 
910a151a66cSOllivier Robert 		if (instance->assert)
911a151a66cSOllivier Robert 			i = PPS_CAPTUREASSERT;
912a151a66cSOllivier Robert 		else
913a151a66cSOllivier Robert 			i = PPS_CAPTURECLEAR;
914a151a66cSOllivier Robert 
915ea906c41SOllivier Robert 		/* we know that 'i' is legal from above */
916ea906c41SOllivier Robert 
917a151a66cSOllivier Robert 		if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i,
918c0b746e5SOllivier Robert 		    PPS_TSFMT_TSPEC) < 0) {
9192b15cb3dSCy Schubert 			oncore_log_f(instance, LOG_ERR, "time_pps_kcbind failed: %m");
9202b15cb3dSCy Schubert 			oncore_log(instance, LOG_ERR, "HARDPPS failed, abort...");
921a151a66cSOllivier Robert 			return (0);
922a151a66cSOllivier Robert 		}
9232b15cb3dSCy Schubert 
9242b15cb3dSCy Schubert 		hardpps_enable = 1;
925a151a66cSOllivier Robert 	}
9269c2daa00SOllivier Robert 	return(1);
927c0b746e5SOllivier Robert }
928a151a66cSOllivier Robert 
9299c2daa00SOllivier Robert 
9309c2daa00SOllivier Robert 
9319c2daa00SOllivier Robert #ifdef ONCORE_SHMEM_STATUS
9329c2daa00SOllivier Robert static void
9339c2daa00SOllivier Robert oncore_init_shmem(
9349c2daa00SOllivier Robert 	struct instance *instance
9359c2daa00SOllivier Robert 	)
9369c2daa00SOllivier Robert {
9372b15cb3dSCy Schubert 	int l, fd;
938ea906c41SOllivier Robert 	u_char *cp, *cp1, *buf, *shmem_old;
9399c2daa00SOllivier Robert 	struct msg_desc *mp;
9409c2daa00SOllivier Robert 	struct stat sbuf;
9412b15cb3dSCy Schubert 	size_t i, n, n1, shmem_length, shmem_old_size;
942c0b746e5SOllivier Robert 
943c0b746e5SOllivier Robert 	/*
9449c2daa00SOllivier Robert 	* The first thing we do is see if there is an instance->shmem_fname file (still)
9459c2daa00SOllivier Robert 	* out there from a previous run.  If so, we copy it in and use it to initialize
9469c2daa00SOllivier Robert 	* shmem (so we won't lose our almanac if we need it).
947c0b746e5SOllivier Robert 	*/
948c0b746e5SOllivier Robert 
9499c2daa00SOllivier Robert 	shmem_old = 0;
950ea906c41SOllivier Robert 	shmem_old_size = 0;
9519c2daa00SOllivier Robert 	if ((fd = open(instance->shmem_fname, O_RDONLY)) < 0)
9522b15cb3dSCy Schubert 		oncore_log(instance, LOG_WARNING, "ONCORE: Can't open SHMEM file");
9539c2daa00SOllivier Robert 	else {
9549c2daa00SOllivier Robert 		fstat(fd, &sbuf);
9559c2daa00SOllivier Robert 		shmem_old_size = sbuf.st_size;
956ea906c41SOllivier Robert 		if (shmem_old_size != 0) {
9572b15cb3dSCy Schubert 			shmem_old = emalloc((unsigned) sbuf.st_size);
958a466cc55SCy Schubert 			if (read(fd, shmem_old, shmem_old_size) != shmem_old_size)
959a466cc55SCy Schubert 				oncore_log(instance, LOG_WARNING,
960a466cc55SCy Schubert 					   "ONCORE: truncated/failed read of SHMEM file");
961ea906c41SOllivier Robert 		}
9629c2daa00SOllivier Robert 		close(fd);
9639c2daa00SOllivier Robert 	}
9649c2daa00SOllivier Robert 
9659c2daa00SOllivier Robert 	/* OK, we now create the NEW SHMEM. */
9669c2daa00SOllivier Robert 
9679c2daa00SOllivier Robert 	if ((instance->shmemfd = open(instance->shmem_fname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) {
9682b15cb3dSCy Schubert 		oncore_log(instance, LOG_WARNING, "ONCORE: Can't open shmem");
969ea906c41SOllivier Robert 		if (shmem_old)
970ea906c41SOllivier Robert 			free(shmem_old);
971ea906c41SOllivier Robert 
9729c2daa00SOllivier Robert 		return;
9739c2daa00SOllivier Robert 	}
9749c2daa00SOllivier Robert 
9759c2daa00SOllivier Robert 	/* see how big it needs to be */
9769c2daa00SOllivier Robert 
9779c2daa00SOllivier Robert 	n = 1;
9789c2daa00SOllivier Robert 	for (mp=oncore_messages; mp->flag[0]; mp++) {
9799c2daa00SOllivier Robert 		mp->shmem = n;
9809c2daa00SOllivier Robert 		/* Allocate space for multiplexed almanac, and 0D/2D/3D @@Ea records */
9819c2daa00SOllivier Robert 		if (!strcmp(mp->flag, "Cb")) {
9829c2daa00SOllivier Robert 			instance->shmem_Cb = n;
9839c2daa00SOllivier Robert 			n += (mp->len + 3) * 34;
9849c2daa00SOllivier Robert 		}
9859c2daa00SOllivier Robert 		if (!strcmp(mp->flag, "Ba")) {
9869c2daa00SOllivier Robert 			instance->shmem_Ba = n;
9879c2daa00SOllivier Robert 			n += (mp->len + 3) * 3;
9889c2daa00SOllivier Robert 		}
9899c2daa00SOllivier Robert 		if (!strcmp(mp->flag, "Ea")) {
9909c2daa00SOllivier Robert 			instance->shmem_Ea = n;
9919c2daa00SOllivier Robert 			n += (mp->len + 3) * 3;
9929c2daa00SOllivier Robert 		}
9939c2daa00SOllivier Robert 		if (!strcmp(mp->flag, "Ha")) {
9949c2daa00SOllivier Robert 			instance->shmem_Ha = n;
9959c2daa00SOllivier Robert 			n += (mp->len + 3) * 3;
9969c2daa00SOllivier Robert 		}
9979c2daa00SOllivier Robert 		n += (mp->len + 3);
9989c2daa00SOllivier Robert 	}
9999c2daa00SOllivier Robert 	shmem_length = n + 2;
10009c2daa00SOllivier Robert 
10012b15cb3dSCy Schubert 	buf = emalloc(shmem_length);
10029c2daa00SOllivier Robert 	memset(buf, 0, shmem_length);
10039c2daa00SOllivier Robert 
10049c2daa00SOllivier Robert 	/* next build the new SHMEM buffer in memory */
10059c2daa00SOllivier Robert 
10069c2daa00SOllivier Robert 	for (mp=oncore_messages; mp->flag[0]; mp++) {
10079c2daa00SOllivier Robert 		l = mp->shmem;
10089c2daa00SOllivier Robert 		buf[l + 0] = mp->len >> 8;
10099c2daa00SOllivier Robert 		buf[l + 1] = mp->len & 0xff;
10109c2daa00SOllivier Robert 		buf[l + 2] = 0;
10119c2daa00SOllivier Robert 		buf[l + 3] = '@';
10129c2daa00SOllivier Robert 		buf[l + 4] = '@';
10139c2daa00SOllivier Robert 		buf[l + 5] = mp->flag[0];
10149c2daa00SOllivier Robert 		buf[l + 6] = mp->flag[1];
10159c2daa00SOllivier Robert 		if (!strcmp(mp->flag, "Cb") || !strcmp(mp->flag, "Ba") || !strcmp(mp->flag, "Ea") || !strcmp(mp->flag, "Ha")) {
10169c2daa00SOllivier Robert 			if (!strcmp(mp->flag, "Cb"))
10179c2daa00SOllivier Robert 				n = 35;
10189c2daa00SOllivier Robert 			else
10199c2daa00SOllivier Robert 				n = 4;
10209c2daa00SOllivier Robert 			for (i=1; i<n; i++) {
10219c2daa00SOllivier Robert 				buf[l + i * (mp->len+3) + 0] = mp->len >> 8;
10229c2daa00SOllivier Robert 				buf[l + i * (mp->len+3) + 1] = mp->len & 0xff;
10239c2daa00SOllivier Robert 				buf[l + i * (mp->len+3) + 2] = 0;
10249c2daa00SOllivier Robert 				buf[l + i * (mp->len+3) + 3] = '@';
10259c2daa00SOllivier Robert 				buf[l + i * (mp->len+3) + 4] = '@';
10269c2daa00SOllivier Robert 				buf[l + i * (mp->len+3) + 5] = mp->flag[0];
10279c2daa00SOllivier Robert 				buf[l + i * (mp->len+3) + 6] = mp->flag[1];
10289c2daa00SOllivier Robert 			}
10299c2daa00SOllivier Robert 		}
10309c2daa00SOllivier Robert 	}
10319c2daa00SOllivier Robert 
10329c2daa00SOllivier Robert 	/* we now walk thru the two buffers (shmem_old and buf, soon to become shmem)
1033ea906c41SOllivier Robert 	 * copying the data in shmem_old to buf.
1034ea906c41SOllivier Robert 	 * When we are done we write it out and free both buffers.
1035ea906c41SOllivier Robert 	 * If the structure sizes dont agree, I will not copy.
1036ea906c41SOllivier Robert 	 * This could be due to an addition/deletion or a problem with the disk file.
10379c2daa00SOllivier Robert 	 */
10389c2daa00SOllivier Robert 
10399c2daa00SOllivier Robert 	if (shmem_old) {
1040ea906c41SOllivier Robert 		if (shmem_old_size == shmem_length) {
10419c2daa00SOllivier Robert 			for (cp=buf+4, cp1=shmem_old+4; (n = 256*(*(cp-3)) + *(cp-2));	cp+=(n+3), cp1+=(n+3)) {
10429c2daa00SOllivier Robert 				n1 = 256*(*(cp1-3)) + *(cp1-2);
1043ea906c41SOllivier Robert 				if (n == 0 || n1 != n || strncmp((char *) cp, (char *) cp1, 4))
10449c2daa00SOllivier Robert 					break;
10459c2daa00SOllivier Robert 
10469c2daa00SOllivier Robert 				memcpy(cp, cp1, (size_t) n);
10479c2daa00SOllivier Robert 			}
1048ea906c41SOllivier Robert 		}
10499c2daa00SOllivier Robert 		free(shmem_old);
10509c2daa00SOllivier Robert 	}
10519c2daa00SOllivier Robert 
10529c2daa00SOllivier Robert 	i = write(instance->shmemfd, buf, shmem_length);
10539c2daa00SOllivier Robert 	free(buf);
10549c2daa00SOllivier Robert 
10559c2daa00SOllivier Robert 	if (i != shmem_length) {
10562b15cb3dSCy Schubert 		oncore_log(instance, LOG_ERR, "ONCORE: error writing shmem");
10579c2daa00SOllivier Robert 		close(instance->shmemfd);
10589c2daa00SOllivier Robert 		return;
10599c2daa00SOllivier Robert 	}
10609c2daa00SOllivier Robert 
10619c2daa00SOllivier Robert 	instance->shmem = (u_char *) mmap(0, shmem_length,
10629c2daa00SOllivier Robert 		PROT_READ | PROT_WRITE,
10639c2daa00SOllivier Robert #ifdef MAP_HASSEMAPHORE
10649c2daa00SOllivier Robert 		MAP_HASSEMAPHORE |
10659c2daa00SOllivier Robert #endif
10669c2daa00SOllivier Robert 		MAP_SHARED, instance->shmemfd, (off_t)0);
10679c2daa00SOllivier Robert 
10689c2daa00SOllivier Robert 	if (instance->shmem == (u_char *)MAP_FAILED) {
10699c2daa00SOllivier Robert 		instance->shmem = 0;
10709c2daa00SOllivier Robert 		close(instance->shmemfd);
10719c2daa00SOllivier Robert 		return;
10729c2daa00SOllivier Robert 	}
10739c2daa00SOllivier Robert 
10742b15cb3dSCy Schubert 	oncore_log_f(instance, LOG_NOTICE,
10752b15cb3dSCy Schubert 		     "SHMEM (size = %ld) is CONFIGURED and available as %s",
1076ea906c41SOllivier Robert 		     (u_long) shmem_length, instance->shmem_fname);
10779c2daa00SOllivier Robert }
10789c2daa00SOllivier Robert #endif /* ONCORE_SHMEM_STATUS */
10799c2daa00SOllivier Robert 
1080a151a66cSOllivier Robert 
1081a151a66cSOllivier Robert 
1082c0b746e5SOllivier Robert /*
1083c0b746e5SOllivier Robert  * Read Input file if it exists.
1084c0b746e5SOllivier Robert  */
1085224ba2bdSOllivier Robert 
1086c0b746e5SOllivier Robert static void
1087c0b746e5SOllivier Robert oncore_read_config(
1088c0b746e5SOllivier Robert 	struct instance *instance
1089c0b746e5SOllivier Robert 	)
1090c0b746e5SOllivier Robert {
1091c0b746e5SOllivier Robert /*
1092224ba2bdSOllivier Robert  * First we try to open the configuration file
10932b15cb3dSCy Schubert  *    /etc/ntp.oncore.N
1094224ba2bdSOllivier Robert  * where N is the unit number viz 127.127.30.N.
1095224ba2bdSOllivier Robert  * If we don't find it we try
10962b15cb3dSCy Schubert  *    /etc/ntp.oncoreN
1097224ba2bdSOllivier Robert  * and then
1098224ba2bdSOllivier Robert  *    /etc/ntp.oncore
1099c0b746e5SOllivier Robert  *
1100224ba2bdSOllivier Robert  * If we don't find any then we don't have the cable delay or PPS offset
1101c0b746e5SOllivier Robert  * and we choose MODE (4) below.
1102c0b746e5SOllivier Robert  *
1103c0b746e5SOllivier Robert  * Five Choices for MODE
1104c0b746e5SOllivier Robert  *    (0) ONCORE is preinitialized, don't do anything to change it.
1105c0b746e5SOllivier Robert  *	    nb, DON'T set 0D mode, DON'T set Delay, position...
1106c0b746e5SOllivier Robert  *    (1) NO RESET, Read Position, delays from data file, lock it in, go to 0D mode.
1107c0b746e5SOllivier Robert  *    (2) NO RESET, Read Delays from data file, do SITE SURVEY to get position,
1108c0b746e5SOllivier Robert  *		    lock this in, go to 0D mode.
1109c0b746e5SOllivier Robert  *    (3) HARD RESET, Read Position, delays from data file, lock it in, go to 0D mode.
1110c0b746e5SOllivier Robert  *    (4) HARD RESET, Read Delays from data file, do SITE SURVEY to get position,
1111c0b746e5SOllivier Robert  *		    lock this in, go to 0D mode.
1112c0b746e5SOllivier Robert  *     NB. If a POSITION is specified in the config file with mode=(2,4) [SITE SURVEY]
1113c0b746e5SOllivier Robert  *	   then this position is set as the INITIAL position of the ONCORE.
1114c0b746e5SOllivier Robert  *	   This can reduce the time to first fix.
1115c0b746e5SOllivier Robert  * -------------------------------------------------------------------------------
1116c0b746e5SOllivier Robert  * Note that an Oncore UT without a battery backup retains NO information if it is
1117c0b746e5SOllivier Robert  *   power cycled, with a Battery Backup it remembers the almanac, etc.
1118c0b746e5SOllivier Robert  * For an Oncore VP, there is an eeprom that will contain this data, along with the
1119c0b746e5SOllivier Robert  *   option of Battery Backup.
1120c0b746e5SOllivier Robert  * So a UT without Battery Backup is equivalent to doing a HARD RESET on each
1121c0b746e5SOllivier Robert  *   power cycle, since there is nowhere to store the data.
1122c0b746e5SOllivier Robert  * -------------------------------------------------------------------------------
1123c0b746e5SOllivier Robert  *
1124c0b746e5SOllivier Robert  * If we open one or the other of the files, we read it looking for
11259c2daa00SOllivier Robert  *   MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET, ASSERT, CLEAR, HARDPPS,
11269c2daa00SOllivier Robert  *   STATUS, POSN3D, POSN2D, CHAN, TRAIM
1127c0b746e5SOllivier Robert  * then initialize using method MODE.  For Mode = (1,3) all of (LAT, LON, HT) must
1128c0b746e5SOllivier Robert  *   be present or mode reverts to (2,4).
1129c0b746e5SOllivier Robert  *
1130c0b746e5SOllivier Robert  * Read input file.
1131c0b746e5SOllivier Robert  *
1132c0b746e5SOllivier Robert  *	# is comment to end of line
1133c0b746e5SOllivier Robert  *	= allowed between 1st and 2nd fields.
1134c0b746e5SOllivier Robert  *
1135c0b746e5SOllivier Robert  *	Expect to see one line with 'MODE' as first field, followed by an integer
1136c0b746e5SOllivier Robert  *	   in the range 0-4 (default = 4).
1137c0b746e5SOllivier Robert  *
1138c0b746e5SOllivier Robert  *	Expect to see two lines with 'LONG', 'LAT' followed by 1-3 fields.
1139c0b746e5SOllivier Robert  *	All numbers are floating point.
1140c0b746e5SOllivier Robert  *		DDD.ddd
1141c0b746e5SOllivier Robert  *		DDD  MMM.mmm
1142c0b746e5SOllivier Robert  *		DDD  MMM  SSS.sss
1143c0b746e5SOllivier Robert  *
1144224ba2bdSOllivier Robert  *	Expect to see one line with 'HT' as first field,
1145224ba2bdSOllivier Robert  *	   followed by 1-2 fields.  First is a number, the second is 'FT' or 'M'
1146224ba2bdSOllivier Robert  *	   for feet or meters.	HT is the height above the GPS ellipsoid.
11479c2daa00SOllivier Robert  *	   If the receiver reports height in both GPS and MSL, then we will report
1148224ba2bdSOllivier Robert  *	   the difference GPS-MSL on the clockstats file.
1149c0b746e5SOllivier Robert  *
1150224ba2bdSOllivier Robert  *	There is an optional line, starting with DELAY, followed
1151c0b746e5SOllivier Robert  *	   by 1 or two fields.	The first is a number (a time) the second is
1152c0b746e5SOllivier Robert  *	   'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
1153c0b746e5SOllivier Robert  *	    DELAY  is cable delay, typically a few tens of ns.
1154224ba2bdSOllivier Robert  *
1155224ba2bdSOllivier Robert  *	There is an optional line, starting with OFFSET, followed
1156224ba2bdSOllivier Robert  *	   by 1 or two fields.	The first is a number (a time) the second is
1157224ba2bdSOllivier Robert  *	   'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
1158c0b746e5SOllivier Robert  *	   OFFSET is the offset of the PPS pulse from 0. (only fully implemented
1159c0b746e5SOllivier Robert  *		with the PPSAPI, we need to be able to tell the Kernel about this
1160c0b746e5SOllivier Robert  *		offset if the Kernel PLL is in use, but can only do this presently
1161c0b746e5SOllivier Robert  *		when using the PPSAPI interface.  If not using the Kernel PLL,
1162c0b746e5SOllivier Robert  *		then there is no problem.
1163c0b746e5SOllivier Robert  *
1164224ba2bdSOllivier Robert  *	There is an optional line, with either ASSERT or CLEAR on it, which
1165c0b746e5SOllivier Robert  *	   determine which transition of the PPS signal is used for timing by the
1166c0b746e5SOllivier Robert  *	   PPSAPI.  If neither is present, then ASSERT is assumed.
11679c2daa00SOllivier Robert  *	   ASSERT/CLEAR can also be set with FLAG2 of the ntp.conf input.
11689c2daa00SOllivier Robert  *	   For Flag2, ASSERT=0, and hence is default.
1169c0b746e5SOllivier Robert  *
11709c2daa00SOllivier Robert  *	There is an optional line, with HARDPPS on it.	Including this line causes
11719c2daa00SOllivier Robert  *	     the PPS signal to control the kernel PLL.
11729c2daa00SOllivier Robert  *	   HARDPPS can also be set with FLAG3 of the ntp.conf input.
11739c2daa00SOllivier Robert  *	   For Flag3, 0 is disabled, and the default.
11749c2daa00SOllivier Robert  *
11759c2daa00SOllivier Robert  *	There are three options that have to do with using the shared memory option.
11769c2daa00SOllivier Robert  *	   First, to enable the option there must be a SHMEM line with a file name.
1177224ba2bdSOllivier Robert  *	   The file name is the file associated with the shared memory.
1178224ba2bdSOllivier Robert  *
11799c2daa00SOllivier Robert  *	In shared memory, there is one 'record' for each returned variable.
11809c2daa00SOllivier Robert  *	For the @@Ea data there are three 'records' containing position data.
11819c2daa00SOllivier Robert  *	   There will always be data in the record corresponding to the '0D' @@Ea record,
11829c2daa00SOllivier Robert  *	   and the user has a choice of filling the '3D' record by specifying POSN3D,
11839c2daa00SOllivier Robert  *	   or the '2D' record by specifying POSN2D.  In either case the '2D' or '3D'
11849c2daa00SOllivier Robert  *	   record is filled once every 15s.
1185224ba2bdSOllivier Robert  *
1186224ba2bdSOllivier Robert  *	Two additional variables that can be set are CHAN and TRAIM.  These should be
1187224ba2bdSOllivier Robert  *	   set correctly by the code examining the @@Cj record, but we bring them out here
11889c2daa00SOllivier Robert  *	   to allow the user to override either the # of channels, or the existence of TRAIM.
1189224ba2bdSOllivier Robert  *	   CHAN expects to be followed by in integer: 6, 8, or 12. TRAIM expects to be
1190224ba2bdSOllivier Robert  *	   followed by YES or NO.
1191224ba2bdSOllivier Robert  *
11929c2daa00SOllivier Robert  *	There is an optional line with MASK on it followed by one integer field in the
11939c2daa00SOllivier Robert  *	   range 0 to 89. This sets the satellite mask angle and will determine the minimum
11949c2daa00SOllivier Robert  *	   elevation angle for satellites to be tracked by the receiver. The default value
11959c2daa00SOllivier Robert  *	   is 10 deg for the VP and 0 deg for all other receivers.
11969c2daa00SOllivier Robert  *
11972b15cb3dSCy Schubert  *	There is an optional line with PPSCONTROL on it (only valid for M12 or M12+T
11982b15cb3dSCy Schubert  *	   receivers, the option is read, but ignored for all others)
11992b15cb3dSCy Schubert  *	   and it is followed by:
12002b15cb3dSCy Schubert  *		ON	   Turn PPS on.  This is the default and the default for other
12012b15cb3dSCy Schubert  *			       oncore receivers.  The PPS is on even if not tracking
12022b15cb3dSCy Schubert  *			       any satellites.
12032b15cb3dSCy Schubert  *		SATELLITE  Turns PPS on if tracking at least 1 satellite, else off.
12042b15cb3dSCy Schubert  *		TRAIM	   Turns PPS on or off controlled by TRAIM.
12052b15cb3dSCy Schubert  *	  The OFF option is NOT implemented, since the Oncore driver will not work
12062b15cb3dSCy Schubert  *	     without the PPS signal.
12072b15cb3dSCy Schubert  *
1208c0b746e5SOllivier Robert  * So acceptable input would be
1209c0b746e5SOllivier Robert  *	# these are my coordinates (RWC)
1210c0b746e5SOllivier Robert  *	LON  -106 34.610
1211c0b746e5SOllivier Robert  *	LAT    35 08.999
1212c0b746e5SOllivier Robert  *	HT	1589	# could equally well say HT 5215 FT
1213c0b746e5SOllivier Robert  *	DELAY  60 ns
1214c0b746e5SOllivier Robert  */
1215c0b746e5SOllivier Robert 
1216c0b746e5SOllivier Robert 	FILE	*fd;
12172b15cb3dSCy Schubert 	char	*cc, *ca, line[100], units[2], device[64];
12182b15cb3dSCy Schubert 	const char	*dirs[] = { "/etc/ntp", "/etc", 0 };
12192b15cb3dSCy Schubert 	const char *cp, **cpp;
12209c2daa00SOllivier Robert 	int	i, sign, lat_flg, long_flg, ht_flg, mode, mask;
1221c0b746e5SOllivier Robert 	double	f1, f2, f3;
1222c0b746e5SOllivier Robert 
1223ea906c41SOllivier Robert 	fd = NULL;	/* just to shutup gcc complaint */
1224ea906c41SOllivier Robert 	for (cpp=dirs; *cpp; cpp++) {
1225ea906c41SOllivier Robert 		cp = *cpp;
12262b15cb3dSCy Schubert 		snprintf(device, sizeof(device), "%s/ntp.oncore.%d",
12272b15cb3dSCy Schubert 			 cp, instance->unit);  /* try "ntp.oncore.0 */
1228ea906c41SOllivier Robert 		if ((fd=fopen(device, "r")))
1229ea906c41SOllivier Robert 			break;
12302b15cb3dSCy Schubert 		snprintf(device, sizeof(device), "%s/ntp.oncore%d",
12312b15cb3dSCy Schubert 			 cp, instance->unit);  /* try "ntp.oncore0" */
1232ea906c41SOllivier Robert 		if ((fd=fopen(device, "r")))
1233ea906c41SOllivier Robert 			break;
12342b15cb3dSCy Schubert 		snprintf(device, sizeof(device), "%s/ntp.oncore", cp);
12352b15cb3dSCy Schubert 		if ((fd=fopen(device, "r")))   /* last try "ntp.oncore" */
1236ea906c41SOllivier Robert 			break;
1237ea906c41SOllivier Robert 	}
1238ea906c41SOllivier Robert 
1239ea906c41SOllivier Robert 	if (!fd) {	/* no inputfile, default to the works ... */
1240c0b746e5SOllivier Robert 		instance->init_type = 4;
1241c0b746e5SOllivier Robert 		return;
1242c0b746e5SOllivier Robert 	}
1243c0b746e5SOllivier Robert 
12449c2daa00SOllivier Robert 	mode = mask = 0;
1245c0b746e5SOllivier Robert 	lat_flg = long_flg = ht_flg = 0;
1246c0b746e5SOllivier Robert 	while (fgets(line, 100, fd)) {
12472b15cb3dSCy Schubert 		char *cpw;
1248a151a66cSOllivier Robert 
1249a151a66cSOllivier Robert 		/* Remove comments */
12502b15cb3dSCy Schubert 		if ((cpw = strchr(line, '#')))
12512b15cb3dSCy Schubert 			*cpw = '\0';
1252a151a66cSOllivier Robert 
1253a151a66cSOllivier Robert 		/* Remove trailing space */
1254a151a66cSOllivier Robert 		for (i = strlen(line);
12552b15cb3dSCy Schubert 		     i > 0 && isascii((unsigned char)line[i - 1]) && isspace((unsigned char)line[i - 1]);
1256a151a66cSOllivier Robert 			)
1257a151a66cSOllivier Robert 			line[--i] = '\0';
1258a151a66cSOllivier Robert 
1259a151a66cSOllivier Robert 		/* Remove leading space */
12602b15cb3dSCy Schubert 		for (cc = line; *cc && isascii((unsigned char)*cc) && isspace((unsigned char)*cc); cc++)
1261a151a66cSOllivier Robert 			continue;
1262a151a66cSOllivier Robert 
1263a151a66cSOllivier Robert 		/* Stop if nothing left */
1264a151a66cSOllivier Robert 		if (!*cc)
1265a151a66cSOllivier Robert 			continue;
1266a151a66cSOllivier Robert 
1267224ba2bdSOllivier Robert 		/* Uppercase the command and find the arg */
1268a151a66cSOllivier Robert 		for (ca = cc; *ca; ca++) {
12692b15cb3dSCy Schubert 			if (isascii((unsigned char)*ca)) {
12702b15cb3dSCy Schubert 				if (islower((unsigned char)*ca)) {
12712b15cb3dSCy Schubert 					*ca = toupper((unsigned char)*ca);
12722b15cb3dSCy Schubert 				} else if (isspace((unsigned char)*ca) || (*ca == '='))
1273a151a66cSOllivier Robert 					break;
1274a151a66cSOllivier Robert 			}
1275a151a66cSOllivier Robert 		}
1276a151a66cSOllivier Robert 
1277224ba2bdSOllivier Robert 		/* Remove space (and possible =) leading the arg */
12782b15cb3dSCy Schubert 		for (; *ca && isascii((unsigned char)*ca) && (isspace((unsigned char)*ca) || (*ca == '=')); ca++)
1279a151a66cSOllivier Robert 			continue;
1280a151a66cSOllivier Robert 
1281224ba2bdSOllivier Robert 		if (!strncmp(cc, "STATUS", (size_t) 6) || !strncmp(cc, "SHMEM", (size_t) 5)) {
12822b15cb3dSCy Schubert 			instance->shmem_fname = estrdup(ca);
1283a151a66cSOllivier Robert 			continue;
1284a151a66cSOllivier Robert 		}
1285a151a66cSOllivier Robert 
1286a151a66cSOllivier Robert 		/* Uppercase argument as well */
12872b15cb3dSCy Schubert 		for (cpw = ca; *cpw; cpw++)
12882b15cb3dSCy Schubert 			if (isascii((unsigned char)*cpw) && islower((unsigned char)*cpw))
12892b15cb3dSCy Schubert 				*cpw = toupper((unsigned char)*cpw);
1290a151a66cSOllivier Robert 
1291224ba2bdSOllivier Robert 		if (!strncmp(cc, "LAT", (size_t) 3)) {
1292c0b746e5SOllivier Robert 			f1 = f2 = f3 = 0;
1293a151a66cSOllivier Robert 			sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
1294c0b746e5SOllivier Robert 			sign = 1;
1295c0b746e5SOllivier Robert 			if (f1 < 0) {
1296c0b746e5SOllivier Robert 				f1 = -f1;
1297c0b746e5SOllivier Robert 				sign = -1;
1298c0b746e5SOllivier Robert 			}
1299c0b746e5SOllivier Robert 			instance->ss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
1300c0b746e5SOllivier Robert 			lat_flg++;
1301224ba2bdSOllivier Robert 		} else if (!strncmp(cc, "LON", (size_t) 3)) {
1302c0b746e5SOllivier Robert 			f1 = f2 = f3 = 0;
1303a151a66cSOllivier Robert 			sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
1304c0b746e5SOllivier Robert 			sign = 1;
1305c0b746e5SOllivier Robert 			if (f1 < 0) {
1306c0b746e5SOllivier Robert 				f1 = -f1;
1307c0b746e5SOllivier Robert 				sign = -1;
1308c0b746e5SOllivier Robert 			}
1309c0b746e5SOllivier Robert 			instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
1310c0b746e5SOllivier Robert 			long_flg++;
1311224ba2bdSOllivier Robert 		} else if (!strncmp(cc, "HT", (size_t) 2)) {
1312c0b746e5SOllivier Robert 			f1 = 0;
1313c0b746e5SOllivier Robert 			units[0] = '\0';
1314a151a66cSOllivier Robert 			sscanf(ca, "%lf %1s", &f1, units);
1315c0b746e5SOllivier Robert 			if (units[0] == 'F')
1316c0b746e5SOllivier Robert 				f1 = 0.3048 * f1;
1317c0b746e5SOllivier Robert 			instance->ss_ht = 100 * f1;    /* cm */
1318c0b746e5SOllivier Robert 			ht_flg++;
1319224ba2bdSOllivier Robert 		} else if (!strncmp(cc, "DELAY", (size_t) 5)) {
1320c0b746e5SOllivier Robert 			f1 = 0;
1321c0b746e5SOllivier Robert 			units[0] = '\0';
1322a151a66cSOllivier Robert 			sscanf(ca, "%lf %1s", &f1, units);
1323c0b746e5SOllivier Robert 			if (units[0] == 'N')
1324c0b746e5SOllivier Robert 				;
1325c0b746e5SOllivier Robert 			else if (units[0] == 'U')
1326c0b746e5SOllivier Robert 				f1 = 1000 * f1;
1327c0b746e5SOllivier Robert 			else if (units[0] == 'M')
1328c0b746e5SOllivier Robert 				f1 = 1000000 * f1;
1329c0b746e5SOllivier Robert 			else
1330c0b746e5SOllivier Robert 				f1 = 1000000000 * f1;
1331c0b746e5SOllivier Robert 			if (f1 < 0 || f1 > 1.e9)
1332c0b746e5SOllivier Robert 				f1 = 0;
13332b15cb3dSCy Schubert 			if (f1 < 0 || f1 > 999999)
13342b15cb3dSCy Schubert 				oncore_log_f(instance, LOG_WARNING,
13352b15cb3dSCy Schubert 					     "PPS Cable delay of %fns out of Range, ignored",
13362b15cb3dSCy Schubert 					     f1);
13372b15cb3dSCy Schubert 			else
1338c0b746e5SOllivier Robert 				instance->delay = f1;		/* delay in ns */
1339224ba2bdSOllivier Robert 		} else if (!strncmp(cc, "OFFSET", (size_t) 6)) {
1340c0b746e5SOllivier Robert 			f1 = 0;
1341c0b746e5SOllivier Robert 			units[0] = '\0';
1342a151a66cSOllivier Robert 			sscanf(ca, "%lf %1s", &f1, units);
1343c0b746e5SOllivier Robert 			if (units[0] == 'N')
1344c0b746e5SOllivier Robert 				;
1345c0b746e5SOllivier Robert 			else if (units[0] == 'U')
1346c0b746e5SOllivier Robert 				f1 = 1000 * f1;
1347c0b746e5SOllivier Robert 			else if (units[0] == 'M')
1348c0b746e5SOllivier Robert 				f1 = 1000000 * f1;
1349c0b746e5SOllivier Robert 			else
1350c0b746e5SOllivier Robert 				f1 = 1000000000 * f1;
1351c0b746e5SOllivier Robert 			if (f1 < 0 || f1 > 1.e9)
1352c0b746e5SOllivier Robert 				f1 = 0;
13532b15cb3dSCy Schubert 			if (f1 < 0 || f1 > 999999999.)
13542b15cb3dSCy Schubert 				oncore_log_f(instance, LOG_WARNING,
13552b15cb3dSCy Schubert 					     "PPS Offset of %fns out of Range, ignored",
13562b15cb3dSCy Schubert 					     f1);
13572b15cb3dSCy Schubert 			else
1358c0b746e5SOllivier Robert 				instance->offset = f1;		/* offset in ns */
1359224ba2bdSOllivier Robert 		} else if (!strncmp(cc, "MODE", (size_t) 4)) {
1360a151a66cSOllivier Robert 			sscanf(ca, "%d", &mode);
1361c0b746e5SOllivier Robert 			if (mode < 0 || mode > 4)
1362c0b746e5SOllivier Robert 				mode = 4;
1363224ba2bdSOllivier Robert 		} else if (!strncmp(cc, "ASSERT", (size_t) 6)) {
1364c0b746e5SOllivier Robert 			instance->assert = 1;
1365224ba2bdSOllivier Robert 		} else if (!strncmp(cc, "CLEAR", (size_t) 5)) {
1366c0b746e5SOllivier Robert 			instance->assert = 0;
13679c2daa00SOllivier Robert 		} else if (!strncmp(cc, "HARDPPS", (size_t) 7)) {
13689c2daa00SOllivier Robert 			instance->hardpps = 1;
1369224ba2bdSOllivier Robert 		} else if (!strncmp(cc, "POSN2D", (size_t) 6)) {
1370224ba2bdSOllivier Robert 			instance->shmem_Posn = 2;
1371224ba2bdSOllivier Robert 		} else if (!strncmp(cc, "POSN3D", (size_t) 6)) {
1372224ba2bdSOllivier Robert 			instance->shmem_Posn = 3;
1373224ba2bdSOllivier Robert 		} else if (!strncmp(cc, "CHAN", (size_t) 4)) {
1374224ba2bdSOllivier Robert 			sscanf(ca, "%d", &i);
1375224ba2bdSOllivier Robert 			if ((i == 6) || (i == 8) || (i == 12))
13769c2daa00SOllivier Robert 				instance->chan_in = i;
1377224ba2bdSOllivier Robert 		} else if (!strncmp(cc, "TRAIM", (size_t) 5)) {
13789c2daa00SOllivier Robert 			instance->traim_in = 1; 	/* so TRAIM alone is YES */
1379224ba2bdSOllivier Robert 			if (!strcmp(ca, "NO") || !strcmp(ca, "OFF"))    /* Yes/No, On/Off */
13809c2daa00SOllivier Robert 				instance->traim_in = 0;
13819c2daa00SOllivier Robert 		} else if (!strncmp(cc, "MASK", (size_t) 4)) {
13829c2daa00SOllivier Robert 			sscanf(ca, "%d", &mask);
13839c2daa00SOllivier Robert 			if (mask > -1 && mask < 90)
13849c2daa00SOllivier Robert 				instance->Ag = mask;			/* Satellite mask angle */
13852b15cb3dSCy Schubert 		} else if (!strncmp(cc,"PPSCONTROL",10)) {              /* pps control M12 only */
13862b15cb3dSCy Schubert 			if (!strcmp(ca,"ON") || !strcmp(ca, "CONTINUOUS")) {
13872b15cb3dSCy Schubert 				instance->pps_control = 1;		/* PPS always on */
13882b15cb3dSCy Schubert 			} else if (!strcmp(ca,"SATELLITE")) {
13892b15cb3dSCy Schubert 				instance->pps_control = 2;		/* PPS on when satellite is available */
13902b15cb3dSCy Schubert 			} else if (!strcmp(ca,"TRAIM")) {
13912b15cb3dSCy Schubert 				instance->pps_control = 3;		/* PPS on when TRAIM status is OK */
13922b15cb3dSCy Schubert 			} else {
13932b15cb3dSCy Schubert 				oncore_log_f(instance, LOG_WARNING,
13942b15cb3dSCy Schubert 				             "Unknown value \"%s\" for PPSCONTROL, ignored",
13952b15cb3dSCy Schubert 					     cc);
13962b15cb3dSCy Schubert 			}
1397c0b746e5SOllivier Robert 		}
1398c0b746e5SOllivier Robert 	}
1399c0b746e5SOllivier Robert 	fclose(fd);
1400c0b746e5SOllivier Robert 
1401c0b746e5SOllivier Robert 	/*
1402c0b746e5SOllivier Robert 	 *    OK, have read all of data file, and extracted the good stuff.
1403c0b746e5SOllivier Robert 	 *    If lat/long/ht specified they ALL must be specified for mode = (1,3).
1404c0b746e5SOllivier Robert 	 */
1405c0b746e5SOllivier Robert 
1406c0b746e5SOllivier Robert 	instance->posn_set = 1;
14079c2daa00SOllivier Robert 	if (!( lat_flg && long_flg && ht_flg )) {
14082b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_WARNING,
14092b15cb3dSCy Schubert 			     "ONCORE: incomplete data on %s", device);
1410c0b746e5SOllivier Robert 		instance->posn_set = 0;
1411224ba2bdSOllivier Robert 		if (mode == 1 || mode == 3) {
14122b15cb3dSCy Schubert 			oncore_log_f(instance, LOG_WARNING,
14132b15cb3dSCy Schubert 				     "Input Mode = %d, but no/incomplete position, mode set to %d",
14142b15cb3dSCy Schubert 				     mode, mode+1);
1415224ba2bdSOllivier Robert 			mode++;
1416c0b746e5SOllivier Robert 		}
1417c0b746e5SOllivier Robert 	}
1418224ba2bdSOllivier Robert 	instance->init_type = mode;
1419224ba2bdSOllivier Robert 
14202b15cb3dSCy Schubert 	oncore_log_f(instance, LOG_INFO, "Input mode = %d", mode);
1421224ba2bdSOllivier Robert }
1422224ba2bdSOllivier Robert 
1423224ba2bdSOllivier Robert 
1424224ba2bdSOllivier Robert 
1425c0b746e5SOllivier Robert /*
14269c2daa00SOllivier Robert  * move data from NTP to buffer (toss the extra in the unlikely case it won't fit)
1427c0b746e5SOllivier Robert  */
1428224ba2bdSOllivier Robert 
1429c0b746e5SOllivier Robert static void
1430c0b746e5SOllivier Robert oncore_receive(
1431c0b746e5SOllivier Robert 	struct recvbuf *rbufp
1432c0b746e5SOllivier Robert 	)
1433c0b746e5SOllivier Robert {
1434224ba2bdSOllivier Robert 	size_t i;
1435c0b746e5SOllivier Robert 	u_char *p;
1436c0b746e5SOllivier Robert 	struct peer *peer;
1437c0b746e5SOllivier Robert 	struct instance *instance;
1438c0b746e5SOllivier Robert 
14392b15cb3dSCy Schubert 	peer = rbufp->recv_peer;
14402b15cb3dSCy Schubert 	instance = peer->procptr->unitptr;
1441c0b746e5SOllivier Robert 	p = (u_char *) &rbufp->recv_space;
1442c0b746e5SOllivier Robert 
14432b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_RECEIVE
1444c0b746e5SOllivier Robert 	if (debug > 4) {
1445c0b746e5SOllivier Robert 		int i;
14462b15cb3dSCy Schubert 		char	Msg[120], Msg2[10];
14472b15cb3dSCy Schubert 
14482b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_DEBUG,
14492b15cb3dSCy Schubert 			     ">>> %d bytes available",
14502b15cb3dSCy Schubert 			     rbufp->recv_length);
14512b15cb3dSCy Schubert 		strlcpy(Msg, ">>>", sizeof(Msg));
14522b15cb3dSCy Schubert 		for (i = 0; i < rbufp->recv_length; i++) {
14532b15cb3dSCy Schubert 			snprintf(Msg2, sizeof(Msg2), "%02x ", p[i]);
14542b15cb3dSCy Schubert 			strlcat(Msg, Msg2, sizeof(Msg));
14552b15cb3dSCy Schubert 		}
14562b15cb3dSCy Schubert 		oncore_log(instance, LOG_DEBUG, Msg);
14572b15cb3dSCy Schubert 
14582b15cb3dSCy Schubert 		strlcpy(Msg, ">>>", sizeof(Msg));
14592b15cb3dSCy Schubert 		for (i = 0; i < rbufp->recv_length; i++) {
14602b15cb3dSCy Schubert 			snprintf(Msg2, sizeof(Msg2), "%03o ", p[i]);
14612b15cb3dSCy Schubert 			strlcat(Msg, Msg2, sizeof(Msg));
14622b15cb3dSCy Schubert 		}
14632b15cb3dSCy Schubert 		oncore_log(instance, LOG_DEBUG, Msg);
1464c0b746e5SOllivier Robert 	}
1465c0b746e5SOllivier Robert #endif
1466c0b746e5SOllivier Robert 
1467c0b746e5SOllivier Robert 	i = rbufp->recv_length;
1468f0574f5cSXin LI 	if ((size_t)rcvptr + i >= sizeof(rcvbuf))
1469c0b746e5SOllivier Robert 		i = sizeof(rcvbuf) - rcvptr;	/* and some char will be lost */
1470c0b746e5SOllivier Robert 	memcpy(rcvbuf+rcvptr, p, i);
1471c0b746e5SOllivier Robert 	rcvptr += i;
1472c0b746e5SOllivier Robert 	oncore_consume(instance);
1473c0b746e5SOllivier Robert }
1474c0b746e5SOllivier Robert 
1475c0b746e5SOllivier Robert 
1476c0b746e5SOllivier Robert 
1477c0b746e5SOllivier Robert /*
1478c0b746e5SOllivier Robert  * Deal with any complete messages
1479c0b746e5SOllivier Robert  */
1480224ba2bdSOllivier Robert 
1481c0b746e5SOllivier Robert static void
1482c0b746e5SOllivier Robert oncore_consume(
1483c0b746e5SOllivier Robert 	struct instance *instance
1484c0b746e5SOllivier Robert 	)
1485c0b746e5SOllivier Robert {
14862b15cb3dSCy Schubert 	unsigned i, m, l;
1487c0b746e5SOllivier Robert 
1488c0b746e5SOllivier Robert 	while (rcvptr >= 7) {
1489c0b746e5SOllivier Robert 		if (rcvbuf[0] != '@' || rcvbuf[1] != '@') {
1490c0b746e5SOllivier Robert 			/* We're not in sync, lets try to get there */
1491c0b746e5SOllivier Robert 			for (i=1; i < rcvptr-1; i++)
1492c0b746e5SOllivier Robert 				if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@')
1493c0b746e5SOllivier Robert 					break;
14942b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_CONSUME
1495c0b746e5SOllivier Robert 			if (debug > 4)
14962b15cb3dSCy Schubert 				oncore_log_f(instance, LOG_DEBUG,
14972b15cb3dSCy Schubert 					     ">>> skipping %d chars",
14982b15cb3dSCy Schubert 					     i);
1499ea906c41SOllivier Robert #endif
1500c0b746e5SOllivier Robert 			if (i != rcvptr)
1501224ba2bdSOllivier Robert 				memcpy(rcvbuf, rcvbuf+i, (size_t)(rcvptr-i));
1502c0b746e5SOllivier Robert 			rcvptr -= i;
1503224ba2bdSOllivier Robert 			continue;
1504c0b746e5SOllivier Robert 		}
1505c0b746e5SOllivier Robert 
1506c0b746e5SOllivier Robert 		/* Ok, we have a header now */
1507c0b746e5SOllivier Robert 		l = sizeof(oncore_messages)/sizeof(oncore_messages[0]) -1;
1508c0b746e5SOllivier Robert 		for(m=0; m<l; m++)
1509224ba2bdSOllivier Robert 			if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), (size_t) 2))
1510c0b746e5SOllivier Robert 				break;
1511224ba2bdSOllivier Robert 		if (m == l) {
15122b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_CONSUME
1513224ba2bdSOllivier Robert 			if (debug > 4)
15142b15cb3dSCy Schubert 				oncore_log_f(instance, LOG_DEBUG,
15152b15cb3dSCy Schubert 					     ">>> Unknown MSG, skipping 4 (%c%c)",
15162b15cb3dSCy Schubert 					     rcvbuf[2], rcvbuf[3]);
1517ea906c41SOllivier Robert #endif
1518224ba2bdSOllivier Robert 			memcpy(rcvbuf, rcvbuf+4, (size_t) 4);
1519224ba2bdSOllivier Robert 			rcvptr -= 4;
1520224ba2bdSOllivier Robert 			continue;
1521224ba2bdSOllivier Robert 		}
1522224ba2bdSOllivier Robert 
1523c0b746e5SOllivier Robert 		l = oncore_messages[m].len;
15242b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_CONSUME
1525c0b746e5SOllivier Robert 		if (debug > 3)
15262b15cb3dSCy Schubert 			oncore_log_f(instance, LOG_DEBUG,
15272b15cb3dSCy Schubert 				     "GOT: %c%c  %d of %d entry %d",
15282b15cb3dSCy Schubert 				     instance->unit, rcvbuf[2],
15292b15cb3dSCy Schubert 				     rcvbuf[3], rcvptr, l, m);
1530c0b746e5SOllivier Robert #endif
1531c0b746e5SOllivier Robert 		/* Got the entire message ? */
1532c0b746e5SOllivier Robert 
1533c0b746e5SOllivier Robert 		if (rcvptr < l)
1534c0b746e5SOllivier Robert 			return;
1535c0b746e5SOllivier Robert 
1536224ba2bdSOllivier Robert 		/* are we at the end of message? should be <Cksum><CR><LF> */
1537c0b746e5SOllivier Robert 
1538224ba2bdSOllivier Robert 		if (rcvbuf[l-2] != '\r' || rcvbuf[l-1] != '\n') {
15392b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_CONSUME
1540224ba2bdSOllivier Robert 			if (debug)
15412b15cb3dSCy Schubert 				oncore_log(instance, LOG_DEBUG, "NO <CR><LF> at end of message");
1542ea906c41SOllivier Robert #endif
1543224ba2bdSOllivier Robert 		} else {	/* check the CheckSum */
15449c2daa00SOllivier Robert 			if (oncore_checksum_ok(rcvbuf, l)) {
1545224ba2bdSOllivier Robert 				if (instance->shmem != NULL) {
1546224ba2bdSOllivier Robert 					instance->shmem[oncore_messages[m].shmem + 2]++;
1547224ba2bdSOllivier Robert 					memcpy(instance->shmem + oncore_messages[m].shmem + 3,
1548224ba2bdSOllivier Robert 					    rcvbuf, (size_t) l);
1549224ba2bdSOllivier Robert 				}
1550224ba2bdSOllivier Robert 				oncore_msg_any(instance, rcvbuf, (size_t) (l-3), m);
1551c0b746e5SOllivier Robert 				if (oncore_messages[m].handler)
1552224ba2bdSOllivier Robert 					oncore_messages[m].handler(instance, rcvbuf, (size_t) (l-3));
1553ea906c41SOllivier Robert 			}
15542b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_CONSUME
1555ea906c41SOllivier Robert 			else if (debug) {
15562b15cb3dSCy Schubert 				char	Msg[120], Msg2[10];
15572b15cb3dSCy Schubert 
15582b15cb3dSCy Schubert 				oncore_log(instance, LOG_ERR, "Checksum mismatch!");
15592b15cb3dSCy Schubert 				snprintf(Msg, sizeof(Msg), "@@%c%c ", rcvbuf[2], rcvbuf[3]);
15602b15cb3dSCy Schubert 				for (i = 4; i < l; i++) {
15612b15cb3dSCy Schubert 					snprintf(Msg2, sizeof(Msg2),
15622b15cb3dSCy Schubert 						 "%03o ", rcvbuf[i]);
15632b15cb3dSCy Schubert 					strlcat(Msg, Msg2, sizeof(Msg));
15642b15cb3dSCy Schubert 				}
15652b15cb3dSCy Schubert 				oncore_log(instance, LOG_DEBUG, Msg);
1566c0b746e5SOllivier Robert 			}
1567ea906c41SOllivier Robert #endif
1568224ba2bdSOllivier Robert 		}
1569c0b746e5SOllivier Robert 
1570c0b746e5SOllivier Robert 		if (l != rcvptr)
1571224ba2bdSOllivier Robert 			memcpy(rcvbuf, rcvbuf+l, (size_t) (rcvptr-l));
1572c0b746e5SOllivier Robert 		rcvptr -= l;
1573c0b746e5SOllivier Robert 	}
1574c0b746e5SOllivier Robert }
1575c0b746e5SOllivier Robert 
1576c0b746e5SOllivier Robert 
1577c0b746e5SOllivier Robert 
1578224ba2bdSOllivier Robert static void
1579224ba2bdSOllivier Robert oncore_get_timestamp(
1580224ba2bdSOllivier Robert 	struct instance *instance,
1581224ba2bdSOllivier Robert 	long dt1,	/* tick offset THIS time step */
1582224ba2bdSOllivier Robert 	long dt2	/* tick offset NEXT time step */
1583224ba2bdSOllivier Robert 	)
1584224ba2bdSOllivier Robert {
1585224ba2bdSOllivier Robert 	int	Rsm;
1586ea906c41SOllivier Robert 	u_long	j;
1587c0b746e5SOllivier Robert 	l_fp ts, ts_tmp;
1588c0b746e5SOllivier Robert 	double dmy;
1589224ba2bdSOllivier Robert #ifdef HAVE_STRUCT_TIMESPEC
1590c0b746e5SOllivier Robert 	struct timespec *tsp = 0;
1591c0b746e5SOllivier Robert #else
1592c0b746e5SOllivier Robert 	struct timeval	*tsp = 0;
1593c0b746e5SOllivier Robert #endif
1594224ba2bdSOllivier Robert 	int	current_mode;
1595224ba2bdSOllivier Robert 	pps_params_t current_params;
1596c0b746e5SOllivier Robert 	struct timespec timeout;
15972b15cb3dSCy Schubert 	struct peer *peer;
1598c0b746e5SOllivier Robert 	pps_info_t pps_i;
15992b15cb3dSCy Schubert 	char Msg[160];
16002b15cb3dSCy Schubert 
16012b15cb3dSCy Schubert 	peer = instance->peer;
1602c0b746e5SOllivier Robert 
16039c2daa00SOllivier Robert #if 1
16049c2daa00SOllivier Robert 	/* If we are in SiteSurvey mode, then we are in 3D mode, and we fall thru.
16059c2daa00SOllivier Robert 	 * If we have Finished the SiteSurvey, then we fall thru for the 14/15
16069c2daa00SOllivier Robert 	 *  times we get here in 0D mode (the 1/15 is in 3D for SHMEM).
16079c2daa00SOllivier Robert 	 * This gives good time, which gets better when the SS is done.
16089c2daa00SOllivier Robert 	 */
16099c2daa00SOllivier Robert 
16102b15cb3dSCy Schubert 	if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D)) {
16119c2daa00SOllivier Robert #else
16129c2daa00SOllivier Robert 	/* old check, only fall thru for SS_DONE and 0D mode, 2h45m wait for ticks */
16139c2daa00SOllivier Robert 
16142b15cb3dSCy Schubert 	if ((instance->site_survey != ONCORE_SS_DONE) || (instance->mode != MODE_0D)) {
16159c2daa00SOllivier Robert #endif
16162b15cb3dSCy Schubert 		peer->flags &= ~FLAG_PPS;	/* problem - clear PPS FLAG */
1617c0b746e5SOllivier Robert 		return;
16182b15cb3dSCy Schubert 	}
1619c0b746e5SOllivier Robert 
1620c0b746e5SOllivier Robert 	/* Don't do anything without an almanac to define the GPS->UTC delta */
1621c0b746e5SOllivier Robert 
16222b15cb3dSCy Schubert 	if (instance->rsm.bad_almanac) {
16232b15cb3dSCy Schubert 		peer->flags &= ~FLAG_PPS;	/* problem - clear PPS FLAG */
1624c0b746e5SOllivier Robert 		return;
16252b15cb3dSCy Schubert 	}
1626c0b746e5SOllivier Robert 
1627ea906c41SOllivier Robert 	/* Once the Almanac is valid, the M12+T does not produce valid UTC
1628ea906c41SOllivier Robert 	 * immediately.
1629ea906c41SOllivier Robert 	 * Wait for UTC offset decode valid, then wait one message more
1630ea906c41SOllivier Robert 	 * so we are not off by 13 seconds after  reset.
1631ea906c41SOllivier Robert 	 */
1632ea906c41SOllivier Robert 
1633ea906c41SOllivier Robert 	if (instance->count5) {
1634ea906c41SOllivier Robert 		instance->count5--;
16352b15cb3dSCy Schubert 		peer->flags &= ~FLAG_PPS;	/* problem - clear PPS FLAG */
1636ea906c41SOllivier Robert 		return;
1637ea906c41SOllivier Robert 	}
1638ea906c41SOllivier Robert 
1639c0b746e5SOllivier Robert 	j = instance->ev_serial;
1640c0b746e5SOllivier Robert 	timeout.tv_sec = 0;
1641c0b746e5SOllivier Robert 	timeout.tv_nsec = 0;
1642c0b746e5SOllivier Robert 	if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i,
1643c0b746e5SOllivier Robert 	    &timeout) < 0) {
16442b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_ERR,
16452b15cb3dSCy Schubert 			     "time_pps_fetch failed %m");
16462b15cb3dSCy Schubert 		peer->flags &= ~FLAG_PPS;	/* problem - clear PPS FLAG */
1647c0b746e5SOllivier Robert 		return;
1648c0b746e5SOllivier Robert 	}
1649c0b746e5SOllivier Robert 
1650c0b746e5SOllivier Robert 	if (instance->assert) {
1651c0b746e5SOllivier Robert 		tsp = &pps_i.assert_timestamp;
1652c0b746e5SOllivier Robert 
16532b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_GET_TIMESTAMP
1654224ba2bdSOllivier Robert 		if (debug > 2) {
16552b15cb3dSCy Schubert 			u_long i;
16562b15cb3dSCy Schubert 
1657224ba2bdSOllivier Robert 			i = (u_long) pps_i.assert_sequence;
1658224ba2bdSOllivier Robert # ifdef HAVE_STRUCT_TIMESPEC
16592b15cb3dSCy Schubert 			oncore_log_f(instance, LOG_DEBUG,
16602b15cb3dSCy Schubert 				     "serial/j (%lu, %lu) %ld.%09ld", i,
16612b15cb3dSCy Schubert 				     j, (long)tsp->tv_sec,
16622b15cb3dSCy Schubert 				     (long)tsp->tv_nsec);
1663224ba2bdSOllivier Robert # else
16642b15cb3dSCy Schubert 			oncore_log_f(instance, LOG_DEBUG,
16652b15cb3dSCy Schubert 				     "serial/j (%lu, %lu) %ld.%06ld", i,
16662b15cb3dSCy Schubert 				     j, (long)tsp->tv_sec,
16672b15cb3dSCy Schubert 				     (long)tsp->tv_usec);
1668224ba2bdSOllivier Robert # endif
1669224ba2bdSOllivier Robert 		}
1670ea906c41SOllivier Robert #endif
1671c0b746e5SOllivier Robert 
1672c0b746e5SOllivier Robert 		if (pps_i.assert_sequence == j) {
16732b15cb3dSCy Schubert 			oncore_log(instance, LOG_NOTICE, "ONCORE: oncore_get_timestamp, error serial pps");
16742b15cb3dSCy Schubert 			peer->flags &= ~FLAG_PPS;	/* problem - clear PPS FLAG */
1675c0b746e5SOllivier Robert 			return;
1676c0b746e5SOllivier Robert 		}
16772b15cb3dSCy Schubert 
1678c0b746e5SOllivier Robert 		instance->ev_serial = pps_i.assert_sequence;
1679c0b746e5SOllivier Robert 	} else {
1680c0b746e5SOllivier Robert 		tsp = &pps_i.clear_timestamp;
1681c0b746e5SOllivier Robert 
16822b15cb3dSCy Schubert #if 0
1683224ba2bdSOllivier Robert 		if (debug > 2) {
16842b15cb3dSCy Schubert 			u_long i;
16852b15cb3dSCy Schubert 
1686224ba2bdSOllivier Robert 			i = (u_long) pps_i.clear_sequence;
1687224ba2bdSOllivier Robert # ifdef HAVE_STRUCT_TIMESPEC
16882b15cb3dSCy Schubert 			oncore_log_f(instance, LOG_DEBUG,
16892b15cb3dSCy Schubert 				     "serial/j (%lu, %lu) %ld.%09ld", i,
16902b15cb3dSCy Schubert 				     j, (long)tsp->tv_sec,
16912b15cb3dSCy Schubert 				     (long)tsp->tv_nsec);
1692224ba2bdSOllivier Robert # else
16932b15cb3dSCy Schubert 			oncore_log_f(instance, LOG_DEBUG,
16942b15cb3dSCy Schubert 				     "serial/j (%lu, %lu) %ld.%06ld", i,
16952b15cb3dSCy Schubert 				     j, (long)tsp->tv_sec,
16962b15cb3dSCy Schubert 				     (long)tsp->tv_usec);
1697224ba2bdSOllivier Robert # endif
1698224ba2bdSOllivier Robert 		}
1699ea906c41SOllivier Robert #endif
1700c0b746e5SOllivier Robert 
1701c0b746e5SOllivier Robert 		if (pps_i.clear_sequence == j) {
17022b15cb3dSCy Schubert 			oncore_log(instance, LOG_ERR, "oncore_get_timestamp, error serial pps");
17032b15cb3dSCy Schubert 			peer->flags &= ~FLAG_PPS;	/* problem - clear PPS FLAG */
1704c0b746e5SOllivier Robert 			return;
1705c0b746e5SOllivier Robert 		}
1706c0b746e5SOllivier Robert 		instance->ev_serial = pps_i.clear_sequence;
1707c0b746e5SOllivier Robert 	}
1708c0b746e5SOllivier Robert 
1709c0b746e5SOllivier Robert 	/* convert timespec -> ntp l_fp */
1710c0b746e5SOllivier Robert 
1711c0b746e5SOllivier Robert 	dmy = tsp->tv_nsec;
1712c0b746e5SOllivier Robert 	dmy /= 1e9;
1713c0b746e5SOllivier Robert 	ts.l_uf = dmy * 4294967296.0;
1714c0b746e5SOllivier Robert 	ts.l_ui = tsp->tv_sec;
1715ea906c41SOllivier Robert 
1716c0b746e5SOllivier Robert #if 0
1717c0b746e5SOllivier Robert      alternate code for previous 4 lines is
1718c0b746e5SOllivier Robert 	dmy = 1.0e-9*tsp->tv_nsec;	/* fractional part */
1719c0b746e5SOllivier Robert 	DTOLFP(dmy, &ts);
1720c0b746e5SOllivier Robert 	dmy = tsp->tv_sec;		/* integer part */
1721c0b746e5SOllivier Robert 	DTOLFP(dmy, &ts_tmp);
1722c0b746e5SOllivier Robert 	L_ADD(&ts, &ts_tmp);
1723c0b746e5SOllivier Robert      or more simply
1724c0b746e5SOllivier Robert 	dmy = 1.0e-9*tsp->tv_nsec;	/* fractional part */
1725c0b746e5SOllivier Robert 	DTOLFP(dmy, &ts);
1726c0b746e5SOllivier Robert 	ts.l_ui = tsp->tv_sec;
1727c0b746e5SOllivier Robert #endif	/* 0 */
1728c0b746e5SOllivier Robert 
1729c0b746e5SOllivier Robert 	/* now have timestamp in ts */
1730224ba2bdSOllivier Robert 	/* add in saw_tooth and offset, these will be ZERO if no TRAIM */
1731ea906c41SOllivier Robert 	/* they will be IGNORED if the PPSAPI cant do PPS_OFFSET/ASSERT/CLEAR */
1732ea906c41SOllivier Robert 	/* we just try to add them in and dont test for that here */
1733c0b746e5SOllivier Robert 
1734c0b746e5SOllivier Robert 	/* saw_tooth not really necessary if using TIMEVAL */
1735c0b746e5SOllivier Robert 	/* since its only precise to us, but do it anyway. */
1736c0b746e5SOllivier Robert 
1737c0b746e5SOllivier Robert 	/* offset in ns, and is positive (late), we subtract */
1738c0b746e5SOllivier Robert 	/* to put the PPS time transition back where it belongs */
1739c0b746e5SOllivier Robert 
1740224ba2bdSOllivier Robert 	/* must hand the offset for the NEXT sec off to the Kernel to do */
1741224ba2bdSOllivier Robert 	/* the addition, so that the Kernel PLL sees the offset too */
1742c0b746e5SOllivier Robert 
1743224ba2bdSOllivier Robert 	if (instance->assert)
1744224ba2bdSOllivier Robert 		instance->pps_p.assert_offset.tv_nsec = -dt2;
1745224ba2bdSOllivier Robert 	else
1746224ba2bdSOllivier Robert 		instance->pps_p.clear_offset.tv_nsec  = -dt2;
1747224ba2bdSOllivier Robert 
1748224ba2bdSOllivier Robert 	/* The following code is necessary, and not just a time_pps_setparams,
1749224ba2bdSOllivier Robert 	 * using the saved instance->pps_p, since some other process on the
1750224ba2bdSOllivier Robert 	 * machine may have diddled with the mode bits (say adding something
1751224ba2bdSOllivier Robert 	 * that it needs).  We take what is there and ADD what we need.
1752224ba2bdSOllivier Robert 	 * [[ The results from the time_pps_getcap is unlikely to change so
1753224ba2bdSOllivier Robert 	 *    we could probably just save it, but I choose to do the call ]]
1754224ba2bdSOllivier Robert 	 * Unfortunately, there is only ONE set of mode bits in the kernel per
1755224ba2bdSOllivier Robert 	 * interface, and not one set for each open handle.
1756224ba2bdSOllivier Robert 	 *
1757224ba2bdSOllivier Robert 	 * There is still a race condition here where we might mess up someone
1758224ba2bdSOllivier Robert 	 * elses mode, but if he is being careful too, he should survive.
1759224ba2bdSOllivier Robert 	 */
1760224ba2bdSOllivier Robert 
1761224ba2bdSOllivier Robert 	if (time_pps_getcap(instance->pps_h, &current_mode) < 0) {
17622b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_ERR,
17632b15cb3dSCy Schubert 			     "time_pps_getcap failed: %m");
17642b15cb3dSCy Schubert 		peer->flags &= ~FLAG_PPS;	/* problem - clear PPS FLAG */
1765224ba2bdSOllivier Robert 		return;
1766c0b746e5SOllivier Robert 	}
1767c0b746e5SOllivier Robert 
1768224ba2bdSOllivier Robert 	if (time_pps_getparams(instance->pps_h, &current_params) < 0) {
17692b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_ERR,
17702b15cb3dSCy Schubert 			     "time_pps_getparams failed: %m");
17712b15cb3dSCy Schubert 		peer->flags &= ~FLAG_PPS;	/* problem - clear PPS FLAG */
1772224ba2bdSOllivier Robert 		return;
1773224ba2bdSOllivier Robert 	}
1774224ba2bdSOllivier Robert 
1775224ba2bdSOllivier Robert 		/* or current and mine */
1776224ba2bdSOllivier Robert 	current_params.mode |= instance->pps_p.mode;
1777224ba2bdSOllivier Robert 		/* but only set whats legal */
1778224ba2bdSOllivier Robert 	current_params.mode &= current_mode;
1779224ba2bdSOllivier Robert 
1780224ba2bdSOllivier Robert 	current_params.assert_offset.tv_sec = 0;
1781224ba2bdSOllivier Robert 	current_params.assert_offset.tv_nsec = -dt2;
1782224ba2bdSOllivier Robert 	current_params.clear_offset.tv_sec = 0;
1783224ba2bdSOllivier Robert 	current_params.clear_offset.tv_nsec = -dt2;
1784224ba2bdSOllivier Robert 
1785224ba2bdSOllivier Robert 	if (time_pps_setparams(instance->pps_h, &current_params))
17862b15cb3dSCy Schubert 		oncore_log(instance, LOG_ERR, "ONCORE: Error doing time_pps_setparams");
1787c0b746e5SOllivier Robert 
1788c0b746e5SOllivier Robert 	/* have time from UNIX origin, convert to NTP origin. */
1789c0b746e5SOllivier Robert 
1790c0b746e5SOllivier Robert 	ts.l_ui += JAN_1970;
1791c0b746e5SOllivier Robert 	instance->pp->lastrec = ts;
17929c2daa00SOllivier Robert 
17939c2daa00SOllivier Robert 	/* print out information about this timestamp (long line) */
1794c0b746e5SOllivier Robert 
1795c0b746e5SOllivier Robert 	ts_tmp = ts;
1796c0b746e5SOllivier Robert 	ts_tmp.l_ui = 0;	/* zero integer part */
1797c0b746e5SOllivier Robert 	LFPTOD(&ts_tmp, dmy);	/* convert fractional part to a double */
1798c0b746e5SOllivier Robert 	j = 1.0e9*dmy;		/* then to integer ns */
1799224ba2bdSOllivier Robert 
1800224ba2bdSOllivier Robert 	Rsm = 0;
1801224ba2bdSOllivier Robert 	if (instance->chan == 6)
18029c2daa00SOllivier Robert 		Rsm = instance->BEHa[64];
1803224ba2bdSOllivier Robert 	else if (instance->chan == 8)
18049c2daa00SOllivier Robert 		Rsm = instance->BEHa[72];
1805224ba2bdSOllivier Robert 	else if (instance->chan == 12)
18069c2daa00SOllivier Robert 		Rsm = ((instance->BEHa[129]<<8) | instance->BEHa[130]);
1807224ba2bdSOllivier Robert 
1808224ba2bdSOllivier Robert 	if (instance->chan == 6 || instance->chan == 8) {
1809ea906c41SOllivier Robert 		char	f1[5], f2[5], f3[5], f4[5];
1810ea906c41SOllivier Robert 		if (instance->traim) {
18112b15cb3dSCy Schubert 			snprintf(f1, sizeof(f1), "%d",
18122b15cb3dSCy Schubert 				 instance->BEHn[21]);
18132b15cb3dSCy Schubert 			snprintf(f2, sizeof(f2), "%d",
18142b15cb3dSCy Schubert 				 instance->BEHn[22]);
18152b15cb3dSCy Schubert 			snprintf(f3, sizeof(f3), "%2d",
18162b15cb3dSCy Schubert 				 instance->BEHn[23] * 256 +
18172b15cb3dSCy Schubert 				     instance->BEHn[24]);
18182b15cb3dSCy Schubert 			snprintf(f4, sizeof(f4), "%3d",
18192b15cb3dSCy Schubert 				 (s_char)instance->BEHn[25]);
1820ea906c41SOllivier Robert 		} else {
18212b15cb3dSCy Schubert 			strlcpy(f1, "x", sizeof(f1));
18222b15cb3dSCy Schubert 			strlcpy(f2, "x", sizeof(f2));
18232b15cb3dSCy Schubert 			strlcpy(f3, "xx", sizeof(f3));
18242b15cb3dSCy Schubert 			strlcpy(f4, "xxx", sizeof(f4));
1825ea906c41SOllivier Robert 		}
18262b15cb3dSCy Schubert 		snprintf(Msg, sizeof(Msg),	/* MAX length 128, currently at 127 */
1827ea906c41SOllivier Robert  "%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",
1828c0b746e5SOllivier Robert 		    ts.l_ui, j,
1829c0b746e5SOllivier Robert 		    instance->pp->year, instance->pp->day,
1830c0b746e5SOllivier Robert 		    instance->pp->hour, instance->pp->minute, instance->pp->second,
1831c0b746e5SOllivier Robert 		    (long) tsp->tv_sec % 60,
18329c2daa00SOllivier Robert 		    Rsm, 0.1*(256*instance->BEHa[35]+instance->BEHa[36]),
1833224ba2bdSOllivier Robert 		    /*rsat	dop */
1834ea906c41SOllivier Robert 		    instance->BEHa[38], instance->BEHa[39], instance->traim, f1, f2,
1835ea906c41SOllivier Robert 		    /*	nsat visible,	  nsat tracked,     traim,traim,traim */
1836ea906c41SOllivier Robert 		    f3, f4,
1837c0b746e5SOllivier Robert 		    /* sigma neg-sawtooth */
18389c2daa00SOllivier Robert 	  /*sat*/   instance->BEHa[41], instance->BEHa[45], instance->BEHa[49], instance->BEHa[53],
18399c2daa00SOllivier Robert 		    instance->BEHa[57], instance->BEHa[61], instance->BEHa[65], instance->BEHa[69]
1840224ba2bdSOllivier Robert 		    );					/* will be 0 for 6 chan */
1841224ba2bdSOllivier Robert 	} else if (instance->chan == 12) {
1842ea906c41SOllivier Robert 		char	f1[5], f2[5], f3[5], f4[5];
1843ea906c41SOllivier Robert 		if (instance->traim) {
18442b15cb3dSCy Schubert 			snprintf(f1, sizeof(f1), "%d",
18452b15cb3dSCy Schubert 				 instance->BEHn[6]);
18462b15cb3dSCy Schubert 			snprintf(f2, sizeof(f2), "%d",
18472b15cb3dSCy Schubert 				 instance->BEHn[7]);
18482b15cb3dSCy Schubert 			snprintf(f3, sizeof(f3), "%d",
18492b15cb3dSCy Schubert 				 instance->BEHn[12] * 256 +
18502b15cb3dSCy Schubert 				     instance->BEHn[13]);
18512b15cb3dSCy Schubert 			snprintf(f4, sizeof(f4), "%3d",
18522b15cb3dSCy Schubert 				 (s_char)instance->BEHn[14]);
1853ea906c41SOllivier Robert 		} else {
18542b15cb3dSCy Schubert 			strlcpy(f1, "x", sizeof(f1));
18552b15cb3dSCy Schubert 			strlcpy(f2, "x", sizeof(f2));
18562b15cb3dSCy Schubert 			strlcpy(f3, "xx", sizeof(f3));
18572b15cb3dSCy Schubert 			strlcpy(f4, "xxx", sizeof(f4));
1858ea906c41SOllivier Robert 		}
18592b15cb3dSCy Schubert 		snprintf(Msg, sizeof(Msg),
1860ea906c41SOllivier Robert  "%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",
1861224ba2bdSOllivier Robert 		    ts.l_ui, j,
1862224ba2bdSOllivier Robert 		    instance->pp->year, instance->pp->day,
1863224ba2bdSOllivier Robert 		    instance->pp->hour, instance->pp->minute, instance->pp->second,
1864224ba2bdSOllivier Robert 		    (long) tsp->tv_sec % 60,
18659c2daa00SOllivier Robert 		    Rsm, 0.1*(256*instance->BEHa[53]+instance->BEHa[54]),
1866224ba2bdSOllivier Robert 		    /*rsat	dop */
1867ea906c41SOllivier Robert 		    instance->BEHa[55], instance->BEHa[56], instance->traim, f1, f2,
1868ea906c41SOllivier Robert 		    /*	nsat visible,	  nsat tracked	 traim,traim,traim */
1869ea906c41SOllivier Robert 		    f3, f4,
18709c2daa00SOllivier Robert 		    /* sigma neg-sawtooth */
18719c2daa00SOllivier Robert 	  /*sat*/   instance->BEHa[58], instance->BEHa[64], instance->BEHa[70], instance->BEHa[76],
18729c2daa00SOllivier Robert 		    instance->BEHa[82], instance->BEHa[88], instance->BEHa[94], instance->BEHa[100],
18739c2daa00SOllivier Robert 		    instance->BEHa[106], instance->BEHa[112], instance->BEHa[118], instance->BEHa[124]
1874c0b746e5SOllivier Robert 		    );
1875224ba2bdSOllivier Robert 	}
1876c0b746e5SOllivier Robert 
1877ea906c41SOllivier Robert 	/* and some things I dont understand (magic ntp things) */
18789c2daa00SOllivier Robert 
18792d4e511cSCy Schubert #if 1
18802d4e511cSCy Schubert 	oncore_feed_clockproc(instance);
18812d4e511cSCy Schubert #else
1882c0b746e5SOllivier Robert 	if (!refclock_process(instance->pp)) {
18832d4e511cSCy Schubert 		refclock_report(peer, CEVNT_BADTIME);
18842b15cb3dSCy Schubert 		peer->flags &= ~FLAG_PPS;	/* problem - clear PPS FLAG */
1885c0b746e5SOllivier Robert 		return;
1886c0b746e5SOllivier Robert 	}
18872d4e511cSCy Schubert #endif
1888c0b746e5SOllivier Robert 
18892b15cb3dSCy Schubert 	oncore_log(instance, LOG_INFO, Msg);	 /* this is long message above */
1890c0b746e5SOllivier Robert 	instance->pollcnt = 2;
1891c0b746e5SOllivier Robert 
1892c0b746e5SOllivier Robert 	if (instance->polled) {
1893c0b746e5SOllivier Robert 		instance->polled = 0;
1894ea906c41SOllivier Robert 	     /* instance->pp->dispersion = instance->pp->skew = 0;	*/
18959c2daa00SOllivier Robert 		instance->pp->lastref = instance->pp->lastrec;
1896c0b746e5SOllivier Robert 		refclock_receive(instance->peer);
1897c0b746e5SOllivier Robert 	}
18982b15cb3dSCy Schubert 	peer->flags |= FLAG_PPS;
1899c0b746e5SOllivier Robert }
1900c0b746e5SOllivier Robert 
1901c0b746e5SOllivier Robert 
19029c2daa00SOllivier Robert /*************** oncore_msg_XX routines start here *******************/
19039c2daa00SOllivier Robert 
19049c2daa00SOllivier Robert 
19059c2daa00SOllivier Robert /*
19069c2daa00SOllivier Robert  * print Oncore response message.
19079c2daa00SOllivier Robert  */
19089c2daa00SOllivier Robert 
19099c2daa00SOllivier Robert static void
19109c2daa00SOllivier Robert oncore_msg_any(
19119c2daa00SOllivier Robert 	struct instance *instance,
19129c2daa00SOllivier Robert 	u_char *buf,
19139c2daa00SOllivier Robert 	size_t len,
19149c2daa00SOllivier Robert 	int idx
19159c2daa00SOllivier Robert 	)
19169c2daa00SOllivier Robert {
19172b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_MSG_ANY
19189c2daa00SOllivier Robert 	int i;
19199c2daa00SOllivier Robert 	const char *fmt = oncore_messages[idx].fmt;
19209c2daa00SOllivier Robert 	const char *p;
19212b15cb3dSCy Schubert 	char *q;
19222b15cb3dSCy Schubert 	char *qlim;
19239c2daa00SOllivier Robert #ifdef HAVE_GETCLOCK
19249c2daa00SOllivier Robert 	struct timespec ts;
19259c2daa00SOllivier Robert #endif
19269c2daa00SOllivier Robert 	struct timeval tv;
19272b15cb3dSCy Schubert 	char	Msg[120], Msg2[10];
19289c2daa00SOllivier Robert 
19299c2daa00SOllivier Robert 	if (debug > 3) {
19309c2daa00SOllivier Robert # ifdef HAVE_GETCLOCK
19319c2daa00SOllivier Robert 		(void) getclock(TIMEOFDAY, &ts);
19329c2daa00SOllivier Robert 		tv.tv_sec = ts.tv_sec;
19339c2daa00SOllivier Robert 		tv.tv_usec = ts.tv_nsec / 1000;
19349c2daa00SOllivier Robert # else
19359c2daa00SOllivier Robert 		GETTIMEOFDAY(&tv, 0);
19369c2daa00SOllivier Robert # endif
19372b15cb3dSCy Schubert 		oncore_log(instance, LOG_DEBUG, "%ld.%06ld",
19382b15cb3dSCy Schubert 			   (long)tv.tv_sec, (long)tv.tv_usec);
19399c2daa00SOllivier Robert 
19409c2daa00SOllivier Robert 		if (!*fmt) {
19412b15cb3dSCy Schubert 			snprintf(Msg, sizeof(Msg), ">>@@%c%c ", buf[2],
19422b15cb3dSCy Schubert 				 buf[3]);
19432b15cb3dSCy Schubert 			for(i = 2; i < len && i < 2400 ; i++) {
19442b15cb3dSCy Schubert 				snprintf(Msg2, sizeof(Msg2), "%02x",
19452b15cb3dSCy Schubert 					 buf[i]);
19462b15cb3dSCy Schubert 				strlcat(Msg, Msg2, sizeof(Msg));
19472b15cb3dSCy Schubert 			}
19482b15cb3dSCy Schubert 			oncore_log(instance, LOG_DEBUG, Msg);
19499c2daa00SOllivier Robert 			return;
19509c2daa00SOllivier Robert 		} else {
19512b15cb3dSCy Schubert 			strlcpy(Msg, "##", sizeof(Msg));
19522b15cb3dSCy Schubert 			qlim = Msg + sizeof(Msg) - 3;
19532b15cb3dSCy Schubert 			for (p = fmt, q = Msg + 2; q < qlim && *p; ) {
19542b15cb3dSCy Schubert 				*q++ = *p++;
19552b15cb3dSCy Schubert 				*q++ = '_';
19569c2daa00SOllivier Robert 			}
19572b15cb3dSCy Schubert 			*q = '\0';
19582b15cb3dSCy Schubert 			oncore_log(instance, LOG_DEBUG, Msg);
19592b15cb3dSCy Schubert 			snprintf(Msg, sizeof(Msg), "%c%c", buf[2],
19602b15cb3dSCy Schubert 				 buf[3]);
19619c2daa00SOllivier Robert 			i = 4;
19629c2daa00SOllivier Robert 			for (p = fmt; *p; p++) {
19632b15cb3dSCy Schubert 				snprintf(Msg2, "%02x", buf[i++]);
19642b15cb3dSCy Schubert 				strlcat(Msg, Msg2, sizeof(Msg));
19659c2daa00SOllivier Robert 			}
19662b15cb3dSCy Schubert 			oncore_log(instance, LOG_DEBUG, Msg);
19679c2daa00SOllivier Robert 		}
19689c2daa00SOllivier Robert 	}
1969ea906c41SOllivier Robert #endif
19709c2daa00SOllivier Robert }
19719c2daa00SOllivier Robert 
19729c2daa00SOllivier Robert 
19739c2daa00SOllivier Robert 
19749c2daa00SOllivier Robert /* Latitude, Longitude, Height */
19759c2daa00SOllivier Robert 
19769c2daa00SOllivier Robert static void
19779c2daa00SOllivier Robert oncore_msg_Adef(
19789c2daa00SOllivier Robert 	struct instance *instance,
19799c2daa00SOllivier Robert 	u_char *buf,
19809c2daa00SOllivier Robert 	size_t len
19819c2daa00SOllivier Robert 	)
19829c2daa00SOllivier Robert {
19839c2daa00SOllivier Robert }
19849c2daa00SOllivier Robert 
19859c2daa00SOllivier Robert 
19869c2daa00SOllivier Robert 
19879c2daa00SOllivier Robert /* Mask Angle */
19889c2daa00SOllivier Robert 
19899c2daa00SOllivier Robert static void
19909c2daa00SOllivier Robert oncore_msg_Ag(
19919c2daa00SOllivier Robert 	struct instance *instance,
19929c2daa00SOllivier Robert 	u_char *buf,
19939c2daa00SOllivier Robert 	size_t len
19949c2daa00SOllivier Robert 	)
19952b15cb3dSCy Schubert {
19962b15cb3dSCy Schubert 	const char *cp;
19979c2daa00SOllivier Robert 
19989c2daa00SOllivier Robert 	cp = "set to";
19999c2daa00SOllivier Robert 	if (instance->o_state == ONCORE_RUN)
20009c2daa00SOllivier Robert 		cp = "is";
20019c2daa00SOllivier Robert 
20029c2daa00SOllivier Robert 	instance->Ag = buf[4];
20032b15cb3dSCy Schubert 	oncore_log_f(instance, LOG_INFO,
20042b15cb3dSCy Schubert 		     "Satellite mask angle %s %d degrees", cp,
20052b15cb3dSCy Schubert 		     (int)instance->Ag);
20069c2daa00SOllivier Robert }
20079c2daa00SOllivier Robert 
20089c2daa00SOllivier Robert 
20099c2daa00SOllivier Robert 
20109c2daa00SOllivier Robert /*
20119c2daa00SOllivier Robert  * get Position hold position
20129c2daa00SOllivier Robert  */
20139c2daa00SOllivier Robert 
20149c2daa00SOllivier Robert static void
20159c2daa00SOllivier Robert oncore_msg_As(
20169c2daa00SOllivier Robert 	struct instance *instance,
20179c2daa00SOllivier Robert 	u_char *buf,
20189c2daa00SOllivier Robert 	size_t len
20199c2daa00SOllivier Robert 	)
20209c2daa00SOllivier Robert {
20219c2daa00SOllivier Robert 	instance->ss_lat  = buf_w32(&buf[4]);
20229c2daa00SOllivier Robert 	instance->ss_long = buf_w32(&buf[8]);
20239c2daa00SOllivier Robert 	instance->ss_ht   = buf_w32(&buf[12]);
20249c2daa00SOllivier Robert 
20259c2daa00SOllivier Robert 	/* Print out Position */
20269c2daa00SOllivier Robert 	oncore_print_posn(instance);
20279c2daa00SOllivier Robert }
20289c2daa00SOllivier Robert 
20299c2daa00SOllivier Robert 
2030c0b746e5SOllivier Robert 
2031c0b746e5SOllivier Robert /*
2032c0b746e5SOllivier Robert  * Try to use Oncore UT+ Auto Survey Feature
2033c0b746e5SOllivier Robert  *	If its not there (VP), set flag to do it ourselves.
2034c0b746e5SOllivier Robert  */
2035224ba2bdSOllivier Robert 
2036c0b746e5SOllivier Robert static void
2037c0b746e5SOllivier Robert oncore_msg_At(
2038c0b746e5SOllivier Robert 	struct instance *instance,
2039c0b746e5SOllivier Robert 	u_char *buf,
2040224ba2bdSOllivier Robert 	size_t len
2041c0b746e5SOllivier Robert 	)
2042c0b746e5SOllivier Robert {
2043224ba2bdSOllivier Robert 	instance->saw_At = 1;
2044224ba2bdSOllivier Robert 	if (instance->site_survey == ONCORE_SS_TESTING) {
2045a151a66cSOllivier Robert 		if (buf[4] == 2) {
20462b15cb3dSCy Schubert 			oncore_log(instance, LOG_NOTICE,
2047a151a66cSOllivier Robert 					"Initiating hardware 3D site survey");
20489c2daa00SOllivier Robert 
20492b15cb3dSCy Schubert 			oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_HW");
2050c0b746e5SOllivier Robert 			instance->site_survey = ONCORE_SS_HW;
2051224ba2bdSOllivier Robert 		}
2052c0b746e5SOllivier Robert 	}
2053c0b746e5SOllivier Robert }
2054c0b746e5SOllivier Robert 
2055c0b746e5SOllivier Robert 
2056c0b746e5SOllivier Robert 
20579c2daa00SOllivier Robert /*
20589c2daa00SOllivier Robert  * get PPS Offset
20599c2daa00SOllivier Robert  * Nb. @@Ay is not supported for early UT (no plus) model
20609c2daa00SOllivier Robert  */
20619c2daa00SOllivier Robert 
20629c2daa00SOllivier Robert static void
20639c2daa00SOllivier Robert oncore_msg_Ay(
20649c2daa00SOllivier Robert 	struct instance *instance,
20659c2daa00SOllivier Robert 	u_char *buf,
20669c2daa00SOllivier Robert 	size_t len
20679c2daa00SOllivier Robert 	)
20689c2daa00SOllivier Robert {
20699c2daa00SOllivier Robert 	if (instance->saw_Ay)
20709c2daa00SOllivier Robert 		return;
20719c2daa00SOllivier Robert 
20729c2daa00SOllivier Robert 	instance->saw_Ay = 1;
20739c2daa00SOllivier Robert 
20749c2daa00SOllivier Robert 	instance->offset = buf_w32(&buf[4]);
20759c2daa00SOllivier Robert 
20762b15cb3dSCy Schubert 	oncore_log_f(instance, LOG_INFO, "PPS Offset is set to %ld ns",
20772b15cb3dSCy Schubert 		     instance->offset);
20789c2daa00SOllivier Robert }
20799c2daa00SOllivier Robert 
20809c2daa00SOllivier Robert 
20819c2daa00SOllivier Robert 
20829c2daa00SOllivier Robert /*
20839c2daa00SOllivier Robert  * get Cable Delay
20849c2daa00SOllivier Robert  */
20859c2daa00SOllivier Robert 
20869c2daa00SOllivier Robert static void
20879c2daa00SOllivier Robert oncore_msg_Az(
20889c2daa00SOllivier Robert 	struct instance *instance,
20899c2daa00SOllivier Robert 	u_char *buf,
20909c2daa00SOllivier Robert 	size_t len
20919c2daa00SOllivier Robert 	)
20929c2daa00SOllivier Robert {
20939c2daa00SOllivier Robert 	if (instance->saw_Az)
20949c2daa00SOllivier Robert 		return;
20959c2daa00SOllivier Robert 
20969c2daa00SOllivier Robert 	instance->saw_Az = 1;
20979c2daa00SOllivier Robert 
20989c2daa00SOllivier Robert 	instance->delay = buf_w32(&buf[4]);
20999c2daa00SOllivier Robert 
21002b15cb3dSCy Schubert 	oncore_log_f(instance, LOG_INFO, "Cable delay is set to %ld ns",
21012b15cb3dSCy Schubert 		     instance->delay);
21029c2daa00SOllivier Robert }
21039c2daa00SOllivier Robert 
21049c2daa00SOllivier Robert 
21059c2daa00SOllivier Robert 
21069c2daa00SOllivier Robert /* Ba, Ea and Ha come here, these contain Position */
21079c2daa00SOllivier Robert 
21089c2daa00SOllivier Robert static void
21099c2daa00SOllivier Robert oncore_msg_BaEaHa(
21109c2daa00SOllivier Robert 	struct instance *instance,
21119c2daa00SOllivier Robert 	u_char *buf,
21129c2daa00SOllivier Robert 	size_t len
21139c2daa00SOllivier Robert 	)
21149c2daa00SOllivier Robert {
21159c2daa00SOllivier Robert 	const char	*cp;
21169c2daa00SOllivier Robert 	int		mode;
21179c2daa00SOllivier Robert 
21189c2daa00SOllivier Robert 	/* OK, we are close to the RUN state now.
21199c2daa00SOllivier Robert 	 * But we have a few more items to initialize first.
21209c2daa00SOllivier Robert 	 *
21219c2daa00SOllivier Robert 	 * At the beginning of this routine there are several 'timers'.
21229c2daa00SOllivier Robert 	 * We enter this routine 1/sec, and since the upper levels of NTP have usurped
21239c2daa00SOllivier Robert 	 * the use of timers, we use the 1/sec entry to do things that
21249c2daa00SOllivier Robert 	 * we would normally do with timers...
21259c2daa00SOllivier Robert 	 */
21269c2daa00SOllivier Robert 
21279c2daa00SOllivier Robert 	if (instance->o_state == ONCORE_CHECK_CHAN) {	/* here while checking for the # chan */
21289c2daa00SOllivier Robert 		if (buf[2] == 'B') {		/* 6chan */
21299c2daa00SOllivier Robert 			if (instance->chan_ck < 6) instance->chan_ck = 6;
21309c2daa00SOllivier Robert 		} else if (buf[2] == 'E') {	/* 8chan */
21319c2daa00SOllivier Robert 			if (instance->chan_ck < 8) instance->chan_ck = 8;
21329c2daa00SOllivier Robert 		} else if (buf[2] == 'H') {	/* 12chan */
21339c2daa00SOllivier Robert 			if (instance->chan_ck < 12) instance->chan_ck = 12;
21349c2daa00SOllivier Robert 		}
21359c2daa00SOllivier Robert 
21369c2daa00SOllivier Robert 		if (instance->count3++ < 5)
21379c2daa00SOllivier Robert 			return;
21389c2daa00SOllivier Robert 
21399c2daa00SOllivier Robert 		instance->count3 = 0;
21409c2daa00SOllivier Robert 
21419c2daa00SOllivier Robert 		if (instance->chan_in != -1)	/* set in Input */
21429c2daa00SOllivier Robert 			instance->chan = instance->chan_in;
21439c2daa00SOllivier Robert 		else				/* set from test */
21449c2daa00SOllivier Robert 			instance->chan = instance->chan_ck;
21459c2daa00SOllivier Robert 
21462b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_INFO, "Input   says chan = %d",
21472b15cb3dSCy Schubert 			    instance->chan_in);
21482b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_INFO, "Model # says chan = %d",
21492b15cb3dSCy Schubert 			     instance->chan_id);
21502b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_INFO, "Testing says chan = %d",
21512b15cb3dSCy Schubert 			     instance->chan_ck);
21522b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_INFO, "Using        chan = %d",
21532b15cb3dSCy Schubert 			     instance->chan);
21549c2daa00SOllivier Robert 
21559c2daa00SOllivier Robert 		instance->o_state = ONCORE_HAVE_CHAN;
21562b15cb3dSCy Schubert 		oncore_log(instance, LOG_NOTICE, "state = ONCORE_HAVE_CHAN");
21579c2daa00SOllivier Robert 
21589c2daa00SOllivier Robert 		instance->timeout = 4;
21592b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
21609c2daa00SOllivier Robert 		return;
21619c2daa00SOllivier Robert 	}
21629c2daa00SOllivier Robert 
21639c2daa00SOllivier Robert 	if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN)
21649c2daa00SOllivier Robert 		return;
21659c2daa00SOllivier Robert 
2166ea906c41SOllivier Robert 	/* PAUSE 5sec - make sure results are stable, before using position */
21679c2daa00SOllivier Robert 
21689c2daa00SOllivier Robert 	if (instance->count) {
2169ea906c41SOllivier Robert 		if (instance->count++ < 5)
21709c2daa00SOllivier Robert 			return;
21719c2daa00SOllivier Robert 		instance->count = 0;
21729c2daa00SOllivier Robert 	}
21739c2daa00SOllivier Robert 
21749c2daa00SOllivier Robert 	memcpy(instance->BEHa, buf, (size_t) (len+3));	/* Ba, Ea or Ha */
21759c2daa00SOllivier Robert 
21762b15cb3dSCy Schubert 	/* check if we saw a response to Gc (M12 or M12+T */
21772b15cb3dSCy Schubert 
21782b15cb3dSCy Schubert 	if (instance->pps_control_msg_seen != -2) {
21792b15cb3dSCy Schubert 		if ((instance->pps_control_msg_seen == -1) && (instance->pps_control != -1)) {
21802b15cb3dSCy Schubert 			oncore_log(instance, LOG_INFO, "PPSCONTROL set, but not implemented (not M12)");
21812b15cb3dSCy Schubert 		}
21822b15cb3dSCy Schubert 		instance->pps_control_msg_seen = -2;
21832b15cb3dSCy Schubert 	}
21842b15cb3dSCy Schubert 
2185ea906c41SOllivier Robert 	/* check the antenna (did it get unplugged) and almanac (is it ready) for changes. */
21869c2daa00SOllivier Robert 
21879c2daa00SOllivier Robert 	oncore_check_almanac(instance);
21889c2daa00SOllivier Robert 	oncore_check_antenna(instance);
21899c2daa00SOllivier Robert 
2190ea906c41SOllivier Robert 	/* If we are in Almanac mode, waiting for Almanac, we can't do anything till we have it */
21919c2daa00SOllivier Robert 	/* When we have an almanac, we will start the Bn/En/@@Hn messages */
21929c2daa00SOllivier Robert 
21939c2daa00SOllivier Robert 	if (instance->o_state == ONCORE_ALMANAC)
21949c2daa00SOllivier Robert 		if (oncore_wait_almanac(instance))
21959c2daa00SOllivier Robert 			return;
21969c2daa00SOllivier Robert 
21979c2daa00SOllivier Robert 	/* do some things once when we get this far in BaEaHa */
21989c2daa00SOllivier Robert 
21999c2daa00SOllivier Robert 	if (instance->once) {
22009c2daa00SOllivier Robert 		instance->once = 0;
22019c2daa00SOllivier Robert 		instance->count2 = 1;
22029c2daa00SOllivier Robert 
22039c2daa00SOllivier Robert 		/* Have we seen an @@At (position hold) command response */
22049c2daa00SOllivier Robert 		/* if not, message out */
22059c2daa00SOllivier Robert 
22069c2daa00SOllivier Robert 		if (instance->chan != 12 && !instance->saw_At) {
22072b15cb3dSCy Schubert 			oncore_log(instance, LOG_NOTICE,
22082b15cb3dSCy Schubert 				"Not Good, no @@At command (no Position Hold), must be a GT/GT+");
22092b15cb3dSCy Schubert 			oncore_sendmsg(instance, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
22109c2daa00SOllivier Robert 		}
22119c2daa00SOllivier Robert 
22129c2daa00SOllivier Robert 		/* have an Almanac, can start the SiteSurvey
22139c2daa00SOllivier Robert 		 * (actually only need to get past the almanac_load where we diddle with At
22149c2daa00SOllivier Robert 		 *  command,- we can't change it after we start the HW_SS below
22159c2daa00SOllivier Robert 		 */
22169c2daa00SOllivier Robert 
22179c2daa00SOllivier Robert 		mode = instance->init_type;
22189c2daa00SOllivier Robert 		switch (mode) {
22199c2daa00SOllivier Robert 		case 0: /* NO initialization, don't change anything */
22209c2daa00SOllivier Robert 		case 1: /* Use given Position */
22219c2daa00SOllivier Robert 		case 3:
22229c2daa00SOllivier Robert 			instance->site_survey = ONCORE_SS_DONE;
22232b15cb3dSCy Schubert 			oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_DONE");
22249c2daa00SOllivier Robert 			break;
22259c2daa00SOllivier Robert 
22269c2daa00SOllivier Robert 		case 2:
22279c2daa00SOllivier Robert 		case 4: /* Site Survey */
22282b15cb3dSCy Schubert 			oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_TESTING");
22299c2daa00SOllivier Robert 			instance->site_survey = ONCORE_SS_TESTING;
22309c2daa00SOllivier Robert 			instance->count1 = 1;
22319c2daa00SOllivier Robert 			if (instance->chan == 12)
22322b15cb3dSCy Schubert 				oncore_sendmsg(instance, oncore_cmd_Gd3,  sizeof(oncore_cmd_Gd3));  /* M12+T */
22339c2daa00SOllivier Robert 			else
22342b15cb3dSCy Schubert 				oncore_sendmsg(instance, oncore_cmd_At2,  sizeof(oncore_cmd_At2));  /* not GT, arg not VP */
22359c2daa00SOllivier Robert 			break;
22369c2daa00SOllivier Robert 		}
22379c2daa00SOllivier Robert 
22389c2daa00SOllivier Robert 		/* Read back PPS Offset for Output */
22399c2daa00SOllivier Robert 		/* Nb. This will fail silently for early UT (no plus) and M12 models */
22409c2daa00SOllivier Robert 
22412b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Ayx,  sizeof(oncore_cmd_Ayx));
22429c2daa00SOllivier Robert 
22439c2daa00SOllivier Robert 		/* Read back Cable Delay for Output */
22449c2daa00SOllivier Robert 
22452b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Azx,  sizeof(oncore_cmd_Azx));
22469c2daa00SOllivier Robert 
22479c2daa00SOllivier Robert 		/* Read back Satellite Mask Angle for Output */
22489c2daa00SOllivier Robert 
22492b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Agx,  sizeof(oncore_cmd_Agx));
22509c2daa00SOllivier Robert 	}
22519c2daa00SOllivier Robert 
2252ea906c41SOllivier Robert 
2253ea906c41SOllivier Robert 	/* Unfortunately, the Gd3 command returns '3' for the M12 v1.3 firmware where it is
2254ea906c41SOllivier Robert 	 * out-of-range and it should return 0-2. (v1.3 can't do a HW Site Survey)
2255ea906c41SOllivier Robert 	 * We must do the Gd3, and then wait a cycle or two for things to settle,
2256ea906c41SOllivier Robert 	 * then check Ha[130]&0x10 to see if a SS is in progress.
2257ea906c41SOllivier Robert 	 * We will set SW if HW has not been set after an appropriate delay.
2258ea906c41SOllivier Robert 	 */
2259ea906c41SOllivier Robert 
22609c2daa00SOllivier Robert 	if (instance->site_survey == ONCORE_SS_TESTING) {
2261ea906c41SOllivier Robert 		if (instance->chan == 12) {
2262ea906c41SOllivier Robert 			if (instance->count1) {
2263ea906c41SOllivier Robert 				if (instance->count1++ > 5 || instance->BEHa[130]&0x10) {
2264ea906c41SOllivier Robert 					instance->count1 = 0;
2265ea906c41SOllivier Robert 					if (instance->BEHa[130]&0x10) {
22662b15cb3dSCy Schubert 						oncore_log(instance, LOG_NOTICE,
2267ea906c41SOllivier Robert 								"Initiating hardware 3D site survey");
2268ea906c41SOllivier Robert 
22692b15cb3dSCy Schubert 						oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_HW");
2270ea906c41SOllivier Robert 						instance->site_survey = ONCORE_SS_HW;
2271ea906c41SOllivier Robert 					} else {
22722b15cb3dSCy Schubert 						oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_SW");
2273ea906c41SOllivier Robert 						instance->site_survey = ONCORE_SS_SW;
2274ea906c41SOllivier Robert 					}
2275ea906c41SOllivier Robert 				}
2276ea906c41SOllivier Robert 			}
2277ea906c41SOllivier Robert 		} else {
2278ea906c41SOllivier Robert 			if (instance->count1) {
2279ea906c41SOllivier Robert 				if (instance->count1++ > 5) {
2280ea906c41SOllivier Robert 					instance->count1 = 0;
22819c2daa00SOllivier Robert 					/*
22829c2daa00SOllivier Robert 					 * For instance->site_survey to still be ONCORE_SS_TESTING, then after a 5sec
22839c2daa00SOllivier Robert 					 * wait after the @@At2/@@Gd3 command we have not changed the state to
22849c2daa00SOllivier Robert 					 * ONCORE_SS_HW.  If the Hardware is capable of doing a Site Survey, then
22859c2daa00SOllivier Robert 					 * the variable would have been changed by now.
22869c2daa00SOllivier Robert 					 * There are three possibilities:
22879c2daa00SOllivier Robert 					 * 6/8chan
22889c2daa00SOllivier Robert 					 *   (a) We did not get a response to the @@At0 or @@At2 commands,
22899c2daa00SOllivier Robert 					 *	   and it must be a GT/GT+/SL with no position hold mode.
22909c2daa00SOllivier Robert 					 *	   We will have to do it ourselves.
22919c2daa00SOllivier Robert 					 *   (b) We saw the @@At0, @@At2 commands, but @@At2 failed,
22929c2daa00SOllivier Robert 					 *	   must be a VP or older UT which doesn't have Site Survey mode.
22939c2daa00SOllivier Robert 					 *	   We will have to do it ourselves.
22949c2daa00SOllivier Robert 					 * 12chan
2295ea906c41SOllivier Robert 					 *   (c) We saw the @@Gd command, and saw H[13]*0x10
2296ea906c41SOllivier Robert 					 *	   We will have to do it ourselves (done above)
22979c2daa00SOllivier Robert 					 */
22989c2daa00SOllivier Robert 
22992b15cb3dSCy Schubert 					oncore_log_f(instance, LOG_INFO,
23002b15cb3dSCy Schubert 						     "Initiating software 3D site survey (%d samples)",
23019c2daa00SOllivier Robert 						     POS_HOLD_AVERAGE);
23029c2daa00SOllivier Robert 
23032b15cb3dSCy Schubert 					oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_SW");
23049c2daa00SOllivier Robert 					instance->site_survey = ONCORE_SS_SW;
23059c2daa00SOllivier Robert 
23069c2daa00SOllivier Robert 					instance->ss_lat = instance->ss_long = instance->ss_ht = 0;
23079c2daa00SOllivier Robert 					if (instance->chan == 12)
23082b15cb3dSCy Schubert 						oncore_sendmsg(instance, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* disable */
23099c2daa00SOllivier Robert 					else {
23102b15cb3dSCy Schubert 						oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* disable */
23112b15cb3dSCy Schubert 						oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* disable */
23129c2daa00SOllivier Robert 					}
23139c2daa00SOllivier Robert 				}
23149c2daa00SOllivier Robert 			}
23159c2daa00SOllivier Robert 		}
2316ea906c41SOllivier Robert 	}
23179c2daa00SOllivier Robert 
23189c2daa00SOllivier Robert 	/* check the mode we are in 0/2/3D */
23199c2daa00SOllivier Robert 
23209c2daa00SOllivier Robert 	if (instance->chan == 6) {
23219c2daa00SOllivier Robert 		if (instance->BEHa[64]&0x8)
23229c2daa00SOllivier Robert 			instance->mode = MODE_0D;
23239c2daa00SOllivier Robert 		else if (instance->BEHa[64]&0x10)
23249c2daa00SOllivier Robert 			instance->mode = MODE_2D;
23259c2daa00SOllivier Robert 		else if (instance->BEHa[64]&0x20)
23269c2daa00SOllivier Robert 			instance->mode = MODE_3D;
23279c2daa00SOllivier Robert 	} else if (instance->chan == 8) {
23289c2daa00SOllivier Robert 		if (instance->BEHa[72]&0x8)
23299c2daa00SOllivier Robert 			instance->mode = MODE_0D;
23309c2daa00SOllivier Robert 		else if (instance->BEHa[72]&0x10)
23319c2daa00SOllivier Robert 			instance->mode = MODE_2D;
23329c2daa00SOllivier Robert 		else if (instance->BEHa[72]&0x20)
23339c2daa00SOllivier Robert 			instance->mode = MODE_3D;
23349c2daa00SOllivier Robert 	} else if (instance->chan == 12) {
23359c2daa00SOllivier Robert 		int bits;
23369c2daa00SOllivier Robert 
23379c2daa00SOllivier Robert 		bits = (instance->BEHa[129]>>5) & 0x7;	/* actually Ha */
23389c2daa00SOllivier Robert 		if (bits == 0x4)
23399c2daa00SOllivier Robert 			instance->mode = MODE_0D;
23409c2daa00SOllivier Robert 		else if (bits == 0x6)
23419c2daa00SOllivier Robert 			instance->mode = MODE_2D;
23429c2daa00SOllivier Robert 		else if (bits == 0x7)
23439c2daa00SOllivier Robert 			instance->mode = MODE_3D;
23449c2daa00SOllivier Robert 	}
23459c2daa00SOllivier Robert 
23469c2daa00SOllivier Robert 	/* copy the record to the (extra) location in SHMEM */
23479c2daa00SOllivier Robert 
23489c2daa00SOllivier Robert 	if (instance->shmem) {
23499c2daa00SOllivier Robert 		int	i;
23509c2daa00SOllivier Robert 		u_char	*smp;	 /* pointer to start of shared mem for Ba/Ea/Ha */
23519c2daa00SOllivier Robert 
23529c2daa00SOllivier Robert 		switch(instance->chan) {
23539c2daa00SOllivier Robert 		case 6:   smp = &instance->shmem[instance->shmem_Ba]; break;
23549c2daa00SOllivier Robert 		case 8:   smp = &instance->shmem[instance->shmem_Ea]; break;
23559c2daa00SOllivier Robert 		case 12:  smp = &instance->shmem[instance->shmem_Ha]; break;
2356ea906c41SOllivier Robert 		default:  smp = (u_char *) NULL;		      break;
23579c2daa00SOllivier Robert 		}
23589c2daa00SOllivier Robert 
23599c2daa00SOllivier Robert 		switch (instance->mode) {
23609c2daa00SOllivier Robert 		case MODE_0D:	i = 1; break;	/* 0D, Position Hold */
23619c2daa00SOllivier Robert 		case MODE_2D:	i = 2; break;	/* 2D, Altitude Hold */
23629c2daa00SOllivier Robert 		case MODE_3D:	i = 3; break;	/* 3D fix */
23639c2daa00SOllivier Robert 		default:	i = 0; break;
23649c2daa00SOllivier Robert 		}
23659c2daa00SOllivier Robert 
2366ea906c41SOllivier Robert 		if (i && smp != NULL) {
23679c2daa00SOllivier Robert 			i *= (len+6);
23689c2daa00SOllivier Robert 			smp[i + 2]++;
23699c2daa00SOllivier Robert 			memcpy(&smp[i+3], buf, (size_t) (len+3));
23709c2daa00SOllivier Robert 		}
23719c2daa00SOllivier Robert 	}
23729c2daa00SOllivier Robert 
23739c2daa00SOllivier Robert 	/*
2374ea906c41SOllivier Robert 	 * check if traim timer active
23759c2daa00SOllivier Robert 	 * if it hasn't been cleared, then @@Bn/@@En/@@Hn did not respond
23769c2daa00SOllivier Robert 	 */
23779c2daa00SOllivier Robert 
23789c2daa00SOllivier Robert 	if (instance->traim_delay) {
23799c2daa00SOllivier Robert 		if (instance->traim_delay++ > 5) {
23809c2daa00SOllivier Robert 			instance->traim = 0;
23819c2daa00SOllivier Robert 			instance->traim_delay = 0;
23829c2daa00SOllivier Robert 			cp = "ONCORE: Did not detect TRAIM response, TRAIM = OFF";
23832b15cb3dSCy Schubert 			oncore_log(instance, LOG_INFO, cp);
23849c2daa00SOllivier Robert 
23859c2daa00SOllivier Robert 			oncore_set_traim(instance);
23869c2daa00SOllivier Robert 		} else
23879c2daa00SOllivier Robert 			return;
23889c2daa00SOllivier Robert 
23899c2daa00SOllivier Robert 	}
23909c2daa00SOllivier Robert 
23919c2daa00SOllivier Robert 	/* by now should have a @@Ba/@@Ea/@@Ha with good data in it */
23929c2daa00SOllivier Robert 
23939c2daa00SOllivier Robert 	if (!instance->have_dH && !instance->traim_delay)
23949c2daa00SOllivier Robert 		oncore_compute_dH(instance);
23959c2daa00SOllivier Robert 
23969c2daa00SOllivier Robert 	/*
23979c2daa00SOllivier Robert 	 * must be ONCORE_RUN if we are here.
23989c2daa00SOllivier Robert 	 * Have # chan and TRAIM by now.
23999c2daa00SOllivier Robert 	 */
24009c2daa00SOllivier Robert 
24019c2daa00SOllivier Robert 	instance->pp->year   = buf[6]*256+buf[7];
24029c2daa00SOllivier Robert 	instance->pp->day    = ymd2yd(buf[6]*256+buf[7], buf[4], buf[5]);
24039c2daa00SOllivier Robert 	instance->pp->hour   = buf[8];
24049c2daa00SOllivier Robert 	instance->pp->minute = buf[9];
24059c2daa00SOllivier Robert 	instance->pp->second = buf[10];
24069c2daa00SOllivier Robert 
24079c2daa00SOllivier Robert 	/*
24089c2daa00SOllivier Robert 	 * Are we doing a Hardware or Software Site Survey?
24099c2daa00SOllivier Robert 	 */
24109c2daa00SOllivier Robert 
24119c2daa00SOllivier Robert 	if (instance->site_survey == ONCORE_SS_HW || instance->site_survey == ONCORE_SS_SW)
24129c2daa00SOllivier Robert 		oncore_ss(instance);
24139c2daa00SOllivier Robert 
24149c2daa00SOllivier Robert 	/* see if we ever saw a response from the @@Ayx above */
24159c2daa00SOllivier Robert 
24169c2daa00SOllivier Robert 	if (instance->count2) {
24179c2daa00SOllivier Robert 		if (instance->count2++ > 5) {	/* this delay to check on @@Ay command */
24189c2daa00SOllivier Robert 			instance->count2 = 0;
24199c2daa00SOllivier Robert 
24209c2daa00SOllivier Robert 			/* Have we seen an Ay (1PPS time offset) command response */
24219c2daa00SOllivier Robert 			/* if not, and non-zero offset, zero the offset, and send message */
24229c2daa00SOllivier Robert 
24239c2daa00SOllivier Robert 			if (!instance->saw_Ay && instance->offset) {
24242b15cb3dSCy Schubert 				oncore_log(instance, LOG_INFO, "No @@Ay command, PPS OFFSET ignored");
24259c2daa00SOllivier Robert 				instance->offset = 0;
24269c2daa00SOllivier Robert 			}
24279c2daa00SOllivier Robert 		}
24289c2daa00SOllivier Robert 	}
24299c2daa00SOllivier Robert 
24309c2daa00SOllivier Robert 	/*
24319c2daa00SOllivier Robert 	 * Check the leap second status once per day.
24329c2daa00SOllivier Robert 	 */
24339c2daa00SOllivier Robert 
24349c2daa00SOllivier Robert 	oncore_check_leap_sec(instance);
24359c2daa00SOllivier Robert 
24369c2daa00SOllivier Robert 	/*
24379c2daa00SOllivier Robert 	 * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn.
24389c2daa00SOllivier Robert 	 */
24399c2daa00SOllivier Robert 
24409c2daa00SOllivier Robert 	if (instance->shmem && !instance->shmem_bad_Ea && instance->shmem_Posn && (instance->site_survey == ONCORE_SS_DONE))
24419c2daa00SOllivier Robert 		oncore_shmem_get_3D(instance);
24429c2daa00SOllivier Robert 
24439c2daa00SOllivier Robert 	if (!instance->traim)	/* NO traim, no BnEnHn, go get tick */
24449c2daa00SOllivier Robert 		oncore_get_timestamp(instance, instance->offset, instance->offset);
24459c2daa00SOllivier Robert }
24469c2daa00SOllivier Robert 
24479c2daa00SOllivier Robert 
24489c2daa00SOllivier Robert 
24499c2daa00SOllivier Robert /* Almanac Status */
24509c2daa00SOllivier Robert 
24519c2daa00SOllivier Robert static void
24529c2daa00SOllivier Robert oncore_msg_Bd(
24539c2daa00SOllivier Robert 	struct instance *instance,
24549c2daa00SOllivier Robert 	u_char *buf,
24559c2daa00SOllivier Robert 	size_t len
24569c2daa00SOllivier Robert 	)
24579c2daa00SOllivier Robert {
24582b15cb3dSCy Schubert 	oncore_log_f(instance, LOG_NOTICE,
24592b15cb3dSCy Schubert 		     "Bd: Almanac %s, week = %d, t = %d, %d SVs: %x",
24602b15cb3dSCy Schubert 		     ((buf[4]) ? "LOADED" : "(NONE)"), buf[5], buf[6],
24612b15cb3dSCy Schubert 		     buf[7], w32(&buf[8]));
24629c2daa00SOllivier Robert }
24639c2daa00SOllivier Robert 
24649c2daa00SOllivier Robert 
24659c2daa00SOllivier Robert 
2466c0b746e5SOllivier Robert /* get leap-second warning message */
2467c0b746e5SOllivier Robert 
2468c0b746e5SOllivier Robert /*
2469c0b746e5SOllivier Robert  * @@Bj does NOT behave as documented in current Oncore firmware.
2470c0b746e5SOllivier Robert  * It turns on the LEAP indicator when the data is set, and does not,
2471c0b746e5SOllivier Robert  * as documented, wait until the beginning of the month when the
2472c0b746e5SOllivier Robert  * leap second will occur.
24739c2daa00SOllivier Robert  * Since this firmware bug will never be fixed in all the outstanding Oncore receivers
24749c2daa00SOllivier Robert  * @@Bj is only called in June/December.
2475c0b746e5SOllivier Robert  */
2476c0b746e5SOllivier Robert 
2477c0b746e5SOllivier Robert static void
2478c0b746e5SOllivier Robert oncore_msg_Bj(
2479c0b746e5SOllivier Robert 	struct instance *instance,
2480c0b746e5SOllivier Robert 	u_char *buf,
2481224ba2bdSOllivier Robert 	size_t len
2482c0b746e5SOllivier Robert 	)
2483c0b746e5SOllivier Robert {
2484c0b746e5SOllivier Robert 	const char	*cp;
2485c0b746e5SOllivier Robert 
24862b15cb3dSCy Schubert 	instance->saw_Bj = 1;
24872b15cb3dSCy Schubert 
2488c0b746e5SOllivier Robert 	switch(buf[4]) {
2489c0b746e5SOllivier Robert 	case 1:
2490ea906c41SOllivier Robert 		instance->pp->leap = LEAP_ADDSECOND;
2491ea906c41SOllivier Robert 		cp = "Set pp.leap to LEAP_ADDSECOND";
2492c0b746e5SOllivier Robert 		break;
2493c0b746e5SOllivier Robert 	case 2:
2494ea906c41SOllivier Robert 		instance->pp->leap = LEAP_DELSECOND;
2495ea906c41SOllivier Robert 		cp = "Set pp.leap to LEAP_DELSECOND";
2496c0b746e5SOllivier Robert 		break;
2497c0b746e5SOllivier Robert 	case 0:
2498c0b746e5SOllivier Robert 	default:
2499ea906c41SOllivier Robert 		instance->pp->leap = LEAP_NOWARNING;
2500ea906c41SOllivier Robert 		cp = "Set pp.leap to LEAP_NOWARNING";
2501c0b746e5SOllivier Robert 		break;
2502c0b746e5SOllivier Robert 	}
25032b15cb3dSCy Schubert 	oncore_log(instance, LOG_NOTICE, cp);
2504c0b746e5SOllivier Robert }
2505c0b746e5SOllivier Robert 
25069c2daa00SOllivier Robert 
25079c2daa00SOllivier Robert 
25089c2daa00SOllivier Robert static void
25092b15cb3dSCy Schubert oncore_msg_Bl(
25102b15cb3dSCy Schubert 	struct instance *instance,
25112b15cb3dSCy Schubert 	u_char *buf,
25122b15cb3dSCy Schubert 	size_t	len
25132b15cb3dSCy Schubert 	)
25142b15cb3dSCy Schubert {
25152b15cb3dSCy Schubert 	int	subframe, valid, page, i, j, tow;
25162b15cb3dSCy Schubert 	int	day_now, day_lsf;
25172b15cb3dSCy Schubert 	const char	*cp;
25182b15cb3dSCy Schubert 	enum {
25192b15cb3dSCy Schubert 		WARN_NOT_YET,
25202b15cb3dSCy Schubert 		WARN_0,
25212b15cb3dSCy Schubert 		WARN_PLUS,
25222b15cb3dSCy Schubert 		WARN_MINUS
25232b15cb3dSCy Schubert 	} warn;
25242b15cb3dSCy Schubert 
25252b15cb3dSCy Schubert 
25262b15cb3dSCy Schubert 	subframe = buf[6] & 017;
25272b15cb3dSCy Schubert 	valid = (buf[6] >> 4) & 017;
25282b15cb3dSCy Schubert 	page = buf[7];
25292b15cb3dSCy Schubert 
25302b15cb3dSCy Schubert 	if ((!instance->Bl.lsf_flg && !instance->Bl.wn_flg) && (subframe == 4 && page == 18 && valid == 10)) {
25312b15cb3dSCy Schubert 		instance->Bl.dt_ls  = buf[32];
25322b15cb3dSCy Schubert 		instance->Bl.WN_lsf = buf[33];
25332b15cb3dSCy Schubert 		instance->Bl.DN_lsf = buf[34];
25342b15cb3dSCy Schubert 		instance->Bl.dt_lsf = buf[35];
25352b15cb3dSCy Schubert 		instance->Bl.lsf_flg++;
25362b15cb3dSCy Schubert 	}
25372b15cb3dSCy Schubert 	if ((instance->Bl.lsf_flg && !instance->Bl.wn_flg) && (subframe == 1 && valid == 10)) {
25382b15cb3dSCy Schubert 		i = (buf[7+7]<<8) + buf[7+8];
25392b15cb3dSCy Schubert 		instance->Bl.WN = i >> 6;
25402b15cb3dSCy Schubert 		tow = (buf[7+4]<<16) + (buf[7+5]<<8) + buf[7+6];
25412b15cb3dSCy Schubert 		tow >>= 7;
25422b15cb3dSCy Schubert 		tow = tow & 0377777;
25432b15cb3dSCy Schubert 		tow <<= 2;
25442b15cb3dSCy Schubert 		instance->Bl.DN = tow/57600L + 1;
25452b15cb3dSCy Schubert 		instance->Bl.wn_flg++;
25462b15cb3dSCy Schubert 	}
25472b15cb3dSCy Schubert 	if (instance->Bl.wn_flg && instance->Bl.lsf_flg)  {
25482b15cb3dSCy Schubert 		instance->Bl.wn_flg = instance->Bl.lsf_flg = 0;
25492b15cb3dSCy Schubert 		oncore_cmd_Bl[2] = 0;
25502b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Bl, sizeof oncore_cmd_Bl);
25512b15cb3dSCy Schubert 		oncore_cmd_Bl[2] = 1;
25522b15cb3dSCy Schubert 
25532b15cb3dSCy Schubert 		i = instance->Bl.WN&01400;
25542b15cb3dSCy Schubert 		instance->Bl.WN_lsf |= i;
25552b15cb3dSCy Schubert 
25562b15cb3dSCy Schubert 		/* have everything I need, doit */
25572b15cb3dSCy Schubert 
25582b15cb3dSCy Schubert 		i = (instance->Bl.WN_lsf - instance->Bl.WN);
25592b15cb3dSCy Schubert 		if (i < 0)
25602b15cb3dSCy Schubert 			i += 1024;
25612b15cb3dSCy Schubert 		day_now = instance->Bl.DN;
25622b15cb3dSCy Schubert 		day_lsf = 7*i + instance->Bl.DN_lsf;
25632b15cb3dSCy Schubert 
25642b15cb3dSCy Schubert 		/* ignore if in past or more than a month in future */
25652b15cb3dSCy Schubert 
25662b15cb3dSCy Schubert 		warn = WARN_NOT_YET;
25672b15cb3dSCy Schubert 		if (day_lsf >= day_now && day_lsf - day_now < 32) {
25682b15cb3dSCy Schubert 			/* if < 28d, doit, if 28-31, ck day-of-month < 20 (not at end of prev month) */
25692b15cb3dSCy Schubert 			if (day_lsf - day_now < 28 ||  instance->BEHa[5] < 20) {
25702b15cb3dSCy Schubert 				i = instance->Bl.dt_lsf - instance->Bl.dt_ls;
25712b15cb3dSCy Schubert 				switch (i) {
25722b15cb3dSCy Schubert 				case -1:
25732b15cb3dSCy Schubert 					warn = WARN_MINUS;
25742b15cb3dSCy Schubert 					break;
25752b15cb3dSCy Schubert 				case  0:
25762b15cb3dSCy Schubert 					warn = WARN_0;
25772b15cb3dSCy Schubert 					break;
25782b15cb3dSCy Schubert 				case  1:
25792b15cb3dSCy Schubert 					warn = WARN_PLUS;
25802b15cb3dSCy Schubert 					break;
25812b15cb3dSCy Schubert 				}
25822b15cb3dSCy Schubert 			}
25832b15cb3dSCy Schubert 		}
25842b15cb3dSCy Schubert 
25852b15cb3dSCy Schubert 		switch (warn) {
25862b15cb3dSCy Schubert 		case WARN_0:
25872b15cb3dSCy Schubert 		case WARN_NOT_YET:
25882b15cb3dSCy Schubert 			instance->peer->leap = LEAP_NOWARNING;
25892b15cb3dSCy Schubert 			cp = "Set peer.leap to LEAP_NOWARNING";
25902b15cb3dSCy Schubert 			break;
25912b15cb3dSCy Schubert 		case WARN_MINUS:
25922b15cb3dSCy Schubert 			instance->peer->leap = LEAP_DELSECOND;
25932b15cb3dSCy Schubert 			cp = "Set peer.leap to LEAP_DELSECOND";
25942b15cb3dSCy Schubert 			break;
25952b15cb3dSCy Schubert 		case WARN_PLUS:
25962b15cb3dSCy Schubert 			instance->peer->leap = LEAP_ADDSECOND;
25972b15cb3dSCy Schubert 			cp = "Set peer.leap to LEAP_ADDSECOND";
25982b15cb3dSCy Schubert 			break;
2599f0574f5cSXin LI 		default:
2600f0574f5cSXin LI 			cp = NULL;
2601f0574f5cSXin LI 			break;
26022b15cb3dSCy Schubert 		}
26032b15cb3dSCy Schubert 		oncore_log(instance, LOG_NOTICE, cp);
26042b15cb3dSCy Schubert 
26052b15cb3dSCy Schubert 		i = instance->Bl.dt_lsf-instance->Bl.dt_ls;
26062b15cb3dSCy Schubert 		if (i) {
26072b15cb3dSCy Schubert 			j = (i >= 0) ? i : -i;		/* abs(i) */
26082b15cb3dSCy Schubert 			oncore_log_f(instance, LOG_NOTICE,
26092b15cb3dSCy Schubert 				     "see Leap_Second (%c%d) in %d days",
26102b15cb3dSCy Schubert 				     ((i >= 0) ? '+' : '-'), j,
26112b15cb3dSCy Schubert 				     day_lsf-day_now);
26122b15cb3dSCy Schubert 		}
26132b15cb3dSCy Schubert 	}
26142b15cb3dSCy Schubert 
26152b15cb3dSCy Schubert /*
26162b15cb3dSCy Schubert  * Reg only wants the following output for "deeper" driver debugging.
26172b15cb3dSCy Schubert  * See Bug 2142 and Bug 1866
26182b15cb3dSCy Schubert  */
26192b15cb3dSCy Schubert #if 0
26202b15cb3dSCy Schubert 	oncore_log_f(instance, LOG_DEBUG,
26212b15cb3dSCy Schubert 		     "dt_ls = %d  dt_lsf = %d  WN = %d  DN = %d  WN_lsf = %d  DNlsf = %d  wn_flg = %d  lsf_flg = %d  Bl_day = %d",
26222b15cb3dSCy Schubert 		     instance->Bl.dt_ls, instance->Bl.dt_lsf,
26232b15cb3dSCy Schubert 		     instance->Bl.WN, instance->Bl.DN,
26242b15cb3dSCy Schubert 		     instance->Bl.WN_lsf, instance->Bl.DN_lsf,
26252b15cb3dSCy Schubert 		     instance->Bl.wn_flg, instance->Bl.lsf_flg,
26262b15cb3dSCy Schubert 		     instance->Bl.Bl_day);
26272b15cb3dSCy Schubert #endif
26282b15cb3dSCy Schubert }
26292b15cb3dSCy Schubert 
26302b15cb3dSCy Schubert 
26312b15cb3dSCy Schubert static void
26329c2daa00SOllivier Robert oncore_msg_BnEnHn(
26339c2daa00SOllivier Robert 	struct instance *instance,
26349c2daa00SOllivier Robert 	u_char *buf,
26359c2daa00SOllivier Robert 	size_t	len
26369c2daa00SOllivier Robert 	)
26379c2daa00SOllivier Robert {
26389c2daa00SOllivier Robert 	long	dt1, dt2;
26399c2daa00SOllivier Robert 
26409c2daa00SOllivier Robert 	if (instance->o_state != ONCORE_RUN)
26419c2daa00SOllivier Robert 		return;
26429c2daa00SOllivier Robert 
26439c2daa00SOllivier Robert 	if (instance->traim_delay) {	 /* flag that @@Bn/@@En/Hn returned */
26449c2daa00SOllivier Robert 			instance->traim_ck = 1;
26459c2daa00SOllivier Robert 			instance->traim_delay = 0;
26462b15cb3dSCy Schubert 			oncore_log(instance, LOG_NOTICE, "ONCORE: Detected TRAIM, TRAIM = ON");
26479c2daa00SOllivier Robert 
26489c2daa00SOllivier Robert 			oncore_set_traim(instance);
26499c2daa00SOllivier Robert 	}
26509c2daa00SOllivier Robert 
26519c2daa00SOllivier Robert 	memcpy(instance->BEHn, buf, (size_t) len);	/* Bn or En or Hn */
26529c2daa00SOllivier Robert 
2653ea906c41SOllivier Robert 	if (!instance->traim)	/* BnEnHn will be turned off in any case */
2654ea906c41SOllivier Robert 		return;
2655ea906c41SOllivier Robert 
26569c2daa00SOllivier Robert 	/* If Time RAIM doesn't like it, don't trust it */
26579c2daa00SOllivier Robert 
26589c2daa00SOllivier Robert 	if (buf[2] == 'H') {
26592b15cb3dSCy Schubert 		if (instance->BEHn[6]) {    /* bad TRAIM */
26602b15cb3dSCy Schubert 			oncore_log(instance, LOG_WARNING, "BAD TRAIM");
26619c2daa00SOllivier Robert 			return;
26622b15cb3dSCy Schubert 		}
26639c2daa00SOllivier Robert 
26649c2daa00SOllivier Robert 		dt1 = instance->saw_tooth + instance->offset;	 /* dt this time step */
2665ea906c41SOllivier Robert 		instance->saw_tooth = (s_char) instance->BEHn[14]; /* update for next time Hn[14] */
26669c2daa00SOllivier Robert 		dt2 = instance->saw_tooth + instance->offset;	 /* dt next time step */
26679c2daa00SOllivier Robert 	} else {
26689c2daa00SOllivier Robert 		if (instance->BEHn[21]) /* bad TRAIM */
26699c2daa00SOllivier Robert 			return;
26709c2daa00SOllivier Robert 
26719c2daa00SOllivier Robert 		dt1 = instance->saw_tooth + instance->offset;	 /* dt this time step */
2672ea906c41SOllivier Robert 		instance->saw_tooth = (s_char) instance->BEHn[25]; /* update for next time Bn[25], En[25] */
26739c2daa00SOllivier Robert 		dt2 = instance->saw_tooth + instance->offset;	 /* dt next time step */
26749c2daa00SOllivier Robert 	}
26759c2daa00SOllivier Robert 
26769c2daa00SOllivier Robert 	oncore_get_timestamp(instance, dt1, dt2);
26779c2daa00SOllivier Robert }
26789c2daa00SOllivier Robert 
26799c2daa00SOllivier Robert 
26809c2daa00SOllivier Robert 
26819c2daa00SOllivier Robert /* Here for @@Ca, @@Fa and @@Ia messages */
26829c2daa00SOllivier Robert 
26839c2daa00SOllivier Robert /* These are Self test Commands for 6, 8, and 12 chan receivers.
26849c2daa00SOllivier Robert  * There are good reasons NOT to do a @@Ca, @@Fa or @@Ia command with the ONCORE.
26859c2daa00SOllivier Robert  * It was found that under some circumstances the following
26869c2daa00SOllivier Robert  * command would fail if issued immediately after the return from the
26879c2daa00SOllivier Robert  * @@Fa, but a 2sec delay seemed to fix things.  Since simply calling
26889c2daa00SOllivier Robert  * sleep(2) is wasteful, and may cause trouble for some OS's, repeating
26899c2daa00SOllivier Robert  * itimer, we set a flag, and test it at the next POLL.  If it hasn't
26909c2daa00SOllivier Robert  * been cleared, we reissue the @@Cj that is issued below.
26919c2daa00SOllivier Robert  * Note that we do a @@Cj at the beginning, and again here.
26929c2daa00SOllivier Robert  * The first is to get the info, the 2nd is just used as a safe command
26939c2daa00SOllivier Robert  * after the @@Fa for all Oncores (and it was in this posn in the
26949c2daa00SOllivier Robert  * original code).
26959c2daa00SOllivier Robert  */
26969c2daa00SOllivier Robert 
26979c2daa00SOllivier Robert static void
26989c2daa00SOllivier Robert oncore_msg_CaFaIa(
26999c2daa00SOllivier Robert 	struct instance *instance,
27009c2daa00SOllivier Robert 	u_char *buf,
27019c2daa00SOllivier Robert 	size_t len
27029c2daa00SOllivier Robert 	)
27039c2daa00SOllivier Robert {
27049c2daa00SOllivier Robert 	int	i;
27059c2daa00SOllivier Robert 
27069c2daa00SOllivier Robert 	if (instance->o_state == ONCORE_TEST_SENT) {
27079c2daa00SOllivier Robert 		enum antenna_state antenna;
27089c2daa00SOllivier Robert 
27099c2daa00SOllivier Robert 		instance->timeout = 0;
27109c2daa00SOllivier Robert 
27112b15cb3dSCy Schubert #if ONCORE_VERBOSE_SELF_TEST
27129c2daa00SOllivier Robert 		if (debug > 2) {
27139c2daa00SOllivier Robert 			if (buf[2] == 'I')
27142b15cb3dSCy Schubert 				oncore_log_f(instance, LOG_DEBUG,
27152b15cb3dSCy Schubert 					     ">>@@%ca %x %x %x", buf[2],
27162b15cb3dSCy Schubert 					     buf[4], buf[5], buf[6]);
27179c2daa00SOllivier Robert 			else
27182b15cb3dSCy Schubert 				oncore_log_f(instance, LOG_DEBUG,
27192b15cb3dSCy Schubert 					     ">>@@%ca %x %x", buf[2],
27202b15cb3dSCy Schubert 					     buf[4], buf[5]);
27219c2daa00SOllivier Robert 		}
2722ea906c41SOllivier Robert #endif
27239c2daa00SOllivier Robert 
27249c2daa00SOllivier Robert 		antenna = (buf[4] & 0xc0) >> 6;
27259c2daa00SOllivier Robert 		buf[4] &= ~0xc0;
27269c2daa00SOllivier Robert 
27279c2daa00SOllivier Robert 		i = buf[4] || buf[5];
27289c2daa00SOllivier Robert 		if (buf[2] == 'I') i = i || buf[6];
27299c2daa00SOllivier Robert 		if (i) {
27302b15cb3dSCy Schubert 			if (buf[2] == 'I')
27312b15cb3dSCy Schubert 				oncore_log_f(instance, LOG_ERR,
27322b15cb3dSCy Schubert 					     "self test failed: result %02x %02x %02x",
27332b15cb3dSCy Schubert 					     buf[4], buf[5], buf[6]);
27342b15cb3dSCy Schubert 			else
27352b15cb3dSCy Schubert 				oncore_log_f(instance, LOG_ERR,
27362b15cb3dSCy Schubert 					     "self test failed: result %02x %02x",
27372b15cb3dSCy Schubert 					     buf[4], buf[5]);
27382b15cb3dSCy Schubert 
27392b15cb3dSCy Schubert 			oncore_log(instance, LOG_ERR,
27402b15cb3dSCy Schubert 				   "ONCORE: self test failed, shutting down driver");
27419c2daa00SOllivier Robert 
27429c2daa00SOllivier Robert 			refclock_report(instance->peer, CEVNT_FAULT);
27439c2daa00SOllivier Robert 			oncore_shutdown(instance->unit, instance->peer);
27449c2daa00SOllivier Robert 			return;
27459c2daa00SOllivier Robert 		}
27469c2daa00SOllivier Robert 
27479c2daa00SOllivier Robert 		/* report the current antenna state */
27489c2daa00SOllivier Robert 
27499c2daa00SOllivier Robert 		oncore_antenna_report(instance, antenna);
27509c2daa00SOllivier Robert 
27519c2daa00SOllivier Robert 		instance->o_state = ONCORE_INIT;
27522b15cb3dSCy Schubert 		oncore_log(instance, LOG_NOTICE, "state = ONCORE_INIT");
27539c2daa00SOllivier Robert 
27549c2daa00SOllivier Robert 		instance->timeout = 4;
27552b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
27569c2daa00SOllivier Robert 	}
27579c2daa00SOllivier Robert }
27589c2daa00SOllivier Robert 
27599c2daa00SOllivier Robert 
27609c2daa00SOllivier Robert 
27619c2daa00SOllivier Robert /*
27629c2daa00SOllivier Robert  * Demultiplex the almanac into shmem
27639c2daa00SOllivier Robert  */
27649c2daa00SOllivier Robert 
27659c2daa00SOllivier Robert static void
27669c2daa00SOllivier Robert oncore_msg_Cb(
27679c2daa00SOllivier Robert 	struct instance *instance,
27689c2daa00SOllivier Robert 	u_char *buf,
27699c2daa00SOllivier Robert 	size_t len
27709c2daa00SOllivier Robert 	)
27719c2daa00SOllivier Robert {
27729c2daa00SOllivier Robert 	int i;
27739c2daa00SOllivier Robert 
27749c2daa00SOllivier Robert 	if (instance->shmem == NULL)
27759c2daa00SOllivier Robert 		return;
27769c2daa00SOllivier Robert 
27779c2daa00SOllivier Robert 	if (buf[4] == 5 && buf[5] > 0 && buf[5] < 26)
27789c2daa00SOllivier Robert 		i = buf[5];
27799c2daa00SOllivier Robert 	else if (buf[4] == 4 && buf[5] <= 5)
27809c2daa00SOllivier Robert 		i = buf[5] + 24;
27819c2daa00SOllivier Robert 	else if (buf[4] == 4 && buf[5] <= 10)
27829c2daa00SOllivier Robert 		i = buf[5] + 23;
27839c2daa00SOllivier Robert 	else if (buf[4] == 4 && buf[5] == 25)
27849c2daa00SOllivier Robert 		i = 34;
27859c2daa00SOllivier Robert 	else {
27862b15cb3dSCy Schubert 		oncore_log(instance, LOG_NOTICE, "Cb: Response is NO ALMANAC");
27879c2daa00SOllivier Robert 		return;
27889c2daa00SOllivier Robert 	}
27899c2daa00SOllivier Robert 
27909c2daa00SOllivier Robert 	i *= 36;
27919c2daa00SOllivier Robert 	instance->shmem[instance->shmem_Cb + i + 2]++;
27929c2daa00SOllivier Robert 	memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3));
27939c2daa00SOllivier Robert 
27942b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_MSG_CB
27952b15cb3dSCy Schubert 	oncore_log_f(instance, LOG_DEBUG, "See Cb [%d,%d]", buf[4],
27962b15cb3dSCy Schubert 		     buf[5]);
27979c2daa00SOllivier Robert #endif
27989c2daa00SOllivier Robert }
27999c2daa00SOllivier Robert 
28009c2daa00SOllivier Robert 
28019c2daa00SOllivier Robert 
28029c2daa00SOllivier Robert /*
28039c2daa00SOllivier Robert  * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup
28049c2daa00SOllivier Robert  *	not so for VP (eeprom) or any unit with a battery
28059c2daa00SOllivier Robert  */
28069c2daa00SOllivier Robert 
28079c2daa00SOllivier Robert static void
28089c2daa00SOllivier Robert oncore_msg_Cf(
28099c2daa00SOllivier Robert 	struct instance *instance,
28109c2daa00SOllivier Robert 	u_char *buf,
28119c2daa00SOllivier Robert 	size_t len
28129c2daa00SOllivier Robert 	)
28139c2daa00SOllivier Robert {
28149c2daa00SOllivier Robert 	if (instance->o_state == ONCORE_RESET_SENT) {
28152b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to  Posn Fix mode */
28169c2daa00SOllivier Robert 										       /* Reset set VP to IDLE */
28179c2daa00SOllivier Robert 		instance->o_state = ONCORE_TEST_SENT;
28182b15cb3dSCy Schubert 		oncore_log(instance, LOG_NOTICE, "state = ONCORE_TEST_SENT");
28199c2daa00SOllivier Robert 
28202b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
28219c2daa00SOllivier Robert 	}
28229c2daa00SOllivier Robert }
28239c2daa00SOllivier Robert 
28249c2daa00SOllivier Robert 
28259c2daa00SOllivier Robert 
28269c2daa00SOllivier Robert /*
28279c2daa00SOllivier Robert  * This is the Grand Central Station for the Preliminary Initialization.
28289c2daa00SOllivier Robert  * Once done here we move on to oncore_msg_BaEaHa for final Initialization and Running.
28299c2daa00SOllivier Robert  *
28309c2daa00SOllivier Robert  * We do an @@Cj whenever we need a safe command for all Oncores.
28319c2daa00SOllivier Robert  * The @@Cj gets us back here where we can switch to the next phase of setup.
28329c2daa00SOllivier Robert  *
28339c2daa00SOllivier Robert  * o Once at the very beginning (in start) to get the Model number.
28349c2daa00SOllivier Robert  *   This info is printed, but no longer used.
28359c2daa00SOllivier Robert  * o Again after we have determined the number of Channels in the receiver.
28369c2daa00SOllivier Robert  * o And once later after we have done a reset and test, (which may hang),
28379c2daa00SOllivier Robert  *   as we are about to initialize the Oncore and start it running.
28389c2daa00SOllivier Robert  * o We have one routine below for each case.
28399c2daa00SOllivier Robert  */
28409c2daa00SOllivier Robert 
28419c2daa00SOllivier Robert static void
28429c2daa00SOllivier Robert oncore_msg_Cj(
28439c2daa00SOllivier Robert 	struct instance *instance,
28449c2daa00SOllivier Robert 	u_char *buf,
28459c2daa00SOllivier Robert 	size_t len
28469c2daa00SOllivier Robert 	)
28479c2daa00SOllivier Robert {
28489c2daa00SOllivier Robert 	int	mode;
28499c2daa00SOllivier Robert 
28509c2daa00SOllivier Robert 	memcpy(instance->Cj, buf, len);
28519c2daa00SOllivier Robert 
28529c2daa00SOllivier Robert 	instance->timeout = 0;
28539c2daa00SOllivier Robert 	if (instance->o_state == ONCORE_CHECK_ID) {
28549c2daa00SOllivier Robert 		oncore_msg_Cj_id(instance, buf, len);
28559c2daa00SOllivier Robert 		oncore_chan_test(instance);
28569c2daa00SOllivier Robert 	} else if (instance->o_state == ONCORE_HAVE_CHAN) {
28579c2daa00SOllivier Robert 		mode = instance->init_type;
28589c2daa00SOllivier Robert 		if (mode == 3 || mode == 4) {	/* Cf will return here to check for TEST */
28599c2daa00SOllivier Robert 			instance->o_state = ONCORE_RESET_SENT;
28602b15cb3dSCy Schubert 			oncore_log(instance, LOG_NOTICE, "state = ONCORE_RESET_SENT");
28612b15cb3dSCy Schubert 			oncore_sendmsg(instance, oncore_cmd_Cf, sizeof(oncore_cmd_Cf));
28629c2daa00SOllivier Robert 		} else {
28639c2daa00SOllivier Robert 			instance->o_state = ONCORE_TEST_SENT;
28642b15cb3dSCy Schubert 			oncore_log(instance, LOG_NOTICE, "state = ONCORE_TEST_SENT");
28659c2daa00SOllivier Robert 		}
28669c2daa00SOllivier Robert 	}
28679c2daa00SOllivier Robert 
28689c2daa00SOllivier Robert 	if (instance->o_state == ONCORE_TEST_SENT) {
28699c2daa00SOllivier Robert 		if (instance->chan == 6)
28702b15cb3dSCy Schubert 			oncore_sendmsg(instance, oncore_cmd_Ca, sizeof(oncore_cmd_Ca));
28719c2daa00SOllivier Robert 		else if (instance->chan == 8)
28722b15cb3dSCy Schubert 			oncore_sendmsg(instance, oncore_cmd_Fa, sizeof(oncore_cmd_Fa));
28739c2daa00SOllivier Robert 		else if (instance->chan == 12)
28742b15cb3dSCy Schubert 			oncore_sendmsg(instance, oncore_cmd_Ia, sizeof(oncore_cmd_Ia));
28759c2daa00SOllivier Robert 	} else if (instance->o_state == ONCORE_INIT)
28769c2daa00SOllivier Robert 		oncore_msg_Cj_init(instance, buf, len);
28779c2daa00SOllivier Robert }
28789c2daa00SOllivier Robert 
28799c2daa00SOllivier Robert 
28809c2daa00SOllivier Robert 
28819c2daa00SOllivier Robert /* The information on determining a Oncore 'Model', viz VP, UT, etc, from
28829c2daa00SOllivier Robert  *	the Model Number comes from "Richard M. Hambly" <rick@cnssys.com>
28839c2daa00SOllivier Robert  *	and from Motorola.  Until recently Rick was the only source of
28849c2daa00SOllivier Robert  *	this information as Motorola didn't give the information out.
28859c2daa00SOllivier Robert  *
28869c2daa00SOllivier Robert  * Determine the Type from the Model #, this determines #chan and if TRAIM is
28879c2daa00SOllivier Robert  *   available.
28889c2daa00SOllivier Robert  *
28899c2daa00SOllivier Robert  * The Information from this routine is NO LONGER USED.
28909c2daa00SOllivier Robert  * The RESULTS are PRINTED, BUT NOT USED, and the routine COULD BE DELETED
28919c2daa00SOllivier Robert  */
28929c2daa00SOllivier Robert 
28939c2daa00SOllivier Robert static void
28949c2daa00SOllivier Robert oncore_msg_Cj_id(
28959c2daa00SOllivier Robert 	struct instance *instance,
28969c2daa00SOllivier Robert 	u_char *buf,
28979c2daa00SOllivier Robert 	size_t len
28989c2daa00SOllivier Robert 	)
28999c2daa00SOllivier Robert {
29002b15cb3dSCy Schubert 	char *cp2, Model[21];
29012b15cb3dSCy Schubert 	const char *cp, *cp1;
29029c2daa00SOllivier Robert 
29039c2daa00SOllivier Robert 	/* Write Receiver ID message to clockstats file */
29049c2daa00SOllivier Robert 
29059c2daa00SOllivier Robert 	instance->Cj[294] = '\0';
29069c2daa00SOllivier Robert 	for (cp= (char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) {
29072b15cb3dSCy Schubert 		char *cpw = strchr(cp, '\r');
29082b15cb3dSCy Schubert 		if (!cpw)
29092b15cb3dSCy Schubert 			cpw = (char *)&instance->Cj[294];
29102b15cb3dSCy Schubert 		*cpw = '\0';
29112b15cb3dSCy Schubert 		oncore_log(instance, LOG_NOTICE, cp);
29122b15cb3dSCy Schubert 		*cpw = '\r';
29132b15cb3dSCy Schubert 		cp = cpw+2;
29149c2daa00SOllivier Robert 	}
29159c2daa00SOllivier Robert 
29169c2daa00SOllivier Robert 	/* next, the Firmware Version and Revision numbers */
29179c2daa00SOllivier Robert 
2918ea906c41SOllivier Robert 	instance->version  = atoi((char *) &instance->Cj[83]);
2919ea906c41SOllivier Robert 	instance->revision = atoi((char *) &instance->Cj[111]);
29209c2daa00SOllivier Robert 
29219c2daa00SOllivier Robert 	/* from model number decide which Oncore this is,
29229c2daa00SOllivier Robert 		and then the number of channels */
29239c2daa00SOllivier Robert 
2924ea906c41SOllivier Robert 	for (cp= (char *) &instance->Cj[160]; *cp == ' '; cp++)   /* start right after 'Model #' */
29259c2daa00SOllivier Robert 		;
29269c2daa00SOllivier Robert 	cp1 = cp;
29279c2daa00SOllivier Robert 	cp2 = Model;
29282b15cb3dSCy Schubert 	for (; !isspace((unsigned char)*cp) && cp-cp1 < 20; cp++, cp2++)
29299c2daa00SOllivier Robert 		*cp2 = *cp;
29309c2daa00SOllivier Robert 	*cp2 = '\0';
29319c2daa00SOllivier Robert 
29329c2daa00SOllivier Robert 	cp = 0;
29339c2daa00SOllivier Robert 	if (!strncmp(Model, "PVT6", (size_t) 4)) {
29349c2daa00SOllivier Robert 		cp = "PVT6";
29359c2daa00SOllivier Robert 		instance->model = ONCORE_PVT6;
29369c2daa00SOllivier Robert 	} else if (Model[0] == 'A') {
29379c2daa00SOllivier Robert 		cp = "Basic";
29389c2daa00SOllivier Robert 		instance->model = ONCORE_BASIC;
29399c2daa00SOllivier Robert 	} else if (Model[0] == 'B' || !strncmp(Model, "T8", (size_t) 2)) {
29409c2daa00SOllivier Robert 		cp = "VP";
29419c2daa00SOllivier Robert 		instance->model = ONCORE_VP;
29429c2daa00SOllivier Robert 	} else if (Model[0] == 'P') {
29439c2daa00SOllivier Robert 		cp = "M12";
29449c2daa00SOllivier Robert 		instance->model = ONCORE_M12;
29459c2daa00SOllivier Robert 	} else if (Model[0] == 'R' || Model[0] == 'D' || Model[0] == 'S') {
29469c2daa00SOllivier Robert 		if (Model[5] == 'N') {
29479c2daa00SOllivier Robert 			cp = "GT";
29489c2daa00SOllivier Robert 			instance->model = ONCORE_GT;
29499c2daa00SOllivier Robert 		} else if ((Model[1] == '3' || Model[1] == '4') && Model[5] == 'G') {
29509c2daa00SOllivier Robert 			cp = "GT+";
29519c2daa00SOllivier Robert 			instance->model = ONCORE_GTPLUS;
29529c2daa00SOllivier Robert 		} else if ((Model[1] == '5' && Model[5] == 'U') || (Model[1] == '1' && Model[5] == 'A')) {
29539c2daa00SOllivier Robert 				cp = "UT";
29549c2daa00SOllivier Robert 				instance->model = ONCORE_UT;
29559c2daa00SOllivier Robert 		} else if (Model[1] == '5' && Model[5] == 'G') {
29569c2daa00SOllivier Robert 			cp = "UT+";
29579c2daa00SOllivier Robert 			instance->model = ONCORE_UTPLUS;
29589c2daa00SOllivier Robert 		} else if (Model[1] == '6' && Model[5] == 'G') {
29599c2daa00SOllivier Robert 			cp = "SL";
29609c2daa00SOllivier Robert 			instance->model = ONCORE_SL;
29619c2daa00SOllivier Robert 		} else {
29629c2daa00SOllivier Robert 			cp = "Unknown";
29639c2daa00SOllivier Robert 			instance->model = ONCORE_UNKNOWN;
29649c2daa00SOllivier Robert 		}
29659c2daa00SOllivier Robert 	} else	{
29669c2daa00SOllivier Robert 		cp = "Unknown";
29679c2daa00SOllivier Robert 		instance->model = ONCORE_UNKNOWN;
29689c2daa00SOllivier Robert 	}
29699c2daa00SOllivier Robert 
29709c2daa00SOllivier Robert 	/* use MODEL to set CHAN and TRAIM and possibly zero SHMEM */
29719c2daa00SOllivier Robert 
29722b15cb3dSCy Schubert 	oncore_log_f(instance, LOG_INFO,
29732b15cb3dSCy Schubert 		     "This looks like an Oncore %s with version %d.%d firmware.",
29742b15cb3dSCy Schubert 		     cp, instance->version, instance->revision);
29759c2daa00SOllivier Robert 
29769c2daa00SOllivier Robert 	instance->chan_id = 8;	   /* default */
29779c2daa00SOllivier Robert 	if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
29789c2daa00SOllivier Robert 		instance->chan_id = 6;
29799c2daa00SOllivier Robert 	else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS)
29809c2daa00SOllivier Robert 		instance->chan_id = 8;
29819c2daa00SOllivier Robert 	else if (instance->model == ONCORE_M12)
29829c2daa00SOllivier Robert 		instance->chan_id = 12;
29839c2daa00SOllivier Robert 
29849c2daa00SOllivier Robert 	instance->traim_id = 0;    /* default */
29859c2daa00SOllivier Robert 	if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
29869c2daa00SOllivier Robert 		instance->traim_id = 0;
29879c2daa00SOllivier Robert 	else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS)
29889c2daa00SOllivier Robert 		instance->traim_id = 1;
29899c2daa00SOllivier Robert 	else if (instance->model == ONCORE_M12)
29909c2daa00SOllivier Robert 		instance->traim_id = -1;
29919c2daa00SOllivier Robert 
29922b15cb3dSCy Schubert 	oncore_log_f(instance, LOG_INFO, "Channels = %d, TRAIM = %s",
29932b15cb3dSCy Schubert 		     instance->chan_id,
29942b15cb3dSCy Schubert 		     ((instance->traim_id < 0)
29952b15cb3dSCy Schubert 			  ? "UNKNOWN"
29962b15cb3dSCy Schubert 			  : (instance->traim_id > 0)
29972b15cb3dSCy Schubert 				? "ON"
29982b15cb3dSCy Schubert 				: "OFF"));
29999c2daa00SOllivier Robert }
30009c2daa00SOllivier Robert 
30019c2daa00SOllivier Robert 
30029c2daa00SOllivier Robert 
30039c2daa00SOllivier Robert /* OK, know type of Oncore, have possibly reset it, and have tested it.
30049c2daa00SOllivier Robert  * We know the number of channels.
30059c2daa00SOllivier Robert  * We will determine whether we have TRAIM before we actually start.
30069c2daa00SOllivier Robert  * Now initialize.
30079c2daa00SOllivier Robert  */
30089c2daa00SOllivier Robert 
30099c2daa00SOllivier Robert static void
30109c2daa00SOllivier Robert oncore_msg_Cj_init(
30119c2daa00SOllivier Robert 	struct instance *instance,
30129c2daa00SOllivier Robert 	u_char *buf,
30139c2daa00SOllivier Robert 	size_t len
30149c2daa00SOllivier Robert 	)
30159c2daa00SOllivier Robert {
3016ea906c41SOllivier Robert 	u_char	Cmd[20];
30179c2daa00SOllivier Robert 	int	mode;
30189c2daa00SOllivier Robert 
30199c2daa00SOllivier Robert 
30209c2daa00SOllivier Robert 	/* The M12 with 1.3 or 2.0 Firmware, loses track of all Satellites and has to
30219c2daa00SOllivier Robert 	 * start again if we go from 0D -> 3D, then loses them again when we
30229c2daa00SOllivier Robert 	 * go from 3D -> 0D.  We do this to get a @@Ea message for SHMEM.
30239c2daa00SOllivier Robert 	 * For NOW we will turn this aspect of filling SHMEM off for the M12
30249c2daa00SOllivier Robert 	 */
30259c2daa00SOllivier Robert 
30269c2daa00SOllivier Robert 	if (instance->chan == 12) {
30279c2daa00SOllivier Robert 		instance->shmem_bad_Ea = 1;
30282b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_NOTICE,
30292b15cb3dSCy Schubert 			     "*** SHMEM partially enabled for ONCORE M12 s/w v%d.%d ***",
30302b15cb3dSCy Schubert 			     instance->version, instance->revision);
30319c2daa00SOllivier Robert 	}
30329c2daa00SOllivier Robert 
30332b15cb3dSCy Schubert 	oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to  Posn Fix mode */
30342b15cb3dSCy Schubert 	oncore_sendmsg(instance, oncore_cmd_Bb, sizeof(oncore_cmd_Bb)); /* turn on for shmem (6/8/12) */
30352b15cb3dSCy Schubert 	oncore_sendmsg(instance, oncore_cmd_Ek, sizeof(oncore_cmd_Ek)); /* turn off (VP) */
30362b15cb3dSCy Schubert 	oncore_sendmsg(instance, oncore_cmd_Aw, sizeof(oncore_cmd_Aw)); /* UTC time (6/8/12) */
30372b15cb3dSCy Schubert 	oncore_sendmsg(instance, oncore_cmd_AB, sizeof(oncore_cmd_AB)); /* Appl type static (VP) */
30382b15cb3dSCy Schubert 	oncore_sendmsg(instance, oncore_cmd_Be, sizeof(oncore_cmd_Be)); /* Tell us the Almanac for shmem (6/8/12) */
30392b15cb3dSCy Schubert 	oncore_sendmsg(instance, oncore_cmd_Bd, sizeof(oncore_cmd_Bd)); /* Tell us when Almanac changes */
30409c2daa00SOllivier Robert 
30419c2daa00SOllivier Robert 	mode = instance->init_type;
30429c2daa00SOllivier Robert 
30439c2daa00SOllivier Robert 	/* If there is Position input in the Config file
30449c2daa00SOllivier Robert 	 * and mode = (1,3) set it as posn hold posn, goto 0D mode.
30459c2daa00SOllivier Robert 	 *  or mode = (2,4) set it as INITIAL position, and do Site Survey.
30469c2daa00SOllivier Robert 	 */
30479c2daa00SOllivier Robert 
30489c2daa00SOllivier Robert 	if (instance->posn_set) {
30492b15cb3dSCy Schubert 		oncore_log(instance, LOG_INFO, "Setting Posn from input data");
30509c2daa00SOllivier Robert 		oncore_set_posn(instance);	/* this should print posn indirectly thru the As cmd */
30519c2daa00SOllivier Robert 	} else	/* must issue an @@At here to check on 6/8 Position Hold, set_posn would have */
30529c2daa00SOllivier Robert 		if (instance->chan != 12)
30532b15cb3dSCy Schubert 			oncore_sendmsg(instance, oncore_cmd_Atx, sizeof(oncore_cmd_Atx));
30549c2daa00SOllivier Robert 
30559c2daa00SOllivier Robert 	if (mode != 0) {
30569c2daa00SOllivier Robert 			/* cable delay in ns */
30579c2daa00SOllivier Robert 		memcpy(Cmd, oncore_cmd_Az, (size_t) sizeof(oncore_cmd_Az));
30582b15cb3dSCy Schubert 		w32_buf(&Cmd[-2+4], (int)instance->delay);
30592b15cb3dSCy Schubert 		oncore_sendmsg(instance, Cmd,  sizeof(oncore_cmd_Az));	/* 6,8,12 */
30609c2daa00SOllivier Robert 
30619c2daa00SOllivier Robert 			/* PPS offset in ns */
30629c2daa00SOllivier Robert 		memcpy(Cmd, oncore_cmd_Ay, (size_t) sizeof(oncore_cmd_Ay));	/* some have it, some don't */
30639c2daa00SOllivier Robert 		w32_buf(&Cmd[-2+4], instance->offset);			/* will check for hw response */
30642b15cb3dSCy Schubert 		oncore_sendmsg(instance, Cmd,  sizeof(oncore_cmd_Ay));
30659c2daa00SOllivier Robert 
30669c2daa00SOllivier Robert 		/* Satellite mask angle */
30679c2daa00SOllivier Robert 
30689c2daa00SOllivier Robert 		if (instance->Ag != 0xff) {	/* will have 0xff in it if not set by user */
30699c2daa00SOllivier Robert 			memcpy(Cmd, oncore_cmd_Ag, (size_t) sizeof(oncore_cmd_Ag));
30709c2daa00SOllivier Robert 			Cmd[-2+4] = instance->Ag;
30712b15cb3dSCy Schubert 			oncore_sendmsg(instance, Cmd,  sizeof(oncore_cmd_Ag));
30729c2daa00SOllivier Robert 		}
30739c2daa00SOllivier Robert 	}
30749c2daa00SOllivier Robert 
30759c2daa00SOllivier Robert 	/* 6, 8 12 chan - Position/Status/Data Output Message, 1/s
30769c2daa00SOllivier Robert 	 * now we're really running
30779c2daa00SOllivier Robert 	 * these were ALL started in the chan test,
30789c2daa00SOllivier Robert 	 * However, if we had mode=3,4 then commands got turned off, so we turn
30799c2daa00SOllivier Robert 	 * them on again here just in case
30809c2daa00SOllivier Robert 	 */
30819c2daa00SOllivier Robert 
30829c2daa00SOllivier Robert 	if (instance->chan == 6) { /* start 6chan, kill 8,12chan commands, possibly testing VP in 6chan mode */
30832b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0));
30842b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_En0, sizeof(oncore_cmd_En0));
30852b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0));
30862b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
30872b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Ba, sizeof(oncore_cmd_Ba ));
30889c2daa00SOllivier Robert 	} else if (instance->chan == 8) {  /* start 8chan, kill 6,12chan commands */
30892b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0));
30902b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0));
30912b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0));
30922b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
30932b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Ea, sizeof(oncore_cmd_Ea ));
30949c2daa00SOllivier Robert 	} else if (instance->chan == 12){  /* start 12chan, kill 6,12chan commands */
30952b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0));
30962b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0));
30972b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0));
30982b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_En0, sizeof(oncore_cmd_En0));
30992b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Ha, sizeof(oncore_cmd_Ha ));
31002b15cb3dSCy Schubert 		oncore_cmd_Gc[2] = (instance->pps_control < 0) ? 1 : instance->pps_control;
31012b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Gc, sizeof(oncore_cmd_Gc)); /* PPS off/continuous/Tracking 1+sat/TRAIM */
31029c2daa00SOllivier Robert 	}
31039c2daa00SOllivier Robert 
31049c2daa00SOllivier Robert 	instance->count = 1;
31059c2daa00SOllivier Robert 	instance->o_state = ONCORE_ALMANAC;
31062b15cb3dSCy Schubert 	oncore_log(instance, LOG_NOTICE, "state = ONCORE_ALMANAC");
31079c2daa00SOllivier Robert }
31089c2daa00SOllivier Robert 
31099c2daa00SOllivier Robert 
31109c2daa00SOllivier Robert 
31119c2daa00SOllivier Robert /* 12chan position */
31129c2daa00SOllivier Robert 
31139c2daa00SOllivier Robert static void
31149c2daa00SOllivier Robert oncore_msg_Ga(
31159c2daa00SOllivier Robert 	struct instance *instance,
31169c2daa00SOllivier Robert 	u_char *buf,
31179c2daa00SOllivier Robert 	size_t len
31189c2daa00SOllivier Robert 	)
31199c2daa00SOllivier Robert {
31209c2daa00SOllivier Robert 	long lat, lon, ht;
31219c2daa00SOllivier Robert 	double Lat, Lon, Ht;
31229c2daa00SOllivier Robert 
31239c2daa00SOllivier Robert 
31249c2daa00SOllivier Robert 	lat = buf_w32(&buf[4]);
31259c2daa00SOllivier Robert 	lon = buf_w32(&buf[8]);
31269c2daa00SOllivier Robert 	ht  = buf_w32(&buf[12]);  /* GPS ellipsoid */
31279c2daa00SOllivier Robert 
31289c2daa00SOllivier Robert 	Lat = lat;
31299c2daa00SOllivier Robert 	Lon = lon;
31309c2daa00SOllivier Robert 	Ht  = ht;
31319c2daa00SOllivier Robert 
31329c2daa00SOllivier Robert 	Lat /= 3600000;
31339c2daa00SOllivier Robert 	Lon /= 3600000;
31349c2daa00SOllivier Robert 	Ht  /= 100;
31359c2daa00SOllivier Robert 
31362b15cb3dSCy Schubert 	oncore_log_f(instance, LOG_NOTICE,
31372b15cb3dSCy Schubert 		     "Ga Posn Lat = %.7f, Lon = %.7f, Ht  = %.2f", Lat,
31382b15cb3dSCy Schubert 		     Lon, Ht);
31399c2daa00SOllivier Robert 
31409c2daa00SOllivier Robert 	instance->ss_lat  = lat;
31419c2daa00SOllivier Robert 	instance->ss_long = lon;
31429c2daa00SOllivier Robert 	instance->ss_ht   = ht;
31439c2daa00SOllivier Robert 
31449c2daa00SOllivier Robert 	oncore_print_posn(instance);
31459c2daa00SOllivier Robert }
31469c2daa00SOllivier Robert 
31479c2daa00SOllivier Robert 
31489c2daa00SOllivier Robert 
31499c2daa00SOllivier Robert /* 12 chan time/date */
31509c2daa00SOllivier Robert 
31519c2daa00SOllivier Robert static void
31529c2daa00SOllivier Robert oncore_msg_Gb(
31539c2daa00SOllivier Robert 	struct instance *instance,
31549c2daa00SOllivier Robert 	u_char *buf,
31559c2daa00SOllivier Robert 	size_t len
31569c2daa00SOllivier Robert 	)
31579c2daa00SOllivier Robert {
31582b15cb3dSCy Schubert 	const char *	gmts;
31599c2daa00SOllivier Robert 	int	mo, d, y, h, m, s, gmth, gmtm;
31609c2daa00SOllivier Robert 
31619c2daa00SOllivier Robert 	mo = buf[4];
31629c2daa00SOllivier Robert 	d  = buf[5];
31639c2daa00SOllivier Robert 	y  = 256*buf[6]+buf[7];
31649c2daa00SOllivier Robert 
31659c2daa00SOllivier Robert 	h  = buf[8];
31669c2daa00SOllivier Robert 	m  = buf[9];
31679c2daa00SOllivier Robert 	s  = buf[10];
31689c2daa00SOllivier Robert 
31699c2daa00SOllivier Robert 	gmts = ((buf[11] == 0) ? "+" : "-");
31709c2daa00SOllivier Robert 	gmth = buf[12];
31719c2daa00SOllivier Robert 	gmtm = buf[13];
31729c2daa00SOllivier Robert 
31732b15cb3dSCy Schubert 	oncore_log_f(instance, LOG_NOTICE,
31742b15cb3dSCy Schubert 		     "Date/Time set to: %d%s%d %2d:%02d:%02d GMT (GMT offset is %s%02d:%02d)",
31752b15cb3dSCy Schubert 		     d, months[mo-1], y, h, m, s, gmts, gmth, gmtm);
31762b15cb3dSCy Schubert }
31772b15cb3dSCy Schubert 
31782b15cb3dSCy Schubert 
31792b15cb3dSCy Schubert 
31802b15cb3dSCy Schubert /* Response to PPS Control message (M12 and M12+T only ) */
31812b15cb3dSCy Schubert 
31822b15cb3dSCy Schubert static void
31832b15cb3dSCy Schubert oncore_msg_Gc(
31842b15cb3dSCy Schubert 	struct instance *instance,
31852b15cb3dSCy Schubert 	u_char *buf,
31862b15cb3dSCy Schubert 	size_t len
31872b15cb3dSCy Schubert 	)
31882b15cb3dSCy Schubert {
31892b15cb3dSCy Schubert 	const char *tbl[] = {"OFF", "ON", "SATELLITE", "TRAIM" };
31902b15cb3dSCy Schubert 
31912b15cb3dSCy Schubert 	instance->pps_control_msg_seen = 1;
31922b15cb3dSCy Schubert 	oncore_log_f(instance, LOG_INFO, "PPS Control set to %s",
31932b15cb3dSCy Schubert 		     tbl[buf[4]]);
31949c2daa00SOllivier Robert }
31959c2daa00SOllivier Robert 
31969c2daa00SOllivier Robert 
31979c2daa00SOllivier Robert 
3198224ba2bdSOllivier Robert /* Leap Second for M12, gives all info from satellite message */
31999c2daa00SOllivier Robert /* also in UT v3.0 */
3200224ba2bdSOllivier Robert 
3201224ba2bdSOllivier Robert static void
3202224ba2bdSOllivier Robert oncore_msg_Gj(
3203224ba2bdSOllivier Robert 	struct instance *instance,
3204224ba2bdSOllivier Robert 	u_char *buf,
3205224ba2bdSOllivier Robert 	size_t len
3206224ba2bdSOllivier Robert 	)
3207224ba2bdSOllivier Robert {
32082b15cb3dSCy Schubert 	static const char * insrem[2] = {
32092b15cb3dSCy Schubert 		"removed",
32102b15cb3dSCy Schubert 		"inserted"
32112b15cb3dSCy Schubert 	};
32122b15cb3dSCy Schubert 
3213224ba2bdSOllivier Robert 	int dt;
32142b15cb3dSCy Schubert 	const char *cp;
32159c2daa00SOllivier Robert 
32169c2daa00SOllivier Robert 	instance->saw_Gj = 1; /* flag, saw_Gj, dont need to try Bj in check_leap */
3217224ba2bdSOllivier Robert 
3218224ba2bdSOllivier Robert 	/* print the message to verify whats there */
3219224ba2bdSOllivier Robert 
3220224ba2bdSOllivier Robert 	dt = buf[5] - buf[4];
3221224ba2bdSOllivier Robert 
32222b15cb3dSCy Schubert 	oncore_log_f(instance, LOG_INFO,
32232b15cb3dSCy Schubert 		     "Leap Sec Msg: %d %d %d %d %d %d %d %d %d %d",
32242b15cb3dSCy Schubert 		     buf[4], buf[5], 256 * buf[6] + buf[7], buf[8],
32252b15cb3dSCy Schubert 		     buf[9], buf[10],
32262b15cb3dSCy Schubert 		     (buf[14] + 256 *
32272b15cb3dSCy Schubert 		         (buf[13] + 256 * (buf[12] + 256 * buf[11]))),
3228224ba2bdSOllivier Robert 		     buf[15], buf[16], buf[17]);
32292b15cb3dSCy Schubert 
32302b15cb3dSCy Schubert 	/* There seems to be eternal confusion about when a leap second
32312b15cb3dSCy Schubert 	 * takes place. It's the second *before* the new TAI offset
32322b15cb3dSCy Schubert 	 * becomes effective. But since the ONCORE receiver tells us
32332b15cb3dSCy Schubert 	 * just that, we would have to do some time/date calculations to
32342b15cb3dSCy Schubert 	 * get the actual leap second -- that is, the one that is
32352b15cb3dSCy Schubert 	 * deleted or inserted.
32362b15cb3dSCy Schubert 	 *
32372b15cb3dSCy Schubert 	 * Going through all this for a simple log is probably overkill,
32382b15cb3dSCy Schubert 	 * so for fixing bug#1050 the message output is changed to
32392b15cb3dSCy Schubert 	 * reflect the fact that it tells the second after the leap
32402b15cb3dSCy Schubert 	 * second.
32412b15cb3dSCy Schubert 	 */
32422b15cb3dSCy Schubert 	if (dt)
32432b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_NOTICE,
32442b15cb3dSCy Schubert 			     "Leap second %s (%d) before %04u-%02u-%02u/%02u:%02u:%02u",
32452b15cb3dSCy Schubert 			     insrem[(dt > 0)], dt,
32462b15cb3dSCy Schubert 			     256u * buf[6] + buf[7], buf[8], buf[9],
3247224ba2bdSOllivier Robert 			     buf[15], buf[16], buf[17]);
3248224ba2bdSOllivier Robert 
3249224ba2bdSOllivier Robert 	/* Only raise warning within a month of the leap second */
3250224ba2bdSOllivier Robert 
3251ea906c41SOllivier Robert 	instance->pp->leap = LEAP_NOWARNING;
3252ea906c41SOllivier Robert 	cp = "Set pp.leap to LEAP_NOWARNING";
3253224ba2bdSOllivier Robert 
32549c2daa00SOllivier Robert 	if (buf[6] == instance->BEHa[6] && buf[7] == instance->BEHa[7] && /* year */
32559c2daa00SOllivier Robert 	    buf[8] == instance->BEHa[4]) {	/* month */
3256224ba2bdSOllivier Robert 		if (dt) {
3257224ba2bdSOllivier Robert 			if (dt < 0) {
3258ea906c41SOllivier Robert 				instance->pp->leap = LEAP_DELSECOND;
3259ea906c41SOllivier Robert 				cp = "Set pp.leap to LEAP_DELSECOND";
3260224ba2bdSOllivier Robert 			} else {
3261ea906c41SOllivier Robert 				instance->pp->leap = LEAP_ADDSECOND;
3262ea906c41SOllivier Robert 				cp = "Set pp.leap to LEAP_ADDSECOND";
3263224ba2bdSOllivier Robert 			}
3264224ba2bdSOllivier Robert 		}
3265224ba2bdSOllivier Robert 	}
32662b15cb3dSCy Schubert 	oncore_log(instance, LOG_INFO, cp);
3267224ba2bdSOllivier Robert }
3268224ba2bdSOllivier Robert 
3269c0b746e5SOllivier Robert 
3270c0b746e5SOllivier Robert 
32719c2daa00SOllivier Robert /* Power on failure */
3272224ba2bdSOllivier Robert 
3273c0b746e5SOllivier Robert static void
32749c2daa00SOllivier Robert oncore_msg_Sz(
3275c0b746e5SOllivier Robert 	struct instance *instance,
3276c0b746e5SOllivier Robert 	u_char *buf,
3277224ba2bdSOllivier Robert 	size_t len
3278c0b746e5SOllivier Robert 	)
3279c0b746e5SOllivier Robert {
32809c2daa00SOllivier Robert 	if (instance && instance->peer) {
32812b15cb3dSCy Schubert 		oncore_log(instance, LOG_ERR, "Oncore: System Failure at Power On");
32829c2daa00SOllivier Robert 		oncore_shutdown(instance->unit, instance->peer);
32839c2daa00SOllivier Robert 	}
32849c2daa00SOllivier Robert }
32859c2daa00SOllivier Robert 
32869c2daa00SOllivier Robert /************** Small Subroutines ***************/
32879c2daa00SOllivier Robert 
32889c2daa00SOllivier Robert 
32899c2daa00SOllivier Robert static void
32909c2daa00SOllivier Robert oncore_antenna_report(
32919c2daa00SOllivier Robert 	struct instance *instance,
32929c2daa00SOllivier Robert 	enum antenna_state new_state)
32939c2daa00SOllivier Robert {
32942b15cb3dSCy Schubert 	const char *cp;
32959c2daa00SOllivier Robert 
32969c2daa00SOllivier Robert 	if (instance->ant_state == new_state)
3297c0b746e5SOllivier Robert 		return;
3298c0b746e5SOllivier Robert 
32999c2daa00SOllivier Robert 	switch (new_state) {
33009c2daa00SOllivier Robert 	case ONCORE_ANTENNA_OK: cp = "GPS antenna: OK";                   break;
33019c2daa00SOllivier Robert 	case ONCORE_ANTENNA_OC: cp = "GPS antenna: short (overcurrent)";  break;
33029c2daa00SOllivier Robert 	case ONCORE_ANTENNA_UC: cp = "GPS antenna: open (not connected)"; break;
33039c2daa00SOllivier Robert 	case ONCORE_ANTENNA_NV: cp = "GPS antenna: short (no voltage)";   break;
33049c2daa00SOllivier Robert 	default:		cp = "GPS antenna: ?";                    break;
33059c2daa00SOllivier Robert 	}
3306c0b746e5SOllivier Robert 
33079c2daa00SOllivier Robert 	instance->ant_state = new_state;
33082b15cb3dSCy Schubert 	oncore_log(instance, LOG_NOTICE, cp);
3309224ba2bdSOllivier Robert }
3310224ba2bdSOllivier Robert 
3311224ba2bdSOllivier Robert 
3312224ba2bdSOllivier Robert 
3313224ba2bdSOllivier Robert static void
33149c2daa00SOllivier Robert oncore_chan_test(
33159c2daa00SOllivier Robert 	struct instance *instance
33169c2daa00SOllivier Robert 	)
33179c2daa00SOllivier Robert {
33189c2daa00SOllivier Robert 	/* subroutine oncore_Cj_id has determined the number of channels from the
33199c2daa00SOllivier Robert 	 * model number of the attached oncore.  This is not always correct since
33209c2daa00SOllivier Robert 	 * the oncore could have non-standard firmware.  Here we check (independently) by
33219c2daa00SOllivier Robert 	 * trying a 6, 8, and 12 chan command, and see which responds.
33229c2daa00SOllivier Robert 	 * Caution: more than one CAN respond.
33239c2daa00SOllivier Robert 	 *
33249c2daa00SOllivier Robert 	 * This #chan is used by the code rather than that calculated from the model number.
33259c2daa00SOllivier Robert 	 */
33269c2daa00SOllivier Robert 
33279c2daa00SOllivier Robert 	instance->o_state = ONCORE_CHECK_CHAN;
33282b15cb3dSCy Schubert 	oncore_log(instance, LOG_NOTICE, "state = ONCORE_CHECK_CHAN");
33299c2daa00SOllivier Robert 
33309c2daa00SOllivier Robert 	instance->count3 = 1;
33312b15cb3dSCy Schubert 	oncore_sendmsg(instance, oncore_cmd_Ba, sizeof(oncore_cmd_Ba));
33322b15cb3dSCy Schubert 	oncore_sendmsg(instance, oncore_cmd_Ea, sizeof(oncore_cmd_Ea));
33332b15cb3dSCy Schubert 	oncore_sendmsg(instance, oncore_cmd_Ha, sizeof(oncore_cmd_Ha));
33349c2daa00SOllivier Robert }
33359c2daa00SOllivier Robert 
33369c2daa00SOllivier Robert 
33379c2daa00SOllivier Robert 
33389c2daa00SOllivier Robert /* check for a GOOD Almanac, have we got one yet? */
33399c2daa00SOllivier Robert 
33409c2daa00SOllivier Robert static void
33419c2daa00SOllivier Robert oncore_check_almanac(
33429c2daa00SOllivier Robert 	struct instance *instance
33439c2daa00SOllivier Robert 	)
33449c2daa00SOllivier Robert {
33459c2daa00SOllivier Robert 	if (instance->chan == 6) {
33469c2daa00SOllivier Robert 		instance->rsm.bad_almanac = instance->BEHa[64]&0x1;
33479c2daa00SOllivier Robert 		instance->rsm.bad_fix	  = instance->BEHa[64]&0x52;
33489c2daa00SOllivier Robert 	} else if (instance->chan == 8) {
33499c2daa00SOllivier Robert 		instance->rsm.bad_almanac = instance->BEHa[72]&0x1;
33509c2daa00SOllivier Robert 		instance->rsm.bad_fix	  = instance->BEHa[72]&0x52;
33519c2daa00SOllivier Robert 	} else if (instance->chan == 12) {
3352ea906c41SOllivier Robert 		int bits1, bits2, bits3;
33539c2daa00SOllivier Robert 
33549c2daa00SOllivier Robert 		bits1 = (instance->BEHa[129]>>5) & 0x7; 	/* actually Ha */
33559c2daa00SOllivier Robert 		bits2 = instance->BEHa[130];
33569c2daa00SOllivier Robert 		instance->rsm.bad_almanac = (bits2 & 0x80);
33579c2daa00SOllivier Robert 		instance->rsm.bad_fix	  = (bits2 & 0x8) || (bits1 == 0x2);
33589c2daa00SOllivier Robert 					  /* too few sat     Bad Geom	  */
3359ea906c41SOllivier Robert 
3360ea906c41SOllivier Robert 		bits3 = instance->BEHa[141];	/* UTC parameters */
3361ea906c41SOllivier Robert 		if (!instance->count5_set && (bits3 & 0xC0)) {
33622b15cb3dSCy Schubert 			instance->count5 = 4;	/* was 2 [Bug 1766] */
3363ea906c41SOllivier Robert 			instance->count5_set = 1;
3364ea906c41SOllivier Robert 		}
33652b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_CHECK_ALMANAC
33662b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_DEBUG,
33672b15cb3dSCy Schubert 			     "DEBUG BITS: (%x %x), (%x %x %x),  %x %x %x %x %x",
33682b15cb3dSCy Schubert 			     instance->BEHa[129], instance->BEHa[130],
33692b15cb3dSCy Schubert 			     bits1, bits2, bits3,
33702b15cb3dSCy Schubert 			     instance->mode == MODE_0D,
33712b15cb3dSCy Schubert 			     instance->mode == MODE_2D,
33722b15cb3dSCy Schubert 			     instance->mode == MODE_3D,
33732b15cb3dSCy Schubert 			     instance->rsm.bad_almanac,
33742b15cb3dSCy Schubert 			     instance->rsm.bad_fix);
3375ea906c41SOllivier Robert 		}
33769c2daa00SOllivier Robert #endif
33779c2daa00SOllivier Robert 	}
33789c2daa00SOllivier Robert }
33799c2daa00SOllivier Robert 
33809c2daa00SOllivier Robert 
33819c2daa00SOllivier Robert 
33829c2daa00SOllivier Robert /* check the antenna for changes (did it get unplugged?) */
33839c2daa00SOllivier Robert 
33849c2daa00SOllivier Robert static void
33859c2daa00SOllivier Robert oncore_check_antenna(
33869c2daa00SOllivier Robert 	struct instance *instance
33879c2daa00SOllivier Robert 	)
33889c2daa00SOllivier Robert {
33899c2daa00SOllivier Robert 	enum antenna_state antenna;		/* antenna state */
33909c2daa00SOllivier Robert 
33919c2daa00SOllivier Robert 	if (instance->chan == 12)
33929c2daa00SOllivier Robert 		antenna = (instance->BEHa[130] & 0x6 ) >> 1;
33939c2daa00SOllivier Robert 	else
33949c2daa00SOllivier Robert 		antenna = (instance->BEHa[37] & 0xc0) >> 6;  /* prob unset 6, set GT, UT unset VP */
33959c2daa00SOllivier Robert 
33969c2daa00SOllivier Robert 	oncore_antenna_report (instance, antenna);
33979c2daa00SOllivier Robert }
33989c2daa00SOllivier Robert 
33999c2daa00SOllivier Robert 
34009c2daa00SOllivier Robert 
34019c2daa00SOllivier Robert /*
34029c2daa00SOllivier Robert  * Check the leap second status once per day.
34039c2daa00SOllivier Robert  *
34049c2daa00SOllivier Robert  * Note that the ONCORE firmware for the Bj command is wrong at
34059c2daa00SOllivier Robert  * least in the VP.
34069c2daa00SOllivier Robert  * It starts advertising a LEAP SECOND as soon as the GPS satellite
34079c2daa00SOllivier Robert  * data message (page 18, subframe 4) is updated to a date in the
34089c2daa00SOllivier Robert  * future, and does not wait for the month that it will occur.
34099c2daa00SOllivier Robert  * The event will usually be advertised several months in advance.
34109c2daa00SOllivier Robert  * Since there is a one bit flag, there is no way to tell if it is
34119c2daa00SOllivier Robert  * this month, or when...
34129c2daa00SOllivier Robert  *
34139c2daa00SOllivier Robert  * As such, we have the workaround below, of only checking for leap
34149c2daa00SOllivier Robert  * seconds with the Bj command in June/December.
34159c2daa00SOllivier Robert  *
34169c2daa00SOllivier Robert  * The Gj command gives more information, and we can tell in which
34179c2daa00SOllivier Robert  * month to apply the correction.
34189c2daa00SOllivier Robert  *
34199c2daa00SOllivier Robert  * Note that with the VP we COULD read the raw data message, and
34209c2daa00SOllivier Robert  * interpret it ourselves, but since this is specific to this receiver
34219c2daa00SOllivier Robert  * only, and the above workaround is adequate, we don't bother.
34229c2daa00SOllivier Robert  */
34239c2daa00SOllivier Robert 
34249c2daa00SOllivier Robert static void
34259c2daa00SOllivier Robert oncore_check_leap_sec(
34269c2daa00SOllivier Robert 	struct instance *instance
34279c2daa00SOllivier Robert 	)
34289c2daa00SOllivier Robert {
34292b15cb3dSCy Schubert 	oncore_cmd_Bl[2] = 1;				/* just to be sure */
34309c2daa00SOllivier Robert 	if (instance->Bj_day != instance->BEHa[5]) {	/* do this 1/day */
34319c2daa00SOllivier Robert 		instance->Bj_day = instance->BEHa[5];
34329c2daa00SOllivier Robert 
34339c2daa00SOllivier Robert 		if (instance->saw_Gj < 0) {	/* -1 DONT have Gj use Bj */
34349c2daa00SOllivier Robert 			if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12))
34352b15cb3dSCy Schubert 				oncore_sendmsg(instance, oncore_cmd_Bj, sizeof(oncore_cmd_Bj));
34362b15cb3dSCy Schubert 			oncore_sendmsg(instance, oncore_cmd_Bl, sizeof(oncore_cmd_Bl));
34379c2daa00SOllivier Robert 			return;
34389c2daa00SOllivier Robert 		}
34399c2daa00SOllivier Robert 
34409c2daa00SOllivier Robert 		if (instance->saw_Gj == 0)	/* 0 is dont know if we have Gj */
34419c2daa00SOllivier Robert 			instance->count4 = 1;
34429c2daa00SOllivier Robert 
34432b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Gj, sizeof(oncore_cmd_Gj));
34449c2daa00SOllivier Robert 		return;
34459c2daa00SOllivier Robert 	}
34469c2daa00SOllivier Robert 
34479c2daa00SOllivier Robert 	/* Gj works for some 6/8 chan UT and the M12	  */
34489c2daa00SOllivier Robert 	/* if no response from Gj in 5 sec, we try Bj	  */
34499c2daa00SOllivier Robert 	/* which isnt implemented in all the GT/UT either */
34509c2daa00SOllivier Robert 
34519c2daa00SOllivier Robert 	if (instance->count4) { 	/* delay, waiting for Gj response */
34529c2daa00SOllivier Robert 		if (instance->saw_Gj == 1)
34539c2daa00SOllivier Robert 			instance->count4 = 0;
34549c2daa00SOllivier Robert 		else if (instance->count4++ > 5) {	/* delay, waiting for Gj response */
34559c2daa00SOllivier Robert 			instance->saw_Gj = -1;		/* didnt see it, will use Bj */
34569c2daa00SOllivier Robert 			instance->count4 = 0;
34572b15cb3dSCy Schubert 			if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12)) {
34582b15cb3dSCy Schubert 				oncore_sendmsg(instance, oncore_cmd_Bj, sizeof(oncore_cmd_Bj));
34592b15cb3dSCy Schubert 				oncore_sendmsg(instance, oncore_cmd_Bl, sizeof(oncore_cmd_Bl));
34602b15cb3dSCy Schubert 			}
34619c2daa00SOllivier Robert 		}
34629c2daa00SOllivier Robert 	}
34639c2daa00SOllivier Robert }
34649c2daa00SOllivier Robert 
34659c2daa00SOllivier Robert 
34669c2daa00SOllivier Robert 
34679c2daa00SOllivier Robert /* check the message checksum,
34689c2daa00SOllivier Robert  *  buf points to START of message ( @@ )
34699c2daa00SOllivier Robert  *  len is length WITH CR/LF.
34709c2daa00SOllivier Robert  */
34719c2daa00SOllivier Robert 
34729c2daa00SOllivier Robert static int
34739c2daa00SOllivier Robert oncore_checksum_ok(
34749c2daa00SOllivier Robert 	u_char *buf,
34759c2daa00SOllivier Robert 	int	len
34769c2daa00SOllivier Robert 	)
34779c2daa00SOllivier Robert {
34789c2daa00SOllivier Robert 	int	i, j;
34799c2daa00SOllivier Robert 
34809c2daa00SOllivier Robert 	j = 0;
34819c2daa00SOllivier Robert 	for (i = 2; i < len-3; i++)
34829c2daa00SOllivier Robert 		j ^= buf[i];
34839c2daa00SOllivier Robert 
34849c2daa00SOllivier Robert 	return(j == buf[len-3]);
34859c2daa00SOllivier Robert }
34869c2daa00SOllivier Robert 
34879c2daa00SOllivier Robert 
34889c2daa00SOllivier Robert 
34899c2daa00SOllivier Robert static void
34909c2daa00SOllivier Robert oncore_compute_dH(
34919c2daa00SOllivier Robert 	struct instance *instance
34929c2daa00SOllivier Robert 	)
34939c2daa00SOllivier Robert {
34949c2daa00SOllivier Robert 	int GPS, MSL;
34959c2daa00SOllivier Robert 
34969c2daa00SOllivier Robert 	/* Here calculate dH = GPS - MSL for output message */
34979c2daa00SOllivier Robert 	/* also set Altitude Hold mode if GT */
34989c2daa00SOllivier Robert 
34999c2daa00SOllivier Robert 	instance->have_dH = 1;
35009c2daa00SOllivier Robert 	if (instance->chan == 12) {
35019c2daa00SOllivier Robert 		GPS = buf_w32(&instance->BEHa[39]);
35029c2daa00SOllivier Robert 		MSL = buf_w32(&instance->BEHa[43]);
35039c2daa00SOllivier Robert 	} else {
35049c2daa00SOllivier Robert 		GPS = buf_w32(&instance->BEHa[23]);
35059c2daa00SOllivier Robert 		MSL = buf_w32(&instance->BEHa[27]);
35069c2daa00SOllivier Robert 	}
35079c2daa00SOllivier Robert 	instance->dH = GPS - MSL;
35089c2daa00SOllivier Robert 	instance->dH /= 100.;
35099c2daa00SOllivier Robert 
35109c2daa00SOllivier Robert 	/* if MSL is not set, the calculation is meaningless */
35119c2daa00SOllivier Robert 
35122b15cb3dSCy Schubert 	if (MSL)	/* not set ! */
35132b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_INFO,
35142b15cb3dSCy Schubert 		             "dH = (GPS - MSL) = %.2fm", instance->dH);
35159c2daa00SOllivier Robert }
35169c2daa00SOllivier Robert 
35179c2daa00SOllivier Robert 
35189c2daa00SOllivier Robert 
35199c2daa00SOllivier Robert /*
35209c2daa00SOllivier Robert  * try loading Almanac from shmem (where it was copied from shmem_old
35219c2daa00SOllivier Robert  */
35229c2daa00SOllivier Robert 
35239c2daa00SOllivier Robert static void
35249c2daa00SOllivier Robert oncore_load_almanac(
35259c2daa00SOllivier Robert 	struct instance *instance
35269c2daa00SOllivier Robert 	)
35279c2daa00SOllivier Robert {
35289c2daa00SOllivier Robert 	u_char	*cp, Cmd[20];
35299c2daa00SOllivier Robert 	int	n;
35309c2daa00SOllivier Robert 	struct timeval tv;
35319c2daa00SOllivier Robert 	struct tm *tm;
35329c2daa00SOllivier Robert 
35339c2daa00SOllivier Robert 	if (!instance->shmem)
35349c2daa00SOllivier Robert 		return;
35359c2daa00SOllivier Robert 
35362b15cb3dSCy Schubert #ifndef ONCORE_VERBOSE_LOAD_ALMANAC
35372b15cb3dSCy Schubert 	for (cp = instance->shmem + 4; (n = 256 * (*(cp-3)) + *(cp-2));
35382b15cb3dSCy Schubert 	     cp += (n + 3)) {
3539ea906c41SOllivier Robert 		if (!strncmp((char *) cp, "@@Cb", 4) &&
35409c2daa00SOllivier Robert 		    oncore_checksum_ok(cp, 33) &&
35419c2daa00SOllivier Robert 		    (*(cp+4) == 4 || *(cp+4) == 5)) {
3542a466cc55SCy Schubert 			refclock_fdwrite(instance->peer, instance->ttyfd,
3543a466cc55SCy Schubert 					 cp, n, "data");
35449c2daa00SOllivier Robert 			oncore_print_Cb(instance, cp);
35459c2daa00SOllivier Robert 		}
35469c2daa00SOllivier Robert 	}
35472b15cb3dSCy Schubert #else	/* ONCORE_VERBOSE_LOAD_ALMANAC follows */
35482b15cb3dSCy Schubert 	for (cp = instance->shmem + 4; (n = 256 * (*(cp-3)) + *(cp-2));
35492b15cb3dSCy Schubert 	     cp += (n+3)) {
35502b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_DEBUG, "See %c%c%c%c %d",
35512b15cb3dSCy Schubert 			   *(cp), *(cp+1), *(cp+2), *(cp+3), *(cp+4));
35529c2daa00SOllivier Robert 
35539c2daa00SOllivier Robert 		if (!strncmp(cp, "@@Cb", 4)) {
35549c2daa00SOllivier Robert 			oncore_print_Cb(instance, cp);
35559c2daa00SOllivier Robert 			if (oncore_checksum_ok(cp, 33)) {
35569c2daa00SOllivier Robert 				if (*(cp+4) == 4 || *(cp+4) == 5) {
35572b15cb3dSCy Schubert 					oncore_log(instance, LOG_DEBUG, "GOOD SF");
35589c2daa00SOllivier Robert 					write(instance->ttyfd, cp, n);
35599c2daa00SOllivier Robert 				} else
35602b15cb3dSCy Schubert 					oncore_log(instance, LOG_DEBUG, "BAD SF");
35619c2daa00SOllivier Robert 			} else
35622b15cb3dSCy Schubert 				oncore_log(instance, LOG_DEBUG, "BAD CHECKSUM");
35639c2daa00SOllivier Robert 		}
35649c2daa00SOllivier Robert 	}
35659c2daa00SOllivier Robert #endif
35669c2daa00SOllivier Robert 
35679c2daa00SOllivier Robert 	/* Must load position and time or the Almanac doesn't do us any good */
35689c2daa00SOllivier Robert 
35699c2daa00SOllivier Robert 	if (!instance->posn_set) {	/* if we input a posn use it, else from SHMEM */
35702b15cb3dSCy Schubert 		oncore_log(instance, LOG_NOTICE, "Loading Posn from SHMEM");
35719c2daa00SOllivier Robert 		for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2));  cp+=(n+3)) {
3572ea906c41SOllivier Robert 			if ((instance->chan == 6  && (!strncmp((char *) cp, "@@Ba", 4) && oncore_checksum_ok(cp,  68))) ||
3573ea906c41SOllivier Robert 			    (instance->chan == 8  && (!strncmp((char *) cp, "@@Ea", 4) && oncore_checksum_ok(cp,  76))) ||
3574ea906c41SOllivier Robert 			    (instance->chan == 12 && (!strncmp((char *) cp, "@@Ha", 4) && oncore_checksum_ok(cp, 154)))) {
35759c2daa00SOllivier Robert 				int ii, jj, kk;
35769c2daa00SOllivier Robert 
35779c2daa00SOllivier Robert 				instance->posn_set = 1;
35789c2daa00SOllivier Robert 				ii = buf_w32(cp + 15);
35799c2daa00SOllivier Robert 				jj = buf_w32(cp + 19);
35809c2daa00SOllivier Robert 				kk = buf_w32(cp + 23);
35812b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_LOAD_ALMANAC
35822b15cb3dSCy Schubert 				oncore_log_f(instance, LOG_DEBUG,
35832b15cb3dSCy Schubert 					     "SHMEM posn = %ld (%d, %d, %d)",
35842b15cb3dSCy Schubert 					     (long)(cp-instance->shmem),
35852b15cb3dSCy Schubert 					     ii, jj, kk);
3586ea906c41SOllivier Robert #endif
35879c2daa00SOllivier Robert 				if (ii != 0 || jj != 0 || kk != 0) { /* phk asked for this test */
35889c2daa00SOllivier Robert 					instance->ss_lat  = ii;
35899c2daa00SOllivier Robert 					instance->ss_long = jj;
35909c2daa00SOllivier Robert 					instance->ss_ht   = kk;
35919c2daa00SOllivier Robert 				}
35929c2daa00SOllivier Robert 			}
35939c2daa00SOllivier Robert 		}
35949c2daa00SOllivier Robert 	}
35959c2daa00SOllivier Robert 	oncore_set_posn(instance);
35969c2daa00SOllivier Robert 
35979c2daa00SOllivier Robert 	/* and set time to time from Computer clock */
35989c2daa00SOllivier Robert 
35992b15cb3dSCy Schubert 	GETTIMEOFDAY(&tv, 0);
36009c2daa00SOllivier Robert 	tm = gmtime((const time_t *) &tv.tv_sec);
36012b15cb3dSCy Schubert 
36022b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_LOAD_ALMANAC
36032b15cb3dSCy Schubert 	oncore_log_f(instance, LOG_DEBUG, "DATE %d %d %d, %d %d %d",
36042b15cb3dSCy Schubert 		     1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
36059c2daa00SOllivier Robert 		     tm->tm_hour, tm->tm_min, tm->tm_sec);
36069c2daa00SOllivier Robert #endif
36079c2daa00SOllivier Robert 	if (instance->chan == 12) {
36089c2daa00SOllivier Robert 		memcpy(Cmd, oncore_cmd_Gb, (size_t) sizeof(oncore_cmd_Gb));
3609ea906c41SOllivier Robert 		Cmd[-2+4]  = tm->tm_mon + 1;
36109c2daa00SOllivier Robert 		Cmd[-2+5]  = tm->tm_mday;
36119c2daa00SOllivier Robert 		Cmd[-2+6]  = (1900+tm->tm_year)/256;
36129c2daa00SOllivier Robert 		Cmd[-2+7]  = (1900+tm->tm_year)%256;
36139c2daa00SOllivier Robert 		Cmd[-2+8]  = tm->tm_hour;
36149c2daa00SOllivier Robert 		Cmd[-2+9]  = tm->tm_min;
36159c2daa00SOllivier Robert 		Cmd[-2+10] = tm->tm_sec;
36169c2daa00SOllivier Robert 		Cmd[-2+11] = 0;
36179c2daa00SOllivier Robert 		Cmd[-2+12] = 0;
36189c2daa00SOllivier Robert 		Cmd[-2+13] = 0;
36192b15cb3dSCy Schubert 		oncore_sendmsg(instance, Cmd,  sizeof(oncore_cmd_Gb));
36209c2daa00SOllivier Robert 	} else {
36219c2daa00SOllivier Robert 		/* First set GMT offset to zero */
36229c2daa00SOllivier Robert 
36232b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Ab, sizeof(oncore_cmd_Ab));
36249c2daa00SOllivier Robert 
36259c2daa00SOllivier Robert 		memcpy(Cmd, oncore_cmd_Ac, (size_t) sizeof(oncore_cmd_Ac));
3626ea906c41SOllivier Robert 		Cmd[-2+4] = tm->tm_mon + 1;
36279c2daa00SOllivier Robert 		Cmd[-2+5] = tm->tm_mday;
36289c2daa00SOllivier Robert 		Cmd[-2+6] = (1900+tm->tm_year)/256;
36299c2daa00SOllivier Robert 		Cmd[-2+7] = (1900+tm->tm_year)%256;
36302b15cb3dSCy Schubert 		oncore_sendmsg(instance, Cmd,  sizeof(oncore_cmd_Ac));
36319c2daa00SOllivier Robert 
36329c2daa00SOllivier Robert 		memcpy(Cmd, oncore_cmd_Aa, (size_t) sizeof(oncore_cmd_Aa));
36339c2daa00SOllivier Robert 		Cmd[-2+4] = tm->tm_hour;
36349c2daa00SOllivier Robert 		Cmd[-2+5] = tm->tm_min;
36359c2daa00SOllivier Robert 		Cmd[-2+6] = tm->tm_sec;
36362b15cb3dSCy Schubert 		oncore_sendmsg(instance, Cmd,  sizeof(oncore_cmd_Aa));
36379c2daa00SOllivier Robert 	}
36389c2daa00SOllivier Robert 
36392b15cb3dSCy Schubert 	oncore_log(instance, LOG_INFO, "Setting Posn and Time after Loading Almanac");
36409c2daa00SOllivier Robert }
36419c2daa00SOllivier Robert 
36429c2daa00SOllivier Robert 
36439c2daa00SOllivier Robert 
36449c2daa00SOllivier Robert /* Almanac data input */
36459c2daa00SOllivier Robert 
36469c2daa00SOllivier Robert static void
36479c2daa00SOllivier Robert oncore_print_Cb(
36489c2daa00SOllivier Robert 	struct instance *instance,
36499c2daa00SOllivier Robert 	u_char *cp
36509c2daa00SOllivier Robert 	)
36519c2daa00SOllivier Robert {
36522b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_CB
36539c2daa00SOllivier Robert 	int	ii;
36542b15cb3dSCy Schubert 	char	Msg[160], Msg2[10];
36559c2daa00SOllivier Robert 
36562b15cb3dSCy Schubert 	oncore_log_f(instance, LOG_DEBUG, "DEBUG: See: %c%c%c%c", *(cp),
36572b15cb3dSCy Schubert 		     *(cp+1), *(cp+2), *(cp+3));
36589c2daa00SOllivier Robert 
36592b15cb3dSCy Schubert 	snprintf(Msg, sizeof(Msg), "DEBUG: Cb: [%d,%d]", *(cp+4),
36602b15cb3dSCy Schubert 		*(cp+5));
36612b15cb3dSCy Schubert 	for (ii = 0; ii < 33; ii++) {
36622b15cb3dSCy Schubert 		snprintf(Msg2, sizeof(Msg2), " %d", *(cp+ii));
36632b15cb3dSCy Schubert 		strlcat(Msg, Msg2, sizeof(Msg));
36642b15cb3dSCy Schubert 	}
36652b15cb3dSCy Schubert 	oncore_log(instance, LOG_DEBUG, Msg);
36662b15cb3dSCy Schubert 
36672b15cb3dSCy Schubert 	oncore_log_f(instance, LOG_DEBUG, "Debug: Cb: [%d,%d]", *(cp+4),
36682b15cb3dSCy Schubert 		     *(cp+5));
36699c2daa00SOllivier Robert #endif
36709c2daa00SOllivier Robert }
36719c2daa00SOllivier Robert 
36729c2daa00SOllivier Robert 
36739c2daa00SOllivier Robert #if 0
36749c2daa00SOllivier Robert static void
36759c2daa00SOllivier Robert oncore_print_array(
36769c2daa00SOllivier Robert 	u_char *cp,
36779c2daa00SOllivier Robert 	int	n
36789c2daa00SOllivier Robert 	)
36799c2daa00SOllivier Robert {
36809c2daa00SOllivier Robert 	int	jj, i, j, nn;
36819c2daa00SOllivier Robert 
36829c2daa00SOllivier Robert 	nn = 0;
36839c2daa00SOllivier Robert 	printf("\nTOP\n");
36849c2daa00SOllivier Robert 	jj = n/16;
36859c2daa00SOllivier Robert 	for (j=0; j<jj; j++) {
36869c2daa00SOllivier Robert 		printf("%4d: ", nn);
36879c2daa00SOllivier Robert 		nn += 16;
36889c2daa00SOllivier Robert 		for (i=0; i<16; i++)
36899c2daa00SOllivier Robert 			printf(" %o", *cp++);
36909c2daa00SOllivier Robert 		printf("\n");
36919c2daa00SOllivier Robert 	}
36929c2daa00SOllivier Robert }
36939c2daa00SOllivier Robert #endif
36949c2daa00SOllivier Robert 
36959c2daa00SOllivier Robert 
36969c2daa00SOllivier Robert static void
36979c2daa00SOllivier Robert oncore_print_posn(
3698224ba2bdSOllivier Robert 	struct instance *instance
3699224ba2bdSOllivier Robert 	)
3700224ba2bdSOllivier Robert {
37012b15cb3dSCy Schubert 	char ew, ns;
3702224ba2bdSOllivier Robert 	double xd, xm, xs, yd, ym, ys, hm, hft;
3703224ba2bdSOllivier Robert 	int idx, idy, is, imx, imy;
3704224ba2bdSOllivier Robert 	long lat, lon;
3705c0b746e5SOllivier Robert 
37062b15cb3dSCy Schubert 	oncore_log(instance, LOG_INFO, "Posn:");
3707c0b746e5SOllivier Robert 	ew = 'E';
3708c0b746e5SOllivier Robert 	lon = instance->ss_long;
3709c0b746e5SOllivier Robert 	if (lon < 0) {
3710c0b746e5SOllivier Robert 		ew = 'W';
3711c0b746e5SOllivier Robert 		lon = -lon;
3712c0b746e5SOllivier Robert 	}
3713c0b746e5SOllivier Robert 
3714c0b746e5SOllivier Robert 	ns = 'N';
3715c0b746e5SOllivier Robert 	lat = instance->ss_lat;
3716c0b746e5SOllivier Robert 	if (lat < 0) {
3717c0b746e5SOllivier Robert 		ns = 'S';
3718c0b746e5SOllivier Robert 		lat = -lat;
3719c0b746e5SOllivier Robert 	}
3720c0b746e5SOllivier Robert 
3721c0b746e5SOllivier Robert 	hm = instance->ss_ht/100.;
3722c0b746e5SOllivier Robert 	hft= hm/0.3048;
3723c0b746e5SOllivier Robert 
3724c0b746e5SOllivier Robert 	xd = lat/3600000.;	/* lat, lon in int msec arc, ht in cm. */
3725c0b746e5SOllivier Robert 	yd = lon/3600000.;
37262b15cb3dSCy Schubert 	oncore_log_f(instance, LOG_INFO,
37272b15cb3dSCy Schubert 		     "Lat = %c %11.7fdeg,    Long = %c %11.7fdeg,    Alt = %5.2fm (%5.2fft) GPS",
37282b15cb3dSCy Schubert 		     ns, xd, ew, yd, hm, hft);
3729c0b746e5SOllivier Robert 
3730c0b746e5SOllivier Robert 	idx = xd;
3731c0b746e5SOllivier Robert 	idy = yd;
3732c0b746e5SOllivier Robert 	imx = lat%3600000;
3733c0b746e5SOllivier Robert 	imy = lon%3600000;
3734c0b746e5SOllivier Robert 	xm = imx/60000.;
3735c0b746e5SOllivier Robert 	ym = imy/60000.;
37362b15cb3dSCy Schubert 	oncore_log_f(instance, LOG_INFO,
37372b15cb3dSCy Schubert 		     "Lat = %c %3ddeg %7.4fm,   Long = %c %3ddeg %8.5fm,  Alt = %7.2fm (%7.2fft) GPS",
37382b15cb3dSCy Schubert 		     ns, idx, xm, ew, idy, ym, hm, hft);
3739c0b746e5SOllivier Robert 
3740c0b746e5SOllivier Robert 	imx = xm;
3741c0b746e5SOllivier Robert 	imy = ym;
3742c0b746e5SOllivier Robert 	is  = lat%60000;
3743c0b746e5SOllivier Robert 	xs  = is/1000.;
3744c0b746e5SOllivier Robert 	is  = lon%60000;
3745c0b746e5SOllivier Robert 	ys  = is/1000.;
37462b15cb3dSCy Schubert 	oncore_log_f(instance, LOG_INFO,
37472b15cb3dSCy Schubert 		     "Lat = %c %3ddeg %2dm %5.2fs, Long = %c %3ddeg %2dm %5.2fs, Alt = %7.2fm (%7.2fft) GPS",
37482b15cb3dSCy Schubert 		     ns, idx, imx, xs, ew, idy, imy, ys, hm, hft);
3749a151a66cSOllivier Robert }
3750c0b746e5SOllivier Robert 
3751c0b746e5SOllivier Robert 
3752a151a66cSOllivier Robert 
3753a151a66cSOllivier Robert /*
37549c2daa00SOllivier Robert  * write message to Oncore.
3755a151a66cSOllivier Robert  */
3756224ba2bdSOllivier Robert 
3757a151a66cSOllivier Robert static void
37589c2daa00SOllivier Robert oncore_sendmsg(
37592b15cb3dSCy Schubert 	struct	instance *instance,
37609c2daa00SOllivier Robert 	u_char *ptr,
3761224ba2bdSOllivier Robert 	size_t len
3762a151a66cSOllivier Robert 	)
3763a151a66cSOllivier Robert {
37642b15cb3dSCy Schubert 	int	fd;
37659c2daa00SOllivier Robert 	u_char cs = 0;
3766a466cc55SCy Schubert 	const struct peer * peer;
3767a151a66cSOllivier Robert 
37682b15cb3dSCy Schubert 	fd   = instance->ttyfd;
3769a466cc55SCy Schubert 	peer = instance->peer;
37702b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_SENDMSG
37712b15cb3dSCy Schubert 	if (debug > 4) {
37722b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_DEBUG, "ONCORE: Send @@%c%c %d",
37732b15cb3dSCy Schubert 			     ptr[0], ptr[1], (int)len);
37742b15cb3dSCy Schubert 	}
3775ea906c41SOllivier Robert #endif
3776a466cc55SCy Schubert 	refclock_fdwrite(peer, fd, "@@", (size_t)2, "data");
3777a466cc55SCy Schubert 	refclock_fdwrite(peer, fd, ptr, len, "data");
37789c2daa00SOllivier Robert 	while (len--)
37799c2daa00SOllivier Robert 		cs ^= *ptr++;
3780a466cc55SCy Schubert 	refclock_fdwrite(peer, fd, &cs, (size_t)1, "data");
3781a466cc55SCy Schubert 	refclock_fdwrite(peer, fd, "\r\n", (size_t)2, "data");
37829c2daa00SOllivier Robert }
3783a151a66cSOllivier Robert 
3784a151a66cSOllivier Robert 
3785c0b746e5SOllivier Robert 
37869c2daa00SOllivier Robert static void
37879c2daa00SOllivier Robert oncore_set_posn(
37889c2daa00SOllivier Robert 	struct instance *instance
37899c2daa00SOllivier Robert 	)
37909c2daa00SOllivier Robert {
37919c2daa00SOllivier Robert 	int	mode;
3792ea906c41SOllivier Robert 	u_char	  Cmd[20];
37939c2daa00SOllivier Robert 
37949c2daa00SOllivier Robert 	/* Turn OFF position hold, it needs to be off to set position (for some units),
37959c2daa00SOllivier Robert 	   will get set ON in @@Ea later */
37969c2daa00SOllivier Robert 
37979c2daa00SOllivier Robert 	if (instance->chan == 12)
37982b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* (12) */
37999c2daa00SOllivier Robert 	else {
38002b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* (6/8) */
38012b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* (6/8) */
38029c2daa00SOllivier Robert 	}
38039c2daa00SOllivier Robert 
38049c2daa00SOllivier Robert 	mode = instance->init_type;
38059c2daa00SOllivier Robert 
38069c2daa00SOllivier Robert 	if (mode != 0) {	/* first set posn hold position */
38079c2daa00SOllivier Robert 		memcpy(Cmd, oncore_cmd_As, (size_t) sizeof(oncore_cmd_As));	/* don't modify static variables */
38089c2daa00SOllivier Robert 		w32_buf(&Cmd[-2+4],  (int) instance->ss_lat);
38099c2daa00SOllivier Robert 		w32_buf(&Cmd[-2+8],  (int) instance->ss_long);
38109c2daa00SOllivier Robert 		w32_buf(&Cmd[-2+12], (int) instance->ss_ht);
38119c2daa00SOllivier Robert 		Cmd[-2+16] = 0;
38122b15cb3dSCy Schubert 		oncore_sendmsg(instance, Cmd,  sizeof(oncore_cmd_As));	/* posn hold 3D posn (6/8/12) */
38139c2daa00SOllivier Robert 
38149c2daa00SOllivier Robert 		memcpy(Cmd, oncore_cmd_Au, (size_t) sizeof(oncore_cmd_Au));
38159c2daa00SOllivier Robert 		w32_buf(&Cmd[-2+4], (int) instance->ss_ht);
38169c2daa00SOllivier Robert 		Cmd[-2+8] = 0;
38172b15cb3dSCy Schubert 		oncore_sendmsg(instance, Cmd,  sizeof(oncore_cmd_Au));	/* altitude hold (6/8/12 not UT, M12T) */
38189c2daa00SOllivier Robert 
38199c2daa00SOllivier Robert 		/* next set current position */
38209c2daa00SOllivier Robert 
38219c2daa00SOllivier Robert 		if (instance->chan == 12) {
38229c2daa00SOllivier Robert 			memcpy(Cmd, oncore_cmd_Ga, (size_t) sizeof(oncore_cmd_Ga));
38239c2daa00SOllivier Robert 			w32_buf(&Cmd[-2+4], (int) instance->ss_lat);
38249c2daa00SOllivier Robert 			w32_buf(&Cmd[-2+8], (int) instance->ss_long);
38259c2daa00SOllivier Robert 			w32_buf(&Cmd[-2+12],(int) instance->ss_ht);
38269c2daa00SOllivier Robert 			Cmd[-2+16] = 0;
38272b15cb3dSCy Schubert 			oncore_sendmsg(instance, Cmd,  sizeof(oncore_cmd_Ga));		  /* 3d posn (12) */
38289c2daa00SOllivier Robert 		} else {
38299c2daa00SOllivier Robert 			memcpy(Cmd, oncore_cmd_Ad, (size_t) sizeof(oncore_cmd_Ad));
38309c2daa00SOllivier Robert 			w32_buf(&Cmd[-2+4], (int) instance->ss_lat);
38312b15cb3dSCy Schubert 			oncore_sendmsg(instance, Cmd,  sizeof(oncore_cmd_Ad));	/* lat (6/8) */
38329c2daa00SOllivier Robert 
38339c2daa00SOllivier Robert 			memcpy(Cmd, oncore_cmd_Ae, (size_t) sizeof(oncore_cmd_Ae));
38349c2daa00SOllivier Robert 			w32_buf(&Cmd[-2+4], (int) instance->ss_long);
38352b15cb3dSCy Schubert 			oncore_sendmsg(instance, Cmd,  sizeof(oncore_cmd_Ae));	/* long (6/8) */
38369c2daa00SOllivier Robert 
38379c2daa00SOllivier Robert 			memcpy(Cmd, oncore_cmd_Af, (size_t) sizeof(oncore_cmd_Af));
38389c2daa00SOllivier Robert 			w32_buf(&Cmd[-2+4], (int) instance->ss_ht);
38399c2daa00SOllivier Robert 			Cmd[-2+8] = 0;
38402b15cb3dSCy Schubert 			oncore_sendmsg(instance, Cmd,  sizeof(oncore_cmd_Af));	/* ht (6/8) */
38419c2daa00SOllivier Robert 		}
38429c2daa00SOllivier Robert 
38439c2daa00SOllivier Robert 		/* Finally, turn on position hold */
38449c2daa00SOllivier Robert 
38459c2daa00SOllivier Robert 		if (instance->chan == 12)
38462b15cb3dSCy Schubert 			oncore_sendmsg(instance, oncore_cmd_Gd1,  sizeof(oncore_cmd_Gd1));
38479c2daa00SOllivier Robert 		else
38482b15cb3dSCy Schubert 			oncore_sendmsg(instance, oncore_cmd_At1,  sizeof(oncore_cmd_At1));
38499c2daa00SOllivier Robert 	}
38509c2daa00SOllivier Robert }
38519c2daa00SOllivier Robert 
38529c2daa00SOllivier Robert 
38539c2daa00SOllivier Robert 
38549c2daa00SOllivier Robert static void
38559c2daa00SOllivier Robert oncore_set_traim(
38569c2daa00SOllivier Robert 	struct instance *instance
38579c2daa00SOllivier Robert 	)
38589c2daa00SOllivier Robert {
38599c2daa00SOllivier Robert 	if (instance->traim_in != -1)	/* set in Input */
38609c2daa00SOllivier Robert 		instance->traim = instance->traim_in;
38619c2daa00SOllivier Robert 	else
38629c2daa00SOllivier Robert 		instance->traim = instance->traim_ck;
38639c2daa00SOllivier Robert 
38642b15cb3dSCy Schubert 	oncore_log_f(instance, LOG_INFO, "Input   says TRAIM = %d",
38652b15cb3dSCy Schubert 		     instance->traim_in);
38662b15cb3dSCy Schubert 	oncore_log_f(instance, LOG_INFO, "Model # says TRAIM = %d",
38672b15cb3dSCy Schubert 		     instance->traim_id);
38682b15cb3dSCy Schubert 	oncore_log_f(instance, LOG_INFO, "Testing says TRAIM = %d",
38692b15cb3dSCy Schubert 		     instance->traim_ck);
38702b15cb3dSCy Schubert 	oncore_log_f(instance, LOG_INFO, "Using        TRAIM = %d",
38712b15cb3dSCy Schubert 		     instance->traim);
38729c2daa00SOllivier Robert 
38739c2daa00SOllivier Robert 	if (instance->traim_ck == 1 && instance->traim == 0) {
38749c2daa00SOllivier Robert 		/* if it should be off, and I turned it on during testing,
38759c2daa00SOllivier Robert 		   then turn it off again */
38769c2daa00SOllivier Robert 		if (instance->chan == 6)
38772b15cb3dSCy Schubert 			oncore_sendmsg(instance, oncore_cmd_Bnx, sizeof(oncore_cmd_Bnx));
38789c2daa00SOllivier Robert 		else if (instance->chan == 8)
38792b15cb3dSCy Schubert 			oncore_sendmsg(instance, oncore_cmd_Enx, sizeof(oncore_cmd_Enx));
38809c2daa00SOllivier Robert 		else	/* chan == 12 */
38812b15cb3dSCy Schubert 			oncore_sendmsg(instance, oncore_cmd_Ge0, sizeof(oncore_cmd_Ge0));
38822b15cb3dSCy Schubert 		oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
38839c2daa00SOllivier Robert 	}
3884c0b746e5SOllivier Robert }
3885c0b746e5SOllivier Robert 
3886a151a66cSOllivier Robert 
3887a151a66cSOllivier Robert 
3888a151a66cSOllivier Robert /*
38899c2daa00SOllivier Robert  * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn.
3890a151a66cSOllivier Robert  */
3891224ba2bdSOllivier Robert 
3892a151a66cSOllivier Robert static void
38939c2daa00SOllivier Robert oncore_shmem_get_3D(
38949c2daa00SOllivier Robert 	struct instance *instance
3895a151a66cSOllivier Robert 	)
3896a151a66cSOllivier Robert {
38979c2daa00SOllivier Robert 	if (instance->pp->second%15 == 3) {	/* start the sequence */			/* by changing mode */
38989c2daa00SOllivier Robert 		instance->shmem_reset = 1;
38999c2daa00SOllivier Robert 		if (instance->chan == 12) {
39009c2daa00SOllivier Robert 			if (instance->shmem_Posn == 2)
39012b15cb3dSCy Schubert 				oncore_sendmsg(instance, oncore_cmd_Gd2,  sizeof(oncore_cmd_Gd2));  /* 2D */
39029c2daa00SOllivier Robert 			else
39032b15cb3dSCy Schubert 				oncore_sendmsg(instance, oncore_cmd_Gd0,  sizeof(oncore_cmd_Gd0));  /* 3D */
39049c2daa00SOllivier Robert 		} else {
39059c2daa00SOllivier Robert 			if (instance->saw_At) { 		/* out of 0D -> 3D mode */
39062b15cb3dSCy Schubert 				oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0));
39079c2daa00SOllivier Robert 				if (instance->shmem_Posn == 2)	/* 3D -> 2D mode */
39082b15cb3dSCy Schubert 					oncore_sendmsg(instance, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
39099c2daa00SOllivier Robert 			} else
39102b15cb3dSCy Schubert 				oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
39119c2daa00SOllivier Robert 		}
39129c2daa00SOllivier Robert 	} else if (instance->shmem_reset || (instance->mode != MODE_0D)) {
39139c2daa00SOllivier Robert 		instance->shmem_reset = 0;
39149c2daa00SOllivier Robert 		if (instance->chan == 12)
39152b15cb3dSCy Schubert 			oncore_sendmsg(instance, oncore_cmd_Gd1,  sizeof(oncore_cmd_Gd1));	/* 0D */
39169c2daa00SOllivier Robert 		else {
39179c2daa00SOllivier Robert 			if (instance->saw_At) {
39189c2daa00SOllivier Robert 				if (instance->mode == MODE_2D)	/* 2D -> 3D or 0D mode */
39192b15cb3dSCy Schubert 					oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
39202b15cb3dSCy Schubert 				oncore_sendmsg(instance, oncore_cmd_At1,  sizeof(oncore_cmd_At1)); /* to 0D mode */
39219c2daa00SOllivier Robert 			} else
39222b15cb3dSCy Schubert 				oncore_sendmsg(instance, oncore_cmd_Av1,  sizeof(oncore_cmd_Av1));
39239c2daa00SOllivier Robert 		}
39249c2daa00SOllivier Robert 	}
3925a151a66cSOllivier Robert }
3926224ba2bdSOllivier Robert 
39279c2daa00SOllivier Robert 
39289c2daa00SOllivier Robert 
39299c2daa00SOllivier Robert /*
39309c2daa00SOllivier Robert  * Here we do the Software SiteSurvey.
39319c2daa00SOllivier Robert  * We have to average our own position for the Position Hold Mode
39329c2daa00SOllivier Robert  *   We use Heights from the GPS ellipsoid.
39339c2daa00SOllivier Robert  * We check for the END of either HW or SW SiteSurvey.
39349c2daa00SOllivier Robert  */
39359c2daa00SOllivier Robert 
3936224ba2bdSOllivier Robert static void
39379c2daa00SOllivier Robert oncore_ss(
39389c2daa00SOllivier Robert 	struct instance *instance
3939224ba2bdSOllivier Robert 	)
3940224ba2bdSOllivier Robert {
39419c2daa00SOllivier Robert 	double	lat, lon, ht;
3942224ba2bdSOllivier Robert 
39439c2daa00SOllivier Robert 
39449c2daa00SOllivier Robert 	if (instance->site_survey == ONCORE_SS_HW) {
39459c2daa00SOllivier Robert 		/*
39469c2daa00SOllivier Robert 		 * Check to see if Hardware SiteSurvey has Finished.
39479c2daa00SOllivier Robert 		 */
39489c2daa00SOllivier Robert 
39499c2daa00SOllivier Robert 		if ((instance->chan == 8  && !(instance->BEHa[37]  & 0x20)) ||
39509c2daa00SOllivier Robert 		    (instance->chan == 12 && !(instance->BEHa[130] & 0x10))) {
39512b15cb3dSCy Schubert 			oncore_log(instance, LOG_INFO, "Now in 0D mode");
39529c2daa00SOllivier Robert 
39539c2daa00SOllivier Robert 			if (instance->chan == 12)
39542b15cb3dSCy Schubert 				oncore_sendmsg(instance, oncore_cmd_Gax, sizeof(oncore_cmd_Gax));
39559c2daa00SOllivier Robert 			else
39562b15cb3dSCy Schubert 				oncore_sendmsg(instance, oncore_cmd_Asx, sizeof(oncore_cmd_Asx));
39579c2daa00SOllivier Robert 
39582b15cb3dSCy Schubert 			oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_DONE");
39599c2daa00SOllivier Robert 			instance->site_survey = ONCORE_SS_DONE;
39609c2daa00SOllivier Robert 		}
39619c2daa00SOllivier Robert 	} else {
39629c2daa00SOllivier Robert 		/*
39639c2daa00SOllivier Robert 		 * Must be a Software Site Survey.
39649c2daa00SOllivier Robert 		 */
39659c2daa00SOllivier Robert 
39669c2daa00SOllivier Robert 		if (instance->rsm.bad_fix)	/* Not if poor geometry or less than 3 sats */
39679c2daa00SOllivier Robert 			return;
39689c2daa00SOllivier Robert 
39699c2daa00SOllivier Robert 		if (instance->mode != MODE_3D)	/* Use only 3D Fixes */
39709c2daa00SOllivier Robert 			return;
39719c2daa00SOllivier Robert 
39729c2daa00SOllivier Robert 		instance->ss_lat  += buf_w32(&instance->BEHa[15]);
39739c2daa00SOllivier Robert 		instance->ss_long += buf_w32(&instance->BEHa[19]);
39749c2daa00SOllivier Robert 		instance->ss_ht   += buf_w32(&instance->BEHa[23]);  /* GPS ellipsoid */
39759c2daa00SOllivier Robert 		instance->ss_count++;
39769c2daa00SOllivier Robert 
39779c2daa00SOllivier Robert 		if (instance->ss_count != POS_HOLD_AVERAGE)
39789c2daa00SOllivier Robert 			return;
39799c2daa00SOllivier Robert 
39809c2daa00SOllivier Robert 		instance->ss_lat  /= POS_HOLD_AVERAGE;
39819c2daa00SOllivier Robert 		instance->ss_long /= POS_HOLD_AVERAGE;
39829c2daa00SOllivier Robert 		instance->ss_ht   /= POS_HOLD_AVERAGE;
39839c2daa00SOllivier Robert 
39842b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_NOTICE,
39852b15cb3dSCy Schubert 			     "Surveyed posn: lat %.3f (mas) long %.3f (mas) ht %.3f (cm)",
39862b15cb3dSCy Schubert 			     instance->ss_lat, instance->ss_long,
39872b15cb3dSCy Schubert 			     instance->ss_ht);
39889c2daa00SOllivier Robert 		lat = instance->ss_lat/3600000.;
39899c2daa00SOllivier Robert 		lon = instance->ss_long/3600000.;
39909c2daa00SOllivier Robert 		ht  = instance->ss_ht/100;
39912b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_NOTICE,
39922b15cb3dSCy Schubert 			     "Surveyed posn: lat %.7f (deg) long %.7f (deg) ht %.2f (m)",
39939c2daa00SOllivier Robert 			     lat, lon, ht);
39949c2daa00SOllivier Robert 
39959c2daa00SOllivier Robert 		oncore_set_posn(instance);
39969c2daa00SOllivier Robert 
39972b15cb3dSCy Schubert 		oncore_log(instance, LOG_INFO, "Now in 0D mode");
39989c2daa00SOllivier Robert 
39992b15cb3dSCy Schubert 		oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_DONE");
40009c2daa00SOllivier Robert 		instance->site_survey = ONCORE_SS_DONE;
4001224ba2bdSOllivier Robert 	}
4002224ba2bdSOllivier Robert }
4003224ba2bdSOllivier Robert 
40049c2daa00SOllivier Robert 
40059c2daa00SOllivier Robert 
40069c2daa00SOllivier Robert static int
40079c2daa00SOllivier Robert oncore_wait_almanac(
40089c2daa00SOllivier Robert 	struct instance *instance
40099c2daa00SOllivier Robert 	)
40109c2daa00SOllivier Robert {
40119c2daa00SOllivier Robert 	if (instance->rsm.bad_almanac) {
40122b15cb3dSCy Schubert 		instance->counta++;
40132b15cb3dSCy Schubert 		if (instance->counta%5 == 0)
40142b15cb3dSCy Schubert 			oncore_log(instance, LOG_INFO, "Waiting for Almanac");
40159c2daa00SOllivier Robert 
40169c2daa00SOllivier Robert 		/*
40179c2daa00SOllivier Robert 		 * If we get here (first time) then we don't have an almanac in memory.
40189c2daa00SOllivier Robert 		 * Check if we have a SHMEM, and if so try to load whatever is there.
40199c2daa00SOllivier Robert 		 */
40209c2daa00SOllivier Robert 
40219c2daa00SOllivier Robert 		if (!instance->almanac_from_shmem) {
40229c2daa00SOllivier Robert 			instance->almanac_from_shmem = 1;
40239c2daa00SOllivier Robert 			oncore_load_almanac(instance);
40249c2daa00SOllivier Robert 		}
40259c2daa00SOllivier Robert 		return(1);
40269c2daa00SOllivier Robert 	} else {  /* Here we have the Almanac, we will be starting the @@Bn/@@En/@@Hn
40279c2daa00SOllivier Robert 		     commands, and can finally check for TRAIM.  Again, we set a delay
40289c2daa00SOllivier Robert 		     (5sec) and wait for things to settle down */
40299c2daa00SOllivier Robert 
40309c2daa00SOllivier Robert 		if (instance->chan == 6)
40312b15cb3dSCy Schubert 			oncore_sendmsg(instance, oncore_cmd_Bn, sizeof(oncore_cmd_Bn));
40329c2daa00SOllivier Robert 		else if (instance->chan == 8)
40332b15cb3dSCy Schubert 			oncore_sendmsg(instance, oncore_cmd_En, sizeof(oncore_cmd_En));
40349c2daa00SOllivier Robert 		else if (instance->chan == 12) {
40352b15cb3dSCy Schubert 			oncore_sendmsg(instance, oncore_cmd_Gc, sizeof(oncore_cmd_Gc)); /* 1PPS on, continuous */
40362b15cb3dSCy Schubert 			oncore_sendmsg(instance, oncore_cmd_Ge, sizeof(oncore_cmd_Ge)); /* TRAIM on */
40372b15cb3dSCy Schubert 			oncore_sendmsg(instance, oncore_cmd_Hn, sizeof(oncore_cmd_Hn)); /* TRAIM status 1/s */
40389c2daa00SOllivier Robert 		}
40399c2daa00SOllivier Robert 		instance->traim_delay = 1;
40409c2daa00SOllivier Robert 
40412b15cb3dSCy Schubert 		oncore_log(instance, LOG_NOTICE, "Have now loaded an ALMANAC");
40429c2daa00SOllivier Robert 
40439c2daa00SOllivier Robert 		instance->o_state = ONCORE_RUN;
40442b15cb3dSCy Schubert 		oncore_log(instance, LOG_NOTICE, "state = ONCORE_RUN");
40459c2daa00SOllivier Robert 	}
40469c2daa00SOllivier Robert 	return(0);
40479c2daa00SOllivier Robert }
40489c2daa00SOllivier Robert 
40499c2daa00SOllivier Robert 
40502d4e511cSCy Schubert static	void
40512d4e511cSCy Schubert oncore_feed_clockproc(
40522d4e511cSCy Schubert 	struct instance * instance
40532d4e511cSCy Schubert 	)
40542d4e511cSCy Schubert {
40552d4e511cSCy Schubert 	struct peer         * const peer = instance->peer;
40562d4e511cSCy Schubert 	struct refclockproc * const pp   = instance->pp;
40572d4e511cSCy Schubert 
40582d4e511cSCy Schubert 	TCivilDate cd;	/* calendar date + time */
40592d4e511cSCy Schubert 	TGpsDatum  gd;	/* GPS datum, remapped into NTP epoch */
40602d4e511cSCy Schubert 	l_fp       fp;	/* the reference time in NTP format */
40612d4e511cSCy Schubert 
40622d4e511cSCy Schubert 	if (pp->year >= 1980) {
40632d4e511cSCy Schubert 		/* There are oncore receivers that run in a fixed
40642d4e511cSCy Schubert 		 * (possibly shifted) GPS era and fold back into that
40652d4e511cSCy Schubert 		 * era on every GPS week rollover.
40662d4e511cSCy Schubert 		 *
40672d4e511cSCy Schubert 		 * We do not trust the date we get and remap to a GPS
40682d4e511cSCy Schubert 		 * era defined by the GPS base date (derived from the
40692d4e511cSCy Schubert 		 * build time stamp or a 'tos basedate' config option.
40702d4e511cSCy Schubert 		 */
40712d4e511cSCy Schubert 		ZERO(fp);	/* has a zero to begin with */
40722d4e511cSCy Schubert 		ZERO(cd);	/* month == monthday == 0 -> use year+yearday */
40732d4e511cSCy Schubert 		cd.year    = pp->year;
40742d4e511cSCy Schubert 		cd.yearday = pp->day;
40752d4e511cSCy Schubert 		cd.hour    = pp->hour;
40762d4e511cSCy Schubert 		cd.minute  = pp->minute;
40772d4e511cSCy Schubert 		cd.second  = pp->second;
40782d4e511cSCy Schubert 
40792d4e511cSCy Schubert 		/* the magic happens in the next line: */
40802d4e511cSCy Schubert 		gd = gpscal_from_calendar(&cd, fp); /* fp should be zero here */
40812d4e511cSCy Schubert 
40822d4e511cSCy Schubert 		/* To avoid the trouble the day-of-year calculations in
40832d4e511cSCy Schubert 		 * 'refclock_process()' can cause we feed the time
40842d4e511cSCy Schubert 		 * stamps we have now directly. This also saves us two
40852d4e511cSCy Schubert 		 * full calendar calendar conversion cycles.
40862d4e511cSCy Schubert 		 */
40872d4e511cSCy Schubert 		fp = ntpfp_from_gpsdatum(&gd);
40882d4e511cSCy Schubert 		refclock_process_offset(pp, fp, pp->lastrec, pp->fudgetime1);
40892d4e511cSCy Schubert 	} else {
40902d4e511cSCy Schubert 		/* This is obviously a bad date/time... */
40912d4e511cSCy Schubert 		refclock_report(peer, CEVNT_BADDATE);
40922d4e511cSCy Schubert 		peer->flags &= ~FLAG_PPS;	/* problem - clear PPS FLAG */
40932d4e511cSCy Schubert 		return;
40942d4e511cSCy Schubert 	}
40952d4e511cSCy Schubert }
40969c2daa00SOllivier Robert 
40972b15cb3dSCy Schubert static void
40982b15cb3dSCy Schubert oncore_log (
40992b15cb3dSCy Schubert 	struct instance *instance,
41002b15cb3dSCy Schubert 	int log_level,
41012b15cb3dSCy Schubert 	const char *msg
41022b15cb3dSCy Schubert 	)
41032b15cb3dSCy Schubert {
41042b15cb3dSCy Schubert 	msyslog(log_level, "ONCORE[%d]: %s", instance->unit, msg);
41052b15cb3dSCy Schubert 	mprintf_clock_stats(&instance->peer->srcadr, "ONCORE[%d]: %s",
41062b15cb3dSCy Schubert 			    instance->unit, msg);
41072b15cb3dSCy Schubert }
41082b15cb3dSCy Schubert 
41092b15cb3dSCy Schubert 
41102b15cb3dSCy Schubert static int
41112b15cb3dSCy Schubert oncore_log_f(
41122b15cb3dSCy Schubert 	struct instance *	instance,
41132b15cb3dSCy Schubert 	int			log_level,
41142b15cb3dSCy Schubert 	const char *		fmt,
41152b15cb3dSCy Schubert 	...
41162b15cb3dSCy Schubert 	)
41172b15cb3dSCy Schubert {
41182b15cb3dSCy Schubert 	va_list	ap;
41192b15cb3dSCy Schubert 	int	rc;
41202b15cb3dSCy Schubert 	char	msg[512];
41212b15cb3dSCy Schubert 
41222b15cb3dSCy Schubert 	va_start(ap, fmt);
41232b15cb3dSCy Schubert 	rc = mvsnprintf(msg, sizeof(msg), fmt, ap);
41242b15cb3dSCy Schubert 	va_end(ap);
41252b15cb3dSCy Schubert 	oncore_log(instance, log_level, msg);
41262b15cb3dSCy Schubert 
41272b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_ONCORE_LOG
41282b15cb3dSCy Schubert 	instance->max_len = max(strlen(msg), instance->max_len);
41292b15cb3dSCy Schubert 	instance->max_count++;
41302b15cb3dSCy Schubert 	if (instance->max_count % 100 == 0)
41312b15cb3dSCy Schubert 		oncore_log_f(instance, LOG_INFO,
41322b15cb3dSCy Schubert 			    "Max Message Length so far is %d",
41332b15cb3dSCy Schubert 			    instance->max_len);
41342b15cb3dSCy Schubert #endif
41352b15cb3dSCy Schubert 	return rc;
41362b15cb3dSCy Schubert }
41372b15cb3dSCy Schubert 
4138c0b746e5SOllivier Robert #else
4139*f5f40dd6SCy Schubert NONEMPTY_TRANSLATION_UNIT
41402b15cb3dSCy Schubert #endif	/* REFCLOCK && CLOCK_ONCORE */
4141