154359Sroberto/*
254359Sroberto * ----------------------------------------------------------------------------
354359Sroberto * "THE BEER-WARE LICENSE" (Revision 42):
454359Sroberto * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
554359Sroberto * can do whatever you want with this stuff. If we meet some day, and you think
654359Sroberto * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
754359Sroberto * ----------------------------------------------------------------------------
854359Sroberto *
954359Sroberto * refclock_oncore.c
1054359Sroberto *
1154359Sroberto * Driver for some of the various the Motorola Oncore GPS receivers.
12132451Sroberto *   should work with Basic, PVT6, VP, UT, UT+, GT, GT+, SL, M12, M12+T
13132451Sroberto *	The receivers with TRAIM (VP, UT, UT+, M12+T), will be more accurate
14132451Sroberto *	than the others.
1582498Sroberto *	The receivers without position hold (GT, GT+) will be less accurate.
1654359Sroberto *
1754359Sroberto * Tested with:
1854359Sroberto *
1954359Sroberto *		(UT)				   (VP)
2054359Sroberto *   COPYRIGHT 1991-1997 MOTOROLA INC.	COPYRIGHT 1991-1996 MOTOROLA INC.
2154359Sroberto *   SFTW P/N #     98-P36848P		SFTW P/N # 98-P36830P
2254359Sroberto *   SOFTWARE VER # 2			SOFTWARE VER # 8
2354359Sroberto *   SOFTWARE REV # 2			SOFTWARE REV # 8
2454359Sroberto *   SOFTWARE DATE  APR 24 1998 	SOFTWARE DATE  06 Aug 1996
2554359Sroberto *   MODEL #	R1121N1114		MODEL #    B4121P1155
2654359Sroberto *   HWDR P/N # 1			HDWR P/N # _
2754359Sroberto *   SERIAL #	R0010A			SERIAL #   SSG0226478
2854359Sroberto *   MANUFACTUR DATE 6H07		MANUFACTUR DATE 7E02
2954359Sroberto *					OPTIONS LIST	IB
3054359Sroberto *
3182498Sroberto *	      (Basic)				   (M12)
32132451Sroberto *   COPYRIGHT 1991-1994 MOTOROLA INC.	COPYRIGHT 1991-2000 MOTOROLA INC.
33132451Sroberto *   SFTW P/N # 98-P39949M		SFTW P/N # 61-G10002A
34132451Sroberto *   SOFTWARE VER # 5			SOFTWARE VER # 1
35132451Sroberto *   SOFTWARE REV # 0			SOFTWARE REV # 3
36132451Sroberto *   SOFTWARE DATE  20 JAN 1994 	SOFTWARE DATE  Mar 13 2000
37132451Sroberto *   MODEL #	A11121P116		MODEL #    P143T12NR1
3882498Sroberto *   HDWR P/N # _			HWDR P/N # 1
39132451Sroberto *   SERIAL #	SSG0049809		SERIAL #   P003UD
40132451Sroberto *   MANUFACTUR DATE 417AMA199		MANUFACTUR DATE 0C27
41132451Sroberto *   OPTIONS LIST    AB
4282498Sroberto *
43182007Sroberto *	      (M12+T)				  (M12+T later version)
44182007Sroberto *   COPYRIGHT 1991-2002 MOTOROLA INC.	COPYRIGHT 1991-2003 MOTOROLA INC.
45182007Sroberto *   SFTW P/N #     61-G10268A		SFTW P/N #     61-G10268A
46182007Sroberto *   SOFTWARE VER # 2			SOFTWARE VER # 2
47182007Sroberto *   SOFTWARE REV # 0			SOFTWARE REV # 1
48182007Sroberto *   SOFTWARE DATE  AUG 14 2002 	SOFTWARE DATE  APR 16 2003
49182007Sroberto *   MODEL #	P283T12T11		MODEL #    P273T12T12
50182007Sroberto *   HWDR P/N # 2			HWDR P/N # 2
51182007Sroberto *   SERIAL #	P04DC2			SERIAL #   P05Z7Z
52182007Sroberto *   MANUFACTUR DATE 2J17		MANUFACTUR DATE 3G15
53182007Sroberto *
5454359Sroberto * --------------------------------------------------------------------------
55182007Sroberto * Reg Clemens (Feb 2006)
56182007Sroberto * Fix some gcc4 compiler complaints
57182007Sroberto * Fix possible segfault in oncore_init_shmem
58182007Sroberto * change all (possible) fprintf(stderr, to record_clock_stats
59182007Sroberto * Apply patch from Russell J. Yount <rjy@cmu.edu> Fixed (new) MT12+T UTC not correct
60182007Sroberto *   immediately after new Almanac Read.
61182007Sroberto * Apply patch for new PPS implementation by Rodolfo Giometti <giometti@linux.it>
62182007Sroberto *   now code can use old Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de> or
63182007Sroberto *   the new one.  Compiles depending on timepps.h seen.
64182007Sroberto * --------------------------------------------------------------------------
65182007Sroberto * Luis Batanero Guerrero <luisba@rao.es> (Dec 2005) Patch for leap seconds
66182007Sroberto * (the oncore driver was setting the wrong ntpd variable)
67182007Sroberto * --------------------------------------------------------------------------
68182007Sroberto * Reg.Clemens (Mar 2004)
69182007Sroberto * Support for interfaces other than PPSAPI removed, for Solaris, SunOS,
70182007Sroberto * SCO, you now need to use one of the timepps.h files in the root dir.
71182007Sroberto * this driver will 'grab' it for you if you dont have one in /usr/include
72182007Sroberto * --------------------------------------------------------------------------
7354359Sroberto * This code uses the two devices
7482498Sroberto *	/dev/oncore.serial.n
7582498Sroberto *	/dev/oncore.pps.n
7654359Sroberto * which may be linked to the same device.
7754359Sroberto * and can read initialization data from the file
7882498Sroberto *	/etc/ntp.oncoreN, /etc/ntp.oncore.N, or /etc/ntp.oncore, where
7982498Sroberto *	n or N are the unit number, viz 127.127.30.N.
8054359Sroberto * --------------------------------------------------------------------------
8154359Sroberto * Reg.Clemens <reg@dwf.com> Sep98.
8254359Sroberto *  Original code written for FreeBSD.
8382498Sroberto *  With these mods it works on FreeBSD, SunOS, Solaris and Linux
8482498Sroberto *    (SunOS 4.1.3 + ppsclock)
8582498Sroberto *    (Solaris7 + MU4)
8682498Sroberto *    (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + or later).
8754359Sroberto *
8854359Sroberto *  Lat,Long,Ht, cable-delay, offset, and the ReceiverID (along with the
8954359Sroberto *  state machine state) are printed to CLOCKSTATS if that file is enabled
9054359Sroberto *  in /etc/ntp.conf.
9154359Sroberto *
9254359Sroberto * --------------------------------------------------------------------------
9382498Sroberto *
9454359Sroberto * According to the ONCORE manual (TRM0003, Rev 3.2, June 1998, page 3.13)
9554359Sroberto * doing an average of 10000 valid 2D and 3D fixes is what the automatic
9654359Sroberto * site survey mode does.  Looking at the output from the receiver
9754359Sroberto * it seems like it is only using 3D fixes.
9854359Sroberto * When we do it ourselves, take 10000 3D fixes.
9954359Sroberto */
10054359Sroberto
10154359Sroberto#define POS_HOLD_AVERAGE	10000	/* nb, 10000s ~= 2h45m */
10254359Sroberto
10356746Sroberto/*
10456746Sroberto * ONCORE_SHMEM_STATUS will create a mmap(2)'ed file named according to a
10556746Sroberto * "STATUS" line in the oncore config file, which contains the most recent
10682498Sroberto * copy of all types of messages we recognize.	This file can be mmap(2)'ed
10756746Sroberto * by monitoring and statistics programs.
10882498Sroberto *
10982498Sroberto * See separate HTML documentation for this option.
11056746Sroberto */
11156746Sroberto
11254359Sroberto#ifdef HAVE_CONFIG_H
11354359Sroberto#include <config.h>
11454359Sroberto#endif
11554359Sroberto
116182007Sroberto#if defined(REFCLOCK) && defined(CLOCK_ONCORE)
11754359Sroberto
11882498Sroberto#include "ntpd.h"
11982498Sroberto#include "ntp_io.h"
12082498Sroberto#include "ntp_unixtime.h"
12182498Sroberto#include "ntp_refclock.h"
12282498Sroberto#include "ntp_stdlib.h"
12382498Sroberto
12454359Sroberto#include <stdio.h>
12554359Sroberto#include <ctype.h>
12654359Sroberto#include <sys/stat.h>
12756746Sroberto#ifdef ONCORE_SHMEM_STATUS
12856746Sroberto# ifdef HAVE_SYS_MMAN_H
12956746Sroberto#  include <sys/mman.h>
13056746Sroberto#  ifndef MAP_FAILED
13156746Sroberto#   define MAP_FAILED ((u_char *) -1)
132182007Sroberto#  endif  /* MAP_FAILED */
13356746Sroberto# endif /* HAVE_SYS_MMAN_H */
13456746Sroberto#endif /* ONCORE_SHMEM_STATUS */
13554359Sroberto
13654359Sroberto#ifdef HAVE_PPSAPI
137182007Sroberto# include "ppsapi_timepps.h"
13854359Sroberto#endif
13954359Sroberto
14056746Sroberto#ifdef HAVE_SYS_SIO_H
14156746Sroberto# include <sys/sio.h>
14256746Sroberto#endif
14356746Sroberto
14454359Srobertoenum receive_state {
14554359Sroberto	ONCORE_NO_IDEA,
146132451Sroberto	ONCORE_CHECK_ID,
147132451Sroberto	ONCORE_CHECK_CHAN,
148132451Sroberto	ONCORE_HAVE_CHAN,
14954359Sroberto	ONCORE_RESET_SENT,
15054359Sroberto	ONCORE_TEST_SENT,
15182498Sroberto	ONCORE_INIT,
15254359Sroberto	ONCORE_ALMANAC,
15354359Sroberto	ONCORE_RUN
15454359Sroberto};
15554359Sroberto
15654359Srobertoenum site_survey_state {
15754359Sroberto	ONCORE_SS_UNKNOWN,
15882498Sroberto	ONCORE_SS_TESTING,
15954359Sroberto	ONCORE_SS_HW,
16054359Sroberto	ONCORE_SS_SW,
16154359Sroberto	ONCORE_SS_DONE
16254359Sroberto};
16354359Sroberto
164132451Srobertoenum antenna_state {
165132451Sroberto      ONCORE_ANTENNA_UNKNOWN = -1,
166132451Sroberto      ONCORE_ANTENNA_OK      =	0,
167132451Sroberto      ONCORE_ANTENNA_OC      =	1,
168132451Sroberto      ONCORE_ANTENNA_UC      =	2,
169132451Sroberto      ONCORE_ANTENNA_NV      =	3
170132451Sroberto};
171132451Sroberto
17282498Sroberto/* Model Name, derived from the @@Cj message.
17382498Sroberto * Used to initialize some variables.
17482498Sroberto */
17582498Sroberto
17682498Srobertoenum oncore_model {
17782498Sroberto	ONCORE_BASIC,
17882498Sroberto	ONCORE_PVT6,
17982498Sroberto	ONCORE_VP,
18082498Sroberto	ONCORE_UT,
18182498Sroberto	ONCORE_UTPLUS,
18282498Sroberto	ONCORE_GT,
18382498Sroberto	ONCORE_GTPLUS,
18482498Sroberto	ONCORE_SL,
18582498Sroberto	ONCORE_M12,
18682498Sroberto	ONCORE_UNKNOWN
18782498Sroberto};
18882498Sroberto
18982498Sroberto/* the bits that describe these properties are in the same place
19082498Sroberto * on the VP/UT, but have moved on the M12.  As such we extract
19182498Sroberto * them, and use them from this struct.
19282498Sroberto *
19382498Sroberto */
19482498Sroberto
19582498Srobertostruct RSM {
19682498Sroberto	u_char	posn0D;
19782498Sroberto	u_char	posn2D;
19882498Sroberto	u_char	posn3D;
19982498Sroberto	u_char	bad_almanac;
20082498Sroberto	u_char	bad_fix;
20182498Sroberto};
20282498Sroberto
20382498Sroberto/* It is possible to test the VP/UT each cycle (@@Ea or equivalent) to
20482498Sroberto * see what mode it is in.  The bits on the M12 are multiplexed with
20582498Sroberto * other messages, so we have to 'keep' the last known mode here.
20682498Sroberto */
20782498Sroberto
20882498Srobertoenum posn_mode {
20982498Sroberto	MODE_UNKNOWN,
21082498Sroberto	MODE_0D,
21182498Sroberto	MODE_2D,
21282498Sroberto	MODE_3D
21382498Sroberto};
21482498Sroberto
21554359Srobertostruct instance {
21654359Sroberto	int	unit;		/* 127.127.30.unit */
21782498Sroberto	struct	refclockproc *pp;
21882498Sroberto	struct	peer *peer;
21982498Sroberto
22054359Sroberto	int	ttyfd;		/* TTY file descriptor */
22154359Sroberto	int	ppsfd;		/* PPS file descriptor */
222132451Sroberto	int	shmemfd;	/* Status shm descriptor */
22354359Sroberto	pps_handle_t pps_h;
22454359Sroberto	pps_params_t pps_p;
22554359Sroberto	enum receive_state o_state;		/* Receive state */
22682498Sroberto	enum posn_mode mode;			/* 0D, 2D, 3D */
22754359Sroberto	enum site_survey_state site_survey;	/* Site Survey state */
228132451Sroberto	enum antenna_state ant_state;		/* antenna state */
22954359Sroberto
23054359Sroberto	int	Bj_day;
23154359Sroberto
23282498Sroberto	u_long	delay;		/* ns */
23354359Sroberto	long	offset; 	/* ns */
23454359Sroberto
23582498Sroberto	u_char	*shmem;
23682498Sroberto	char	*shmem_fname;
23782498Sroberto	u_int	shmem_Cb;
23882498Sroberto	u_int	shmem_Ba;
23982498Sroberto	u_int	shmem_Ea;
24082498Sroberto	u_int	shmem_Ha;
24182498Sroberto	u_char	shmem_reset;
24282498Sroberto	u_char	shmem_Posn;
243132451Sroberto	u_char	shmem_bad_Ea;
244132451Sroberto	u_char	almanac_from_shmem;
24582498Sroberto
24654359Sroberto	double	ss_lat;
24754359Sroberto	double	ss_long;
24854359Sroberto	double	ss_ht;
24982498Sroberto	double	dH;
25054359Sroberto	int	ss_count;
25182498Sroberto	u_char	posn_set;
25254359Sroberto
25382498Sroberto	enum oncore_model model;
25482498Sroberto	u_int	version;
25582498Sroberto	u_int	revision;
25682498Sroberto
25782498Sroberto	u_char	chan;		/* 6 for PVT6 or BASIC, 8 for UT/VP, 12 for m12, 0 if unknown */
258182007Sroberto	s_char	traim;		/* do we have traim? yes UT/VP, M12+T, no BASIC, GT, M12, -1 unknown, 0 no, +1 yes */
259132451Sroberto				/* the following 7 are all timing counters */
26082498Sroberto	u_char	traim_delay;	/* seconds counter, waiting for reply */
261132451Sroberto	u_char	count;		/* cycles thru Ea before starting */
262132451Sroberto	u_char	count1; 	/* cycles thru Ea after SS_TESTING, waiting for SS_HW */
263132451Sroberto	u_char	count2; 	/* cycles thru Ea after count, to check for @@Ea */
264132451Sroberto	u_char	count3; 	/* cycles thru Ea checking for # channels */
265132451Sroberto	u_char	count4; 	/* cycles thru leap after Gj to issue Bj */
266182007Sroberto	u_char	count5; 	/* cycles thru get_timestamp waiting for valid UTC correction */
267182007Sroberto	u_char	count5_set;	/* only set count5 once */
268132451Sroberto	u_char	pollcnt;
269132451Sroberto	u_char	timeout;	/* count to retry Cj after Fa self-test */
27082498Sroberto
27182498Sroberto	struct	RSM rsm;	/* bits extracted from Receiver Status Msg in @@Ea */
27282498Sroberto	u_char	printed;
27382498Sroberto	u_char	polled;
274132451Sroberto	u_long	ev_serial;
27554359Sroberto	int	Rcvptr;
27654359Sroberto	u_char	Rcvbuf[500];
277132451Sroberto	u_char	BEHa[160];	/* Ba, Ea or Ha */
278132451Sroberto	u_char	BEHn[80];	/* Bn , En , or Hn */
27954359Sroberto	u_char	Cj[300];
280132451Sroberto	u_char	Ag;		/* Satellite mask angle */
281132451Sroberto	u_char	saw_At;
282132451Sroberto	u_char	saw_Ay;
283132451Sroberto	u_char	saw_Az;
284132451Sroberto	s_char	saw_Gj;
28582498Sroberto	u_char	have_dH;
28654359Sroberto	u_char	init_type;
28754359Sroberto	s_char	saw_tooth;
288132451Sroberto	s_char	chan_in;	/* chan number from INPUT, will always use it */
289132451Sroberto	u_char	chan_id;	/* chan number determined from part number */
290132451Sroberto	u_char	chan_ck;	/* chan number determined by sending commands to hardware */
291182007Sroberto	s_char	traim_in;	/* TRAIM from INPUT, will always use ON/OFF specified */
292132451Sroberto	s_char	traim_id;	/* TRAIM determined from part number */
293132451Sroberto	u_char	traim_ck;	/* TRAIM determined by sending commands to hardware */
294132451Sroberto	u_char	once;		/* one pass code at top of BaEaHa */
29582498Sroberto	s_char	assert;
296132451Sroberto	u_char	hardpps;
29754359Sroberto};
29854359Sroberto
29954359Sroberto#define rcvbuf	instance->Rcvbuf
30054359Sroberto#define rcvptr	instance->Rcvptr
30154359Sroberto
302132451Srobertostatic	int	oncore_start	      P((int, struct peer *));
303132451Srobertostatic	void	oncore_poll	      P((int, struct peer *));
304132451Srobertostatic	void	oncore_shutdown       P((int, struct peer *));
305132451Srobertostatic	void	oncore_consume	      P((struct instance *));
306132451Srobertostatic	void	oncore_read_config    P((struct instance *));
307132451Srobertostatic	void	oncore_receive	      P((struct recvbuf *));
308132451Srobertostatic	int	oncore_ppsapi	      P((struct instance *));
309132451Srobertostatic	void	oncore_get_timestamp  P((struct instance *, long, long));
310132451Srobertostatic	void	oncore_init_shmem     P((struct instance *));
31154359Sroberto
312132451Srobertostatic	void	oncore_antenna_report P((struct instance *, enum antenna_state));
313132451Srobertostatic	void	oncore_chan_test      P((struct instance *));
314132451Srobertostatic	void	oncore_check_almanac  P((struct instance *));
315132451Srobertostatic	void	oncore_check_antenna  P((struct instance *));
316132451Srobertostatic	void	oncore_check_leap_sec P((struct instance *));
317132451Srobertostatic	int	oncore_checksum_ok    P((u_char *, int));
318132451Srobertostatic	void	oncore_compute_dH     P((struct instance *));
319132451Srobertostatic	void	oncore_load_almanac   P((struct instance *));
320132451Srobertostatic	void	oncore_print_Cb       P((struct instance *, u_char *));
321132451Sroberto/* static  void    oncore_print_array	 P((u_char *, int));	*/
322132451Srobertostatic	void	oncore_print_posn     P((struct instance *));
323132451Srobertostatic	void	oncore_sendmsg	      P((int, u_char *, size_t));
324132451Srobertostatic	void	oncore_set_posn       P((struct instance *));
325132451Srobertostatic	void	oncore_set_traim      P((struct instance *));
326132451Srobertostatic	void	oncore_shmem_get_3D   P((struct instance *));
327132451Srobertostatic	void	oncore_ss	      P((struct instance *));
328132451Srobertostatic	int	oncore_wait_almanac   P((struct instance *));
329132451Sroberto
33082498Srobertostatic	void	oncore_msg_any	   P((struct instance *, u_char *, size_t, int));
331132451Srobertostatic	void	oncore_msg_Adef    P((struct instance *, u_char *, size_t));
332132451Srobertostatic	void	oncore_msg_Ag	   P((struct instance *, u_char *, size_t));
33382498Srobertostatic	void	oncore_msg_As	   P((struct instance *, u_char *, size_t));
33482498Srobertostatic	void	oncore_msg_At	   P((struct instance *, u_char *, size_t));
33582498Srobertostatic	void	oncore_msg_Ay	   P((struct instance *, u_char *, size_t));
33682498Srobertostatic	void	oncore_msg_Az	   P((struct instance *, u_char *, size_t));
33782498Srobertostatic	void	oncore_msg_BaEaHa  P((struct instance *, u_char *, size_t));
338132451Srobertostatic	void	oncore_msg_Bd	   P((struct instance *, u_char *, size_t));
33982498Srobertostatic	void	oncore_msg_Bj	   P((struct instance *, u_char *, size_t));
340132451Srobertostatic	void	oncore_msg_BnEnHn  P((struct instance *, u_char *, size_t));
34182498Srobertostatic	void	oncore_msg_CaFaIa  P((struct instance *, u_char *, size_t));
34282498Srobertostatic	void	oncore_msg_Cb	   P((struct instance *, u_char *, size_t));
34382498Srobertostatic	void	oncore_msg_Cf	   P((struct instance *, u_char *, size_t));
34482498Srobertostatic	void	oncore_msg_Cj	   P((struct instance *, u_char *, size_t));
34582498Srobertostatic	void	oncore_msg_Cj_id   P((struct instance *, u_char *, size_t));
34682498Srobertostatic	void	oncore_msg_Cj_init P((struct instance *, u_char *, size_t));
347132451Srobertostatic	void	oncore_msg_Ga	   P((struct instance *, u_char *, size_t));
348132451Srobertostatic	void	oncore_msg_Gb	   P((struct instance *, u_char *, size_t));
34982498Srobertostatic	void	oncore_msg_Gj	   P((struct instance *, u_char *, size_t));
35082498Srobertostatic	void	oncore_msg_Sz	   P((struct instance *, u_char *, size_t));
35154359Sroberto
35254359Srobertostruct	refclock refclock_oncore = {
35354359Sroberto	oncore_start,		/* start up driver */
35454359Sroberto	oncore_shutdown,	/* shut down driver */
35554359Sroberto	oncore_poll,		/* transmit poll message */
35654359Sroberto	noentry,		/* not used */
35754359Sroberto	noentry,		/* not used */
358182007Sroberto	noentry,		/* not used */
35954359Sroberto	NOFLAGS 		/* not used */
36054359Sroberto};
36154359Sroberto
36254359Sroberto/*
36354359Sroberto * Understanding the next bit here is not easy unless you have a manual
36482498Sroberto * for the the various Oncore Models.
36554359Sroberto */
36654359Sroberto
36756746Srobertostatic struct msg_desc {
36854359Sroberto	const char	flag[3];
36954359Sroberto	const int	len;
37082498Sroberto	void		(*handler) P((struct instance *, u_char *, size_t));
37154359Sroberto	const char	*fmt;
37256746Sroberto	int		shmem;
37354359Sroberto} oncore_messages[] = {
37482498Sroberto			/* Ea and En first since they're most common */
37582498Sroberto	{ "Ea",  76,    oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" },
37682498Sroberto	{ "Ba",  68,    oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC" },
37782498Sroberto	{ "Ha", 154,    oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC" },
378132451Sroberto	{ "Bn",  59,    oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC" },
379132451Sroberto	{ "En",  69,    oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" },
380132451Sroberto	{ "Hn",  78,    oncore_msg_BnEnHn, "" },
38182498Sroberto	{ "Ab",  10,    0,                 "" },
38282498Sroberto	{ "Ac",  11,    0,                 "" },
383132451Sroberto	{ "Ad",  11,    oncore_msg_Adef,   "" },
384132451Sroberto	{ "Ae",  11,    oncore_msg_Adef,   "" },
385132451Sroberto	{ "Af",  15,    oncore_msg_Adef,   "" },
386132451Sroberto	{ "Ag",   8,    oncore_msg_Ag,     "" }, /* Satellite mask angle */
38782498Sroberto	{ "As",  20,    oncore_msg_As,     "" },
38882498Sroberto	{ "At",   8,    oncore_msg_At,     "" },
38982498Sroberto	{ "Au",  12,    0,                 "" },
39082498Sroberto	{ "Av",   8,    0,                 "" },
39182498Sroberto	{ "Aw",   8,    0,                 "" },
39282498Sroberto	{ "Ay",  11,    oncore_msg_Ay,     "" },
39382498Sroberto	{ "Az",  11,    oncore_msg_Az,     "" },
39482498Sroberto	{ "AB",   8,    0,                 "" },
39582498Sroberto	{ "Bb",  92,    0,                 "" },
396132451Sroberto	{ "Bd",  23,    oncore_msg_Bd,     "" },
39782498Sroberto	{ "Bj",   8,    oncore_msg_Bj,     "" },
39882498Sroberto	{ "Ca",   9,    oncore_msg_CaFaIa, "" },
39982498Sroberto	{ "Cb",  33,    oncore_msg_Cb,     "" },
40082498Sroberto	{ "Cf",   7,    oncore_msg_Cf,     "" },
40182498Sroberto	{ "Cg",   8,    0,                 "" },
40282498Sroberto	{ "Ch",   9,    0,                 "" },
40382498Sroberto	{ "Cj", 294,    oncore_msg_Cj,     "" },
40482498Sroberto	{ "Ek",  71,    0,                 "" },
40582498Sroberto	{ "Fa",   9,    oncore_msg_CaFaIa, "" },
406132451Sroberto	{ "Ga",  20,    oncore_msg_Ga,     "" },
407132451Sroberto	{ "Gb",  17,    oncore_msg_Gb,     "" },
408132451Sroberto	{ "Gc",   8,    0,                 "" },
409182007Sroberto	{ "Gd",   8,    0,                 "" },
410132451Sroberto	{ "Ge",   8,    0,                 "" },
41182498Sroberto	{ "Gj",  21,    oncore_msg_Gj,     "" },
41282498Sroberto	{ "Ia",  10,    oncore_msg_CaFaIa, "" },
41382498Sroberto	{ "Sz",   8,    oncore_msg_Sz,     "" },
41482498Sroberto	{ {0},	  7,	0,		   "" }
41554359Sroberto};
41654359Sroberto
41754359Sroberto
418132451Srobertostatic u_char oncore_cmd_Aa[]  = { 'A', 'a', 0, 0, 0 }; 			    /* 6/8	Time of Day				*/
419132451Srobertostatic u_char oncore_cmd_Ab[]  = { 'A', 'b', 0, 0, 0 }; 			    /* 6/8	GMT Correction				*/
420132451Srobertostatic u_char oncore_cmd_AB[]  = { 'A', 'B', 4 };				    /* VP	Application Type: Static		*/
421132451Srobertostatic u_char oncore_cmd_Ac[]  = { 'A', 'c', 0, 0, 0, 0 };			    /* 6/8	Date					*/
422132451Srobertostatic u_char oncore_cmd_Ad[]  = { 'A', 'd', 0,0,0,0 }; 			    /* 6/8	Latitude				*/
423132451Srobertostatic u_char oncore_cmd_Ae[]  = { 'A', 'e', 0,0,0,0 }; 			    /* 6/8	Longitude				*/
424132451Srobertostatic u_char oncore_cmd_Af[]  = { 'A', 'f', 0,0,0,0, 0 };			    /* 6/8	Height					*/
425132451Srobertostatic u_char oncore_cmd_Ag[]  = { 'A', 'g', 0 };				    /* 6/8/12	Satellite Mask Angle			*/
426132451Srobertostatic u_char oncore_cmd_Agx[] = { 'A', 'g', 0xff };				    /* 6/8/12	Satellite Mask Angle: read		*/
427132451Srobertostatic 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			*/
428132451Srobertostatic u_char oncore_cmd_Asx[] = { 'A', 's', 0x7f,0xff,0xff,0xff,		    /* 6/8/12	Posn Hold Readback			*/
429132451Sroberto					     0x7f,0xff,0xff,0xff,		    /*		 on UT+ this doesnt work with 0xff	*/
430132451Sroberto					     0x7f,0xff,0xff,0xff, 0xff };	    /*		 but does work with 0x7f (sigh).	*/
431132451Srobertostatic u_char oncore_cmd_At0[] = { 'A', 't', 0 };				    /* 6/8	Posn Hold: off				*/
432132451Srobertostatic u_char oncore_cmd_At1[] = { 'A', 't', 1 };				    /* 6/8	Posn Hold: on				*/
433132451Srobertostatic u_char oncore_cmd_At2[] = { 'A', 't', 2 };				    /* 6/8	Posn Hold: Start Site Survey		*/
434132451Srobertostatic u_char oncore_cmd_Atx[] = { 'A', 't', 0xff };				    /* 6/8	Posn Hold: Read Back			*/
435132451Srobertostatic u_char oncore_cmd_Au[]  = { 'A', 'u', 0,0,0,0, 0 };			    /* GT/M12	Altitude Hold Ht.			*/
436132451Srobertostatic u_char oncore_cmd_Av0[] = { 'A', 'v', 0 };				    /* VP/GT	Altitude Hold: off			*/
437132451Srobertostatic u_char oncore_cmd_Av1[] = { 'A', 'v', 1 };				    /* VP/GT	Altitude Hold: on			*/
438132451Srobertostatic u_char oncore_cmd_Aw[]  = { 'A', 'w', 1 };				    /* 6/8/12	UTC/GPS time selection			*/
439132451Srobertostatic u_char oncore_cmd_Ay[]  = { 'A', 'y', 0, 0, 0, 0 };			    /* Timing	1PPS time offset: set			*/
440132451Srobertostatic u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff };		    /* Timing	1PPS time offset: Read			*/
441132451Srobertostatic u_char oncore_cmd_Az[]  = { 'A', 'z', 0, 0, 0, 0 };			    /* 6/8UT/12 1PPS Cable Delay: set			*/
442132451Srobertostatic u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff };		    /* 6/8UT/12 1PPS Cable Delay: Read			*/
443132451Srobertostatic u_char oncore_cmd_Ba0[] = { 'B', 'a', 0 };				    /* 6	Position/Data/Status: off		*/
444132451Srobertostatic u_char oncore_cmd_Ba[]  = { 'B', 'a', 1 };				    /* 6	Position/Data/Status: on		*/
445132451Srobertostatic u_char oncore_cmd_Bb[]  = { 'B', 'b', 1 };				    /* 6/8/12	Visible Satellites			*/
446132451Srobertostatic u_char oncore_cmd_Bd[]  = { 'B', 'd', 1 };				    /* 6/8/12?	Almanac Status Msg.			*/
447132451Srobertostatic u_char oncore_cmd_Be[]  = { 'B', 'e', 1 };				    /* 6/8/12	Request Almanac Data			*/
448132451Srobertostatic u_char oncore_cmd_Bj[]  = { 'B', 'j', 0 };				    /* 6/8	Leap Second Pending			*/
449132451Srobertostatic 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	*/
450182007Srobertostatic 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	*/
451182007Srobertostatic 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	*/
452132451Srobertostatic u_char oncore_cmd_Ca[]  = { 'C', 'a' };					    /* 6	Self Test				*/
453132451Srobertostatic u_char oncore_cmd_Cf[]  = { 'C', 'f' };					    /* 6/8/12	Set to Defaults 			*/
454132451Srobertostatic u_char oncore_cmd_Cg[]  = { 'C', 'g', 1 };				    /* VP	Posn Fix/Idle Mode			*/
455132451Srobertostatic u_char oncore_cmd_Cj[]  = { 'C', 'j' };					    /* 6/8/12	Receiver ID				*/
456132451Srobertostatic u_char oncore_cmd_Ea0[] = { 'E', 'a', 0 };				    /* 8	Position/Data/Status: off		*/
457132451Srobertostatic u_char oncore_cmd_Ea[]  = { 'E', 'a', 1 };				    /* 8	Position/Data/Status: on		*/
458132451Srobertostatic u_char oncore_cmd_Ek[]  = { 'E', 'k', 0 }; /* just turn off */		    /* 8	Posn/Status/Data - extension		*/
459132451Srobertostatic 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	*/
460182007Srobertostatic 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	*/
461182007Srobertostatic 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	*/
462132451Srobertostatic u_char oncore_cmd_Fa[]  = { 'F', 'a' };					    /* 8	Self Test				*/
463132451Srobertostatic u_char oncore_cmd_Ga[]  = { 'G', 'a', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 };	    /* 12	Position Set				*/
464132451Srobertostatic u_char oncore_cmd_Gax[] = { 'G', 'a', 0xff, 0xff, 0xff, 0xff,		    /* 12	Position Set: Read			*/
465132451Sroberto					     0xff, 0xff, 0xff, 0xff,		    /*							*/
466132451Sroberto					     0xff, 0xff, 0xff, 0xff, 0xff };	    /*							*/
467132451Srobertostatic u_char oncore_cmd_Gb[]  = { 'G', 'b', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };	    /* 12	set Date/Time				*/
468132451Srobertostatic u_char oncore_cmd_Gc[]  = { 'G', 'c', 1 };				    /* 12	PPS Control: On Cont			*/
469132451Srobertostatic u_char oncore_cmd_Gd0[] = { 'G', 'd', 0 };				    /* 12	Position Control: 3D (no hold)		*/
470132451Srobertostatic u_char oncore_cmd_Gd1[] = { 'G', 'd', 1 };				    /* 12	Position Control: 0D (3D hold)		*/
471132451Srobertostatic u_char oncore_cmd_Gd2[] = { 'G', 'd', 2 };				    /* 12	Position Control: 2D (Alt Hold) 	*/
472132451Srobertostatic u_char oncore_cmd_Gd3[] = { 'G', 'd', 3 };				    /* 12	Position Coltrol: Start Site Survey	*/
473132451Srobertostatic u_char oncore_cmd_Ge0[] = { 'G', 'e', 0 };				    /* M12+T	TRAIM: off				*/
474132451Srobertostatic u_char oncore_cmd_Ge[]  = { 'G', 'e', 1 };				    /* M12+T	TRAIM: on				*/
475132451Srobertostatic u_char oncore_cmd_Gj[]  = { 'G', 'j' };					    /* 8?/12	Leap Second Pending			*/
476132451Srobertostatic u_char oncore_cmd_Ha0[] = { 'H', 'a', 0 };				    /* 12	Position/Data/Status: off		*/
477132451Srobertostatic u_char oncore_cmd_Ha[]  = { 'H', 'a', 1 };				    /* 12	Position/Data/Status: on		*/
478132451Srobertostatic u_char oncore_cmd_Hn0[] = { 'H', 'n', 0 };				    /* 12	TRAIM Status: off			*/
479132451Srobertostatic u_char oncore_cmd_Hn[]  = { 'H', 'n', 1 };				    /* 12	TRAIM Status: on			*/
480132451Srobertostatic u_char oncore_cmd_Ia[]  = { 'I', 'a' };					    /* 12	Self Test				*/
48154359Sroberto
482132451Sroberto/* it appears that as of 1997/1998, the UT had As,At, but not Au,Av
483132451Sroberto *				    the GT had Au,Av, but not As,At
484132451Sroberto * This was as of v2.0 of both firmware sets. possibly 1.3 for UT.
485132451Sroberto * Bj in UT at v1.3
486132451Sroberto * dont see Bd in UT/GT thru 1999
487132451Sroberto * Gj in UT as of 3.0, 1999 , Bj as of 1.3
48854359Sroberto */
48954359Sroberto
490132451Srobertostatic char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jly",
491132451Sroberto	"Aug", "Sep", "Oct", "Nov", "Dec" };
49282498Sroberto
493182007Sroberto#define DEVICE1 	"/dev/oncore.serial.%d" /* name of serial device */
494182007Sroberto#define DEVICE2 	"/dev/oncore.pps.%d"    /* name of pps device */
49554359Sroberto
49654359Sroberto#define SPEED		B9600		/* Oncore Binary speed (9600 bps) */
49754359Sroberto
49854359Sroberto/*
49954359Sroberto * Assemble and disassemble 32bit signed quantities from a buffer.
50054359Sroberto *
50154359Sroberto */
50254359Sroberto
50354359Sroberto	/* to buffer, int w, u_char *buf */
50482498Sroberto#define w32_buf(buf,w)	{ u_int i_tmp;			   \
50554359Sroberto			  i_tmp = (w<0) ? (~(-w)+1) : (w); \
50654359Sroberto			  (buf)[0] = (i_tmp >> 24) & 0xff; \
50754359Sroberto			  (buf)[1] = (i_tmp >> 16) & 0xff; \
50854359Sroberto			  (buf)[2] = (i_tmp >>	8) & 0xff; \
50954359Sroberto			  (buf)[3] = (i_tmp	 ) & 0xff; \
51054359Sroberto			}
51154359Sroberto
51254359Sroberto#define w32(buf)      (((buf)[0]&0xff) << 24 | \
51354359Sroberto		       ((buf)[1]&0xff) << 16 | \
51454359Sroberto		       ((buf)[2]&0xff) <<  8 | \
51554359Sroberto		       ((buf)[3]&0xff) )
51654359Sroberto
51754359Sroberto	/* from buffer, char *buf, result to an int */
51854359Sroberto#define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf))
51954359Sroberto
52056746Sroberto
52154359Sroberto/*
52254359Sroberto * oncore_start - initialize data for processing
52354359Sroberto */
52482498Sroberto
52554359Srobertostatic int
52654359Srobertooncore_start(
52754359Sroberto	int unit,
52854359Sroberto	struct peer *peer
52954359Sroberto	)
53054359Sroberto{
531182007Sroberto#define STRING_LEN	32
53254359Sroberto	register struct instance *instance;
53354359Sroberto	struct refclockproc *pp;
534182007Sroberto	int fd1, fd2, num;
535182007Sroberto	char device1[STRING_LEN], device2[STRING_LEN], Msg[160];
53654359Sroberto	const char *cp;
53754359Sroberto	struct stat stat1, stat2;
53854359Sroberto
539132451Sroberto	/* create instance structure for this unit */
540132451Sroberto
541132451Sroberto	if (!(instance = (struct instance *) malloc(sizeof *instance))) {
542132451Sroberto		perror("malloc");
543132451Sroberto		return (0);
544132451Sroberto	}
545132451Sroberto	memset((char *) instance, 0, sizeof *instance);
546132451Sroberto
547132451Sroberto	/* initialize miscellaneous variables */
54854359Sroberto
54954359Sroberto	pp = peer->procptr;
55082498Sroberto	pp->unitptr    = (caddr_t) instance;
55182498Sroberto	instance->pp   = pp;
55282498Sroberto	instance->unit = unit;
55382498Sroberto	instance->peer = peer;
554132451Sroberto	instance->assert = 1;
555132451Sroberto	instance->once = 1;
55682498Sroberto
55754359Sroberto	instance->Bj_day = -1;
55882498Sroberto	instance->traim = -1;
559132451Sroberto	instance->traim_in = -1;
560132451Sroberto	instance->chan_in = -1;
56182498Sroberto	instance->model = ONCORE_UNKNOWN;
56282498Sroberto	instance->mode = MODE_UNKNOWN;
56382498Sroberto	instance->site_survey = ONCORE_SS_UNKNOWN;
564132451Sroberto	instance->Ag = 0xff;		/* Satellite mask angle, unset by user */
565132451Sroberto	instance->ant_state = ONCORE_ANTENNA_UNKNOWN;
56654359Sroberto
56782498Sroberto	peer->precision = -26;
56882498Sroberto	peer->minpoll = 4;
56982498Sroberto	peer->maxpoll = 4;
57082498Sroberto	pp->clockdesc = "Motorola Oncore GPS Receiver";
57182498Sroberto	memcpy((char *)&pp->refid, "GPS\0", (size_t) 4);
57282498Sroberto
573182007Sroberto	cp = "ONCORE DRIVER -- CONFIGURING";
574182007Sroberto	record_clock_stats(&(instance->peer->srcadr), cp);
57554359Sroberto
576182007Sroberto	instance->o_state = ONCORE_NO_IDEA;
577182007Sroberto	cp = "state = ONCORE_NO_IDEA";
578182007Sroberto	record_clock_stats(&(instance->peer->srcadr), cp);
57954359Sroberto
580182007Sroberto	/* Now open files.
581182007Sroberto	 * This is a bit complicated, a we dont want to open the same file twice
582182007Sroberto	 * (its a problem on some OS), and device2 may not exist for the new PPS
583182007Sroberto	 */
584182007Sroberto
585182007Sroberto	(void)sprintf(device1, DEVICE1, unit);
586182007Sroberto	(void)sprintf(device2, DEVICE2, unit);
587182007Sroberto
588182007Sroberto	/* OPEN DEVICES */
589182007Sroberto	/* opening different devices for fd1 and fd2 presents no problems */
590182007Sroberto	/* opening the SAME device twice, seems to be OS dependent.
591182007Sroberto		(a) on Linux (no streams) no problem
592182007Sroberto		(b) on SunOS (and possibly Solaris, untested), (streams)
593182007Sroberto			never see the line discipline.
594182007Sroberto	   Since things ALWAYS work if we only open the device once, we check
595182007Sroberto	     to see if the two devices are in fact the same, then proceed to
596182007Sroberto	     do one open or two.
597182007Sroberto	*/
598182007Sroberto
599182007Sroberto	if (stat(device1, &stat1)) {
600182007Sroberto		sprintf(Msg, "Can't stat fd1 (%s)\n", device1);
601182007Sroberto		record_clock_stats(&(instance->peer->srcadr), Msg);
602182007Sroberto		exit(1);
60354359Sroberto	}
60454359Sroberto
605182007Sroberto	if (stat(device2, &stat2)) {
606182007Sroberto		sprintf(Msg, "Can't stat fd2 (%s)\n", device2);
607182007Sroberto		record_clock_stats(&(instance->peer->srcadr), Msg);
608182007Sroberto		exit(1);
609182007Sroberto	}
610132451Sroberto
611182007Sroberto	if (!(fd1 = refclock_open(device1, SPEED, LDISC_RAW))) {
612182007Sroberto		sprintf(Msg, "Can't open fd1 (%s)\n", device1);
613182007Sroberto		record_clock_stats(&(instance->peer->srcadr), Msg);
614182007Sroberto		exit(1);
615132451Sroberto	}
616132451Sroberto
617182007Sroberto	if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino))	/* same device here */
618182007Sroberto		fd2 = fd1;
619182007Sroberto	else {	/* different devices here */
620182007Sroberto		if ((fd2=open(device2, O_RDWR)) < 0) {
621182007Sroberto			sprintf(Msg, "Can't open fd2 (%s)\n", device2);
622182007Sroberto			record_clock_stats(&(instance->peer->srcadr), Msg);
623182007Sroberto			exit(1);
624182007Sroberto		}
625182007Sroberto	}
626182007Sroberto	num = fd2;
627182007Sroberto
628182007Sroberto	/* open ppsapi soure */
629182007Sroberto
630182007Sroberto	if (time_pps_create(num, &instance->pps_h) < 0) {
631182007Sroberto		record_clock_stats(&(instance->peer->srcadr), "PPSAPI not found in kernel");
632182007Sroberto		return(0);
633182007Sroberto	}
634182007Sroberto
635182007Sroberto	/* continue initialization */
636182007Sroberto
637182007Sroberto	instance->ttyfd = fd1;
638182007Sroberto	instance->ppsfd = fd2;
639182007Sroberto
640182007Sroberto	/* go read any input data in /etc/ntp.oncoreX or /etc/ntp/oncore.X */
641182007Sroberto
642182007Sroberto	oncore_read_config(instance);
643182007Sroberto
644132451Sroberto	if (!oncore_ppsapi(instance))
645132451Sroberto		return(0);
646132451Sroberto
647132451Sroberto	pp->io.clock_recv = oncore_receive;
648132451Sroberto	pp->io.srcclock = (caddr_t)peer;
649132451Sroberto	pp->io.datalen = 0;
650132451Sroberto	pp->io.fd = fd1;
651132451Sroberto	if (!io_addclock(&pp->io)) {
652182007Sroberto		record_clock_stats(&(instance->peer->srcadr), "ONCORE: io_addclock");
653132451Sroberto		(void) close(fd1);
654132451Sroberto		free(instance);
655132451Sroberto		return (0);
656132451Sroberto	}
657132451Sroberto
658132451Sroberto#ifdef ONCORE_SHMEM_STATUS
659132451Sroberto	/*
660132451Sroberto	 * Before starting ONCORE, lets setup SHMEM
661132451Sroberto	 * This will include merging an old SHMEM into the new one if
662132451Sroberto	 * an old one is found.
663132451Sroberto	 */
664132451Sroberto
665132451Sroberto	oncore_init_shmem(instance);
666132451Sroberto#endif
667132451Sroberto
668132451Sroberto	/*
669132451Sroberto	 * This will return the Model of the Oncore receiver.
670132451Sroberto	 * and start the Initialization loop in oncore_msg_Cj.
671132451Sroberto	 */
672132451Sroberto
673132451Sroberto	instance->o_state = ONCORE_CHECK_ID;
674132451Sroberto	cp = "state = ONCORE_CHECK_ID";
675132451Sroberto	record_clock_stats(&(instance->peer->srcadr), cp);
676132451Sroberto
677132451Sroberto	instance->timeout = 4;
678132451Sroberto	oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Set Posn Fix mode (not Idle (VP)) */
679132451Sroberto	oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
680132451Sroberto
681132451Sroberto	instance->pollcnt = 2;
682132451Sroberto	return (1);
683132451Sroberto}
684132451Sroberto
685132451Sroberto
686132451Sroberto/*
687132451Sroberto * oncore_shutdown - shut down the clock
688132451Sroberto */
689132451Sroberto
690132451Srobertostatic void
691132451Srobertooncore_shutdown(
692132451Sroberto	int unit,
693132451Sroberto	struct peer *peer
694132451Sroberto	)
695132451Sroberto{
696132451Sroberto	register struct instance *instance;
697132451Sroberto	struct refclockproc *pp;
698132451Sroberto
699132451Sroberto	pp = peer->procptr;
700132451Sroberto	instance = (struct instance *) pp->unitptr;
701132451Sroberto
702132451Sroberto	io_closeclock(&pp->io);
703132451Sroberto
704182007Sroberto	time_pps_destroy (instance->pps_h);
705182007Sroberto
706132451Sroberto	close(instance->ttyfd);
707182007Sroberto
708182007Sroberto	if ((instance->ppsfd != -1) && (instance->ppsfd != instance->ttyfd))
709182007Sroberto		close(instance->ppsfd);
710182007Sroberto
711132451Sroberto	if (instance->shmemfd)
712132451Sroberto		close(instance->shmemfd);
713182007Sroberto
714132451Sroberto	free(instance);
715132451Sroberto}
716132451Sroberto
717132451Sroberto
718132451Sroberto
719132451Sroberto/*
720132451Sroberto * oncore_poll - called by the transmit procedure
721132451Sroberto */
722132451Sroberto
723132451Srobertostatic void
724132451Srobertooncore_poll(
725132451Sroberto	int unit,
726132451Sroberto	struct peer *peer
727132451Sroberto	)
728132451Sroberto{
729132451Sroberto	struct instance *instance;
730132451Sroberto
731132451Sroberto	instance = (struct instance *) peer->procptr->unitptr;
732132451Sroberto	if (instance->timeout) {
733132451Sroberto		char	*cp;
734132451Sroberto
735132451Sroberto		instance->timeout--;
736132451Sroberto		if (instance->timeout == 0) {
737132451Sroberto			cp = "Oncore: No response from @@Cj, shutting down driver";
738132451Sroberto			record_clock_stats(&(instance->peer->srcadr), cp);
739132451Sroberto			oncore_shutdown(unit, peer);
740132451Sroberto		} else {
741132451Sroberto			oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
742132451Sroberto			cp = "Oncore: Resend @@Cj";
743132451Sroberto			record_clock_stats(&(instance->peer->srcadr), cp);
744132451Sroberto		}
745132451Sroberto		return;
746132451Sroberto	}
747132451Sroberto
748132451Sroberto	if (!instance->pollcnt)
749132451Sroberto		refclock_report(peer, CEVNT_TIMEOUT);
750132451Sroberto	else
751132451Sroberto		instance->pollcnt--;
752132451Sroberto	peer->procptr->polls++;
753132451Sroberto	instance->polled = 1;
754132451Sroberto}
755132451Sroberto
756132451Sroberto
757132451Sroberto
758132451Sroberto/*
759132451Sroberto * Initialize PPSAPI
760132451Sroberto */
761132451Sroberto
762132451Srobertostatic int
763132451Srobertooncore_ppsapi(
764132451Sroberto	struct instance *instance
765132451Sroberto	)
766132451Sroberto{
767182007Sroberto	int cap, mode, mode1;
768182007Sroberto	char *cp, Msg[160];
769132451Sroberto
770182007Sroberto	if (time_pps_getcap(instance->pps_h, &cap) < 0) {
771182007Sroberto		msyslog(LOG_ERR, "time_pps_getcap failed: %m");
77256746Sroberto		return (0);
77356746Sroberto	}
77456746Sroberto
77556746Sroberto	if (time_pps_getparams(instance->pps_h, &instance->pps_p) < 0) {
776182007Sroberto		msyslog(LOG_ERR, "time_pps_getparams failed: %m");
77756746Sroberto		return (0);
77856746Sroberto	}
77956746Sroberto
78056746Sroberto	/* nb. only turn things on, if someone else has turned something
78182498Sroberto	 *	on before we get here, leave it alone!
78256746Sroberto	 */
78356746Sroberto
784182007Sroberto	if (instance->assert) {
785182007Sroberto		cp = "Assert.";
786182007Sroberto		mode = PPS_CAPTUREASSERT;
787182007Sroberto		mode1 = PPS_OFFSETASSERT;
78854359Sroberto	} else {
789182007Sroberto		cp = "Clear.";
790182007Sroberto		mode = PPS_CAPTURECLEAR;
791182007Sroberto		mode1 = PPS_OFFSETCLEAR;
79254359Sroberto	}
793182007Sroberto	sprintf(Msg, "Initializing timeing to %s.", cp);
794182007Sroberto	record_clock_stats(&(instance->peer->srcadr), Msg);
79556746Sroberto
796182007Sroberto	if (!(mode & cap)) {
797182007Sroberto		sprintf(Msg, "Can't set timeing to %s, exiting...", cp);
798182007Sroberto		record_clock_stats(&(instance->peer->srcadr), Msg);
799182007Sroberto		return(0);
800182007Sroberto	}
801182007Sroberto
802182007Sroberto	if (!(mode1 & cap)) {
803182007Sroberto		sprintf(Msg, "Can't set PPS_%sCLEAR, this will increase jitter.", cp);
804182007Sroberto		record_clock_stats(&(instance->peer->srcadr), Msg);
805182007Sroberto		mode1 = 0;
806182007Sroberto	}
807182007Sroberto
808182007Sroberto	/* only set what is legal */
809182007Sroberto
810182007Sroberto	instance->pps_p.mode = (mode | mode1 | PPS_TSFMT_TSPEC) & cap;
811182007Sroberto
81254359Sroberto	if (time_pps_setparams(instance->pps_h, &instance->pps_p) < 0) {
813182007Sroberto		record_clock_stats(&(instance->peer->srcadr), "ONCORE: time_pps_setparams fails");
81454359Sroberto		exit(1);
81554359Sroberto	}
81656746Sroberto
817132451Sroberto	/* If HARDPPS is on, we tell kernel */
81882498Sroberto
819132451Sroberto	if (instance->hardpps) {
820132451Sroberto		int	i;
82182498Sroberto
822182007Sroberto		record_clock_stats(&(instance->peer->srcadr), "HARDPPS Set.");
823182007Sroberto
824132451Sroberto		if (instance->assert)
825132451Sroberto			i = PPS_CAPTUREASSERT;
826132451Sroberto		else
827132451Sroberto			i = PPS_CAPTURECLEAR;
82882498Sroberto
829182007Sroberto		/* we know that 'i' is legal from above */
830182007Sroberto
831182007Sroberto		if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i,
832182007Sroberto		    PPS_TSFMT_TSPEC) < 0) {
833182007Sroberto			msyslog(LOG_ERR, "time_pps_kcbind failed: %m");
834182007Sroberto			record_clock_stats(&(instance->peer->srcadr), "HARDPPS failed, abort...");
835182007Sroberto			return (0);
83656746Sroberto		}
837182007Sroberto		pps_enable = 1;
83854359Sroberto	}
839132451Sroberto	return(1);
840132451Sroberto}
84156746Sroberto
842132451Sroberto
843132451Sroberto
844132451Sroberto#ifdef ONCORE_SHMEM_STATUS
845132451Srobertostatic void
846132451Srobertooncore_init_shmem(
847132451Sroberto	struct instance *instance
848132451Sroberto	)
849132451Sroberto{
850132451Sroberto	int i, l, n, fd, shmem_old_size, n1;
851182007Sroberto	char Msg[160];
852182007Sroberto	u_char *cp, *cp1, *buf, *shmem_old;
853132451Sroberto	struct msg_desc *mp;
854132451Sroberto	struct stat sbuf;
855132451Sroberto	size_t shmem_length;
856132451Sroberto
857132451Sroberto       /*
858132451Sroberto	* The first thing we do is see if there is an instance->shmem_fname file (still)
859132451Sroberto	* out there from a previous run.  If so, we copy it in and use it to initialize
860132451Sroberto	* shmem (so we won't lose our almanac if we need it).
861132451Sroberto	*/
862132451Sroberto
863132451Sroberto	shmem_old = 0;
864182007Sroberto	shmem_old_size = 0;
865132451Sroberto	if ((fd = open(instance->shmem_fname, O_RDONLY)) < 0)
866182007Sroberto		record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't open SHMEM file");
867132451Sroberto	else {
868132451Sroberto		fstat(fd, &sbuf);
869132451Sroberto		shmem_old_size = sbuf.st_size;
870182007Sroberto		if (shmem_old_size != 0) {
871182007Sroberto			shmem_old = (u_char *) malloc((unsigned) sbuf.st_size);
872182007Sroberto			if (shmem_old == NULL)
873182007Sroberto				record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't malloc buffer for shmem_old");
874182007Sroberto			else
875182007Sroberto				read(fd, shmem_old, shmem_old_size);
876132451Sroberto		}
877132451Sroberto		close(fd);
87854359Sroberto	}
87954359Sroberto
880132451Sroberto	/* OK, we now create the NEW SHMEM. */
881132451Sroberto
882132451Sroberto	if ((instance->shmemfd = open(instance->shmem_fname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) {
883182007Sroberto		record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't open shmem");
884182007Sroberto		if (shmem_old)
885182007Sroberto			free(shmem_old);
886182007Sroberto
887132451Sroberto		return;
888132451Sroberto	}
889132451Sroberto
890132451Sroberto	/* see how big it needs to be */
891132451Sroberto
892132451Sroberto	n = 1;
893132451Sroberto	for (mp=oncore_messages; mp->flag[0]; mp++) {
894132451Sroberto		mp->shmem = n;
895132451Sroberto		/* Allocate space for multiplexed almanac, and 0D/2D/3D @@Ea records */
896132451Sroberto		if (!strcmp(mp->flag, "Cb")) {
897132451Sroberto			instance->shmem_Cb = n;
898132451Sroberto			n += (mp->len + 3) * 34;
899132451Sroberto		}
900132451Sroberto		if (!strcmp(mp->flag, "Ba")) {
901132451Sroberto			instance->shmem_Ba = n;
902132451Sroberto			n += (mp->len + 3) * 3;
903132451Sroberto		}
904132451Sroberto		if (!strcmp(mp->flag, "Ea")) {
905132451Sroberto			instance->shmem_Ea = n;
906132451Sroberto			n += (mp->len + 3) * 3;
907132451Sroberto		}
908132451Sroberto		if (!strcmp(mp->flag, "Ha")) {
909132451Sroberto			instance->shmem_Ha = n;
910132451Sroberto			n += (mp->len + 3) * 3;
911132451Sroberto		}
912132451Sroberto		n += (mp->len + 3);
913132451Sroberto	}
914132451Sroberto	shmem_length = n + 2;
915132451Sroberto
916132451Sroberto	buf = malloc(shmem_length);
917132451Sroberto	if (buf == NULL) {
918182007Sroberto		record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't malloc buffer for shmem");
919132451Sroberto		close(instance->shmemfd);
920182007Sroberto		if (shmem_old)
921182007Sroberto			free(shmem_old);
922182007Sroberto
923132451Sroberto		return;
924132451Sroberto	}
925132451Sroberto
926132451Sroberto	memset(buf, 0, shmem_length);
927132451Sroberto
928132451Sroberto	/* next build the new SHMEM buffer in memory */
929132451Sroberto
930132451Sroberto	for (mp=oncore_messages; mp->flag[0]; mp++) {
931132451Sroberto		l = mp->shmem;
932132451Sroberto		buf[l + 0] = mp->len >> 8;
933132451Sroberto		buf[l + 1] = mp->len & 0xff;
934132451Sroberto		buf[l + 2] = 0;
935132451Sroberto		buf[l + 3] = '@';
936132451Sroberto		buf[l + 4] = '@';
937132451Sroberto		buf[l + 5] = mp->flag[0];
938132451Sroberto		buf[l + 6] = mp->flag[1];
939132451Sroberto		if (!strcmp(mp->flag, "Cb") || !strcmp(mp->flag, "Ba") || !strcmp(mp->flag, "Ea") || !strcmp(mp->flag, "Ha")) {
940132451Sroberto			if (!strcmp(mp->flag, "Cb"))
941132451Sroberto				n = 35;
942132451Sroberto			else
943132451Sroberto				n = 4;
944132451Sroberto			for (i=1; i<n; i++) {
945132451Sroberto				buf[l + i * (mp->len+3) + 0] = mp->len >> 8;
946132451Sroberto				buf[l + i * (mp->len+3) + 1] = mp->len & 0xff;
947132451Sroberto				buf[l + i * (mp->len+3) + 2] = 0;
948132451Sroberto				buf[l + i * (mp->len+3) + 3] = '@';
949132451Sroberto				buf[l + i * (mp->len+3) + 4] = '@';
950132451Sroberto				buf[l + i * (mp->len+3) + 5] = mp->flag[0];
951132451Sroberto				buf[l + i * (mp->len+3) + 6] = mp->flag[1];
952132451Sroberto			}
953132451Sroberto		}
954132451Sroberto	}
955132451Sroberto
956132451Sroberto	/* we now walk thru the two buffers (shmem_old and buf, soon to become shmem)
957182007Sroberto	 * copying the data in shmem_old to buf.
958182007Sroberto	 * When we are done we write it out and free both buffers.
959182007Sroberto	 * If the structure sizes dont agree, I will not copy.
960182007Sroberto	 * This could be due to an addition/deletion or a problem with the disk file.
96154359Sroberto	 */
96254359Sroberto
963132451Sroberto	if (shmem_old) {
964182007Sroberto		if (shmem_old_size == shmem_length) {
965182007Sroberto			for (cp=buf+4, cp1=shmem_old+4; (n = 256*(*(cp-3)) + *(cp-2));	cp+=(n+3), cp1+=(n+3)) {
966182007Sroberto				n1 = 256*(*(cp1-3)) + *(cp1-2);
967182007Sroberto				if (n == 0 || n1 != n || strncmp((char *) cp, (char *) cp1, 4))
968182007Sroberto					break;
96954359Sroberto
970182007Sroberto				memcpy(cp, cp1, (size_t) n);
971182007Sroberto			}
972132451Sroberto		}
973132451Sroberto		free(shmem_old);
974132451Sroberto	}
975132451Sroberto
976132451Sroberto	i = write(instance->shmemfd, buf, shmem_length);
977132451Sroberto	free(buf);
978132451Sroberto
979132451Sroberto	if (i != shmem_length) {
980182007Sroberto		record_clock_stats(&(instance->peer->srcadr), "ONCORE: error writing shmem");
981132451Sroberto		close(instance->shmemfd);
982132451Sroberto		return;
983132451Sroberto	}
984132451Sroberto
985132451Sroberto	instance->shmem = (u_char *) mmap(0, shmem_length,
986132451Sroberto		PROT_READ | PROT_WRITE,
987132451Sroberto#ifdef MAP_HASSEMAPHORE
988132451Sroberto		MAP_HASSEMAPHORE |
989132451Sroberto#endif
990132451Sroberto		MAP_SHARED, instance->shmemfd, (off_t)0);
991132451Sroberto
992132451Sroberto	if (instance->shmem == (u_char *)MAP_FAILED) {
993132451Sroberto		instance->shmem = 0;
994132451Sroberto		close(instance->shmemfd);
995132451Sroberto		return;
996132451Sroberto	}
997132451Sroberto
998182007Sroberto	sprintf(Msg, "SHMEM (size = %ld) is CONFIGURED and available as %s",
999182007Sroberto		(u_long) shmem_length, instance->shmem_fname);
1000132451Sroberto	record_clock_stats(&(instance->peer->srcadr), Msg);
100154359Sroberto}
1002132451Sroberto#endif /* ONCORE_SHMEM_STATUS */
100354359Sroberto
100456746Sroberto
100556746Sroberto
100654359Sroberto/*
100754359Sroberto * Read Input file if it exists.
100854359Sroberto */
100982498Sroberto
101054359Srobertostatic void
101154359Srobertooncore_read_config(
101254359Sroberto	struct instance *instance
101354359Sroberto	)
101454359Sroberto{
101554359Sroberto/*
101682498Sroberto * First we try to open the configuration file
101782498Sroberto *    /etc/oncoreN
101882498Sroberto * where N is the unit number viz 127.127.30.N.
101982498Sroberto * If we don't find it we try
102082498Sroberto *    /etc/ntp.oncore.N
102182498Sroberto * and then
102282498Sroberto *    /etc/ntp.oncore
102354359Sroberto *
102482498Sroberto * If we don't find any then we don't have the cable delay or PPS offset
102554359Sroberto * and we choose MODE (4) below.
102654359Sroberto *
102754359Sroberto * Five Choices for MODE
102854359Sroberto *    (0) ONCORE is preinitialized, don't do anything to change it.
102954359Sroberto *	    nb, DON'T set 0D mode, DON'T set Delay, position...
103054359Sroberto *    (1) NO RESET, Read Position, delays from data file, lock it in, go to 0D mode.
103154359Sroberto *    (2) NO RESET, Read Delays from data file, do SITE SURVEY to get position,
103254359Sroberto *		    lock this in, go to 0D mode.
103354359Sroberto *    (3) HARD RESET, Read Position, delays from data file, lock it in, go to 0D mode.
103454359Sroberto *    (4) HARD RESET, Read Delays from data file, do SITE SURVEY to get position,
103554359Sroberto *		    lock this in, go to 0D mode.
103654359Sroberto *     NB. If a POSITION is specified in the config file with mode=(2,4) [SITE SURVEY]
103754359Sroberto *	   then this position is set as the INITIAL position of the ONCORE.
103854359Sroberto *	   This can reduce the time to first fix.
103954359Sroberto * -------------------------------------------------------------------------------
104054359Sroberto * Note that an Oncore UT without a battery backup retains NO information if it is
104154359Sroberto *   power cycled, with a Battery Backup it remembers the almanac, etc.
104254359Sroberto * For an Oncore VP, there is an eeprom that will contain this data, along with the
104354359Sroberto *   option of Battery Backup.
104454359Sroberto * So a UT without Battery Backup is equivalent to doing a HARD RESET on each
104554359Sroberto *   power cycle, since there is nowhere to store the data.
104654359Sroberto * -------------------------------------------------------------------------------
104754359Sroberto *
104854359Sroberto * If we open one or the other of the files, we read it looking for
1049132451Sroberto *   MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET, ASSERT, CLEAR, HARDPPS,
1050132451Sroberto *   STATUS, POSN3D, POSN2D, CHAN, TRAIM
105154359Sroberto * then initialize using method MODE.  For Mode = (1,3) all of (LAT, LON, HT) must
105254359Sroberto *   be present or mode reverts to (2,4).
105354359Sroberto *
105454359Sroberto * Read input file.
105554359Sroberto *
105654359Sroberto *	# is comment to end of line
105754359Sroberto *	= allowed between 1st and 2nd fields.
105854359Sroberto *
105954359Sroberto *	Expect to see one line with 'MODE' as first field, followed by an integer
106054359Sroberto *	   in the range 0-4 (default = 4).
106154359Sroberto *
106254359Sroberto *	Expect to see two lines with 'LONG', 'LAT' followed by 1-3 fields.
106354359Sroberto *	All numbers are floating point.
106454359Sroberto *		DDD.ddd
106554359Sroberto *		DDD  MMM.mmm
106654359Sroberto *		DDD  MMM  SSS.sss
106754359Sroberto *
106882498Sroberto *	Expect to see one line with 'HT' as first field,
106982498Sroberto *	   followed by 1-2 fields.  First is a number, the second is 'FT' or 'M'
107082498Sroberto *	   for feet or meters.	HT is the height above the GPS ellipsoid.
1071132451Sroberto *	   If the receiver reports height in both GPS and MSL, then we will report
107282498Sroberto *	   the difference GPS-MSL on the clockstats file.
107354359Sroberto *
107482498Sroberto *	There is an optional line, starting with DELAY, followed
107554359Sroberto *	   by 1 or two fields.	The first is a number (a time) the second is
107654359Sroberto *	   'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
107782498Sroberto *	    DELAY  is cable delay, typically a few tens of ns.
107882498Sroberto *
107982498Sroberto *	There is an optional line, starting with OFFSET, followed
108082498Sroberto *	   by 1 or two fields.	The first is a number (a time) the second is
108182498Sroberto *	   'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
108282498Sroberto *	   OFFSET is the offset of the PPS pulse from 0. (only fully implemented
108354359Sroberto *		with the PPSAPI, we need to be able to tell the Kernel about this
108454359Sroberto *		offset if the Kernel PLL is in use, but can only do this presently
108554359Sroberto *		when using the PPSAPI interface.  If not using the Kernel PLL,
108654359Sroberto *		then there is no problem.
108754359Sroberto *
108882498Sroberto *	There is an optional line, with either ASSERT or CLEAR on it, which
108954359Sroberto *	   determine which transition of the PPS signal is used for timing by the
109054359Sroberto *	   PPSAPI.  If neither is present, then ASSERT is assumed.
1091132451Sroberto *	   ASSERT/CLEAR can also be set with FLAG2 of the ntp.conf input.
1092132451Sroberto *	   For Flag2, ASSERT=0, and hence is default.
109354359Sroberto *
1094132451Sroberto *	There is an optional line, with HARDPPS on it.	Including this line causes
1095132451Sroberto *	   the PPS signal to control the kernel PLL.
1096132451Sroberto *	   HARDPPS can also be set with FLAG3 of the ntp.conf input.
1097132451Sroberto *	   For Flag3, 0 is disabled, and the default.
1098132451Sroberto *
1099132451Sroberto *	There are three options that have to do with using the shared memory option.
1100132451Sroberto *	   First, to enable the option there must be a SHMEM line with a file name.
110182498Sroberto *	   The file name is the file associated with the shared memory.
110282498Sroberto *
1103132451Sroberto *	In shared memory, there is one 'record' for each returned variable.
1104132451Sroberto *	For the @@Ea data there are three 'records' containing position data.
1105132451Sroberto *	   There will always be data in the record corresponding to the '0D' @@Ea record,
1106132451Sroberto *	   and the user has a choice of filling the '3D' record by specifying POSN3D,
1107132451Sroberto *	   or the '2D' record by specifying POSN2D.  In either case the '2D' or '3D'
1108132451Sroberto *	   record is filled once every 15s.
110982498Sroberto *
111082498Sroberto *	Two additional variables that can be set are CHAN and TRAIM.  These should be
111182498Sroberto *	   set correctly by the code examining the @@Cj record, but we bring them out here
1112132451Sroberto *	   to allow the user to override either the # of channels, or the existence of TRAIM.
111382498Sroberto *	   CHAN expects to be followed by in integer: 6, 8, or 12. TRAIM expects to be
111482498Sroberto *	   followed by YES or NO.
111582498Sroberto *
1116132451Sroberto *	There is an optional line with MASK on it followed by one integer field in the
1117132451Sroberto *	   range 0 to 89. This sets the satellite mask angle and will determine the minimum
1118132451Sroberto *	   elevation angle for satellites to be tracked by the receiver. The default value
1119132451Sroberto *	   is 10 deg for the VP and 0 deg for all other receivers.
1120132451Sroberto *
112154359Sroberto * So acceptable input would be
112254359Sroberto *	# these are my coordinates (RWC)
112354359Sroberto *	LON  -106 34.610
112454359Sroberto *	LAT    35 08.999
112554359Sroberto *	HT	1589	# could equally well say HT 5215 FT
112654359Sroberto *	DELAY  60 ns
112754359Sroberto */
112854359Sroberto
112954359Sroberto	FILE	*fd;
1130182007Sroberto	char	*cp, *cc, *ca, line[100], units[2], device[20], Msg[160], **cpp;
1131182007Sroberto	char	*dirs[] = { "/etc/ntp", "/etc", 0 };
1132132451Sroberto	int	i, sign, lat_flg, long_flg, ht_flg, mode, mask;
113354359Sroberto	double	f1, f2, f3;
113454359Sroberto
1135182007Sroberto	fd = NULL;	/* just to shutup gcc complaint */
1136182007Sroberto	for (cpp=dirs; *cpp; cpp++) {
1137182007Sroberto		cp = *cpp;
1138182007Sroberto		sprintf(device, "%s/ntp.oncore.%d", cp, instance->unit); /* try "ntp.oncore.0 */
1139182007Sroberto		if ((fd=fopen(device, "r")))
1140182007Sroberto			break;
1141182007Sroberto		sprintf(device, "%s/ntp.oncore%d", cp, instance->unit);  /* try "ntp.oncore0" */
1142182007Sroberto		if ((fd=fopen(device, "r")))
1143182007Sroberto			break;
1144182007Sroberto		sprintf(device, "%s/ntp.oncore", cp);   /* and finally "ntp.oncore" */
1145182007Sroberto		if ((fd=fopen(device, "r")))
1146182007Sroberto			break;
114782498Sroberto	}
114854359Sroberto
1149182007Sroberto	if (!fd) {	/* no inputfile, default to the works ... */
1150182007Sroberto		instance->init_type = 4;
1151182007Sroberto		return;
1152182007Sroberto	}
1153182007Sroberto
1154132451Sroberto	mode = mask = 0;
115554359Sroberto	lat_flg = long_flg = ht_flg = 0;
115654359Sroberto	while (fgets(line, 100, fd)) {
115756746Sroberto
115856746Sroberto		/* Remove comments */
115956746Sroberto		if ((cp = strchr(line, '#')))
116054359Sroberto			*cp = '\0';
116182498Sroberto
116256746Sroberto		/* Remove trailing space */
116356746Sroberto		for (i = strlen(line);
116456746Sroberto		     i > 0 && isascii((int)line[i - 1]) && isspace((int)line[i - 1]);
116556746Sroberto			)
116656746Sroberto			line[--i] = '\0';
116756746Sroberto
116856746Sroberto		/* Remove leading space */
116956746Sroberto		for (cc = line; *cc && isascii((int)*cc) && isspace((int)*cc); cc++)
117056746Sroberto			continue;
117156746Sroberto
117256746Sroberto		/* Stop if nothing left */
117356746Sroberto		if (!*cc)
117456746Sroberto			continue;
117556746Sroberto
117682498Sroberto		/* Uppercase the command and find the arg */
117756746Sroberto		for (ca = cc; *ca; ca++) {
117882498Sroberto			if (isascii((int)*ca)) {
117982498Sroberto				if (islower((int)*ca)) {
118082498Sroberto					*ca = toupper(*ca);
118182498Sroberto				} else if (isspace((int)*ca) || (*ca == '='))
118282498Sroberto					break;
118356746Sroberto			}
118456746Sroberto		}
118582498Sroberto
118682498Sroberto		/* Remove space (and possible =) leading the arg */
118782498Sroberto		for (; *ca && isascii((int)*ca) && (isspace((int)*ca) || (*ca == '=')); ca++)
118856746Sroberto			continue;
118956746Sroberto
119082498Sroberto		if (!strncmp(cc, "STATUS", (size_t) 6) || !strncmp(cc, "SHMEM", (size_t) 5)) {
119182498Sroberto			i = strlen(ca);
119282498Sroberto			instance->shmem_fname = (char *) malloc((unsigned) (i+1));
119382498Sroberto			strcpy(instance->shmem_fname, ca);
119456746Sroberto			continue;
119556746Sroberto		}
119656746Sroberto
119756746Sroberto		/* Uppercase argument as well */
119856746Sroberto		for (cp = ca; *cp; cp++)
119956746Sroberto			if (isascii((int)*cp) && islower((int)*cp))
120056746Sroberto				*cp = toupper(*cp);
120156746Sroberto
120282498Sroberto		if (!strncmp(cc, "LAT", (size_t) 3)) {
120354359Sroberto			f1 = f2 = f3 = 0;
120456746Sroberto			sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
120554359Sroberto			sign = 1;
120654359Sroberto			if (f1 < 0) {
120754359Sroberto				f1 = -f1;
120854359Sroberto				sign = -1;
120954359Sroberto			}
121054359Sroberto			instance->ss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
121154359Sroberto			lat_flg++;
121282498Sroberto		} else if (!strncmp(cc, "LON", (size_t) 3)) {
121354359Sroberto			f1 = f2 = f3 = 0;
121456746Sroberto			sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
121554359Sroberto			sign = 1;
121654359Sroberto			if (f1 < 0) {
121754359Sroberto				f1 = -f1;
121854359Sroberto				sign = -1;
121954359Sroberto			}
122054359Sroberto			instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
122154359Sroberto			long_flg++;
122282498Sroberto		} else if (!strncmp(cc, "HT", (size_t) 2)) {
122354359Sroberto			f1 = 0;
122454359Sroberto			units[0] = '\0';
122556746Sroberto			sscanf(ca, "%lf %1s", &f1, units);
122654359Sroberto			if (units[0] == 'F')
122754359Sroberto				f1 = 0.3048 * f1;
122854359Sroberto			instance->ss_ht = 100 * f1;    /* cm */
122954359Sroberto			ht_flg++;
123082498Sroberto		} else if (!strncmp(cc, "DELAY", (size_t) 5)) {
123154359Sroberto			f1 = 0;
123254359Sroberto			units[0] = '\0';
123356746Sroberto			sscanf(ca, "%lf %1s", &f1, units);
123454359Sroberto			if (units[0] == 'N')
123554359Sroberto				;
123654359Sroberto			else if (units[0] == 'U')
123754359Sroberto				f1 = 1000 * f1;
123854359Sroberto			else if (units[0] == 'M')
123954359Sroberto				f1 = 1000000 * f1;
124054359Sroberto			else
124154359Sroberto				f1 = 1000000000 * f1;
124254359Sroberto			if (f1 < 0 || f1 > 1.e9)
124354359Sroberto				f1 = 0;
124482498Sroberto			if (f1 < 0 || f1 > 999999) {
124582498Sroberto				sprintf(Msg, "PPS Cable delay of %fns out of Range, ignored", f1);
124682498Sroberto				record_clock_stats(&(instance->peer->srcadr), Msg);
124782498Sroberto			} else
124882498Sroberto				instance->delay = f1;		/* delay in ns */
124982498Sroberto		} else if (!strncmp(cc, "OFFSET", (size_t) 6)) {
125054359Sroberto			f1 = 0;
125154359Sroberto			units[0] = '\0';
125256746Sroberto			sscanf(ca, "%lf %1s", &f1, units);
125354359Sroberto			if (units[0] == 'N')
125454359Sroberto				;
125554359Sroberto			else if (units[0] == 'U')
125654359Sroberto				f1 = 1000 * f1;
125754359Sroberto			else if (units[0] == 'M')
125854359Sroberto				f1 = 1000000 * f1;
125954359Sroberto			else
126054359Sroberto				f1 = 1000000000 * f1;
126154359Sroberto			if (f1 < 0 || f1 > 1.e9)
126254359Sroberto				f1 = 0;
126382498Sroberto			if (f1 < 0 || f1 > 999999999.) {
126482498Sroberto				sprintf(Msg, "PPS Offset of %fns out of Range, ignored", f1);
126582498Sroberto				record_clock_stats(&(instance->peer->srcadr), Msg);
126682498Sroberto			} else
126782498Sroberto				instance->offset = f1;		/* offset in ns */
126882498Sroberto		} else if (!strncmp(cc, "MODE", (size_t) 4)) {
126956746Sroberto			sscanf(ca, "%d", &mode);
127054359Sroberto			if (mode < 0 || mode > 4)
127154359Sroberto				mode = 4;
127282498Sroberto		} else if (!strncmp(cc, "ASSERT", (size_t) 6)) {
127354359Sroberto			instance->assert = 1;
127482498Sroberto		} else if (!strncmp(cc, "CLEAR", (size_t) 5)) {
127554359Sroberto			instance->assert = 0;
1276132451Sroberto		} else if (!strncmp(cc, "HARDPPS", (size_t) 7)) {
1277132451Sroberto			instance->hardpps = 1;
127882498Sroberto		} else if (!strncmp(cc, "POSN2D", (size_t) 6)) {
127982498Sroberto			instance->shmem_Posn = 2;
128082498Sroberto		} else if (!strncmp(cc, "POSN3D", (size_t) 6)) {
128182498Sroberto			instance->shmem_Posn = 3;
128282498Sroberto		} else if (!strncmp(cc, "CHAN", (size_t) 4)) {
128382498Sroberto			sscanf(ca, "%d", &i);
128482498Sroberto			if ((i == 6) || (i == 8) || (i == 12))
1285132451Sroberto				instance->chan_in = i;
128682498Sroberto		} else if (!strncmp(cc, "TRAIM", (size_t) 5)) {
1287132451Sroberto			instance->traim_in = 1; 	/* so TRAIM alone is YES */
128882498Sroberto			if (!strcmp(ca, "NO") || !strcmp(ca, "OFF"))    /* Yes/No, On/Off */
1289132451Sroberto				instance->traim_in = 0;
1290132451Sroberto		} else if (!strncmp(cc, "MASK", (size_t) 4)) {
1291132451Sroberto			sscanf(ca, "%d", &mask);
1292132451Sroberto			if (mask > -1 && mask < 90)
1293132451Sroberto				instance->Ag = mask;			/* Satellite mask angle */
129454359Sroberto		}
129554359Sroberto	}
129654359Sroberto	fclose(fd);
129754359Sroberto
129854359Sroberto	/*
129954359Sroberto	 *    OK, have read all of data file, and extracted the good stuff.
130054359Sroberto	 *    If lat/long/ht specified they ALL must be specified for mode = (1,3).
130154359Sroberto	 */
130254359Sroberto
130354359Sroberto	instance->posn_set = 1;
1304132451Sroberto	if (!( lat_flg && long_flg && ht_flg )) {
1305182007Sroberto		printf("ONCORE: incomplete data on %s\n", device);
130654359Sroberto		instance->posn_set = 0;
130782498Sroberto		if (mode == 1 || mode == 3) {
130882498Sroberto			sprintf(Msg, "Input Mode = %d, but no/incomplete position, mode set to %d", mode, mode+1);
130982498Sroberto			record_clock_stats(&(instance->peer->srcadr), Msg);
131082498Sroberto			mode++;
131182498Sroberto		}
131254359Sroberto	}
131382498Sroberto	instance->init_type = mode;
131482498Sroberto
131582498Sroberto	sprintf(Msg, "Input mode = %d", mode);
131682498Sroberto	record_clock_stats(&(instance->peer->srcadr), Msg);
131754359Sroberto}
131854359Sroberto
131954359Sroberto
132054359Sroberto
132154359Sroberto/*
1322132451Sroberto * move data from NTP to buffer (toss the extra in the unlikely case it won't fit)
132354359Sroberto */
132482498Sroberto
132554359Srobertostatic void
132654359Srobertooncore_receive(
132754359Sroberto	struct recvbuf *rbufp
132854359Sroberto	)
132954359Sroberto{
133082498Sroberto	size_t i;
133154359Sroberto	u_char *p;
133254359Sroberto	struct peer *peer;
133354359Sroberto	struct instance *instance;
133454359Sroberto
133554359Sroberto	peer = (struct peer *)rbufp->recv_srcclock;
133654359Sroberto	instance = (struct instance *) peer->procptr->unitptr;
133754359Sroberto	p = (u_char *) &rbufp->recv_space;
133854359Sroberto
133954359Sroberto#if 0
134054359Sroberto	if (debug > 4) {
134154359Sroberto		int i;
134254359Sroberto		printf("ONCORE: >>>");
134354359Sroberto		for(i=0; i<rbufp->recv_length; i++)
134454359Sroberto			printf("%02x ", p[i]);
134554359Sroberto		printf("\n");
134654359Sroberto		printf("ONCORE: >>>");
134754359Sroberto		for(i=0; i<rbufp->recv_length; i++)
134854359Sroberto			printf("%03o ", p[i]);
134954359Sroberto		printf("\n");
135054359Sroberto	}
135154359Sroberto#endif
135254359Sroberto
135354359Sroberto	i = rbufp->recv_length;
135454359Sroberto	if (rcvbuf+rcvptr+i > &rcvbuf[sizeof rcvbuf])
135554359Sroberto		i = sizeof(rcvbuf) - rcvptr;	/* and some char will be lost */
135654359Sroberto	memcpy(rcvbuf+rcvptr, p, i);
135754359Sroberto	rcvptr += i;
135854359Sroberto	oncore_consume(instance);
135954359Sroberto}
136054359Sroberto
136154359Sroberto
136254359Sroberto
136354359Sroberto/*
136454359Sroberto * Deal with any complete messages
136554359Sroberto */
136682498Sroberto
136754359Srobertostatic void
136854359Srobertooncore_consume(
136954359Sroberto	struct instance *instance
137054359Sroberto	)
137154359Sroberto{
1372132451Sroberto	int i, m;
137356746Sroberto	unsigned l;
137454359Sroberto
137554359Sroberto	while (rcvptr >= 7) {
137654359Sroberto		if (rcvbuf[0] != '@' || rcvbuf[1] != '@') {
137754359Sroberto			/* We're not in sync, lets try to get there */
137854359Sroberto			for (i=1; i < rcvptr-1; i++)
137954359Sroberto				if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@')
138054359Sroberto					break;
1381182007Sroberto#ifdef DEBUG
138254359Sroberto			if (debug > 4)
138382498Sroberto				printf("ONCORE[%d]: >>> skipping %d chars\n", instance->unit, i);
1384182007Sroberto#endif
138554359Sroberto			if (i != rcvptr)
138682498Sroberto				memcpy(rcvbuf, rcvbuf+i, (size_t)(rcvptr-i));
138754359Sroberto			rcvptr -= i;
138882498Sroberto			continue;
138954359Sroberto		}
139054359Sroberto
139154359Sroberto		/* Ok, we have a header now */
139254359Sroberto		l = sizeof(oncore_messages)/sizeof(oncore_messages[0]) -1;
139354359Sroberto		for(m=0; m<l; m++)
139482498Sroberto			if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), (size_t) 2))
139554359Sroberto				break;
139682498Sroberto		if (m == l) {
1397182007Sroberto#ifdef DEBUG
139882498Sroberto			if (debug > 4)
139982498Sroberto				printf("ONCORE[%d]: >>> Unknown MSG, skipping 4 (%c%c)\n", instance->unit, rcvbuf[2], rcvbuf[3]);
1400182007Sroberto#endif
140182498Sroberto			memcpy(rcvbuf, rcvbuf+4, (size_t) 4);
140282498Sroberto			rcvptr -= 4;
140382498Sroberto			continue;
140482498Sroberto		}
140582498Sroberto
140654359Sroberto		l = oncore_messages[m].len;
140754359Sroberto#if 0
140854359Sroberto		if (debug > 3)
140982498Sroberto			printf("ONCORE[%d]: GOT: %c%c  %d of %d entry %d\n", instance->unit, rcvbuf[2], rcvbuf[3], rcvptr, l, m);
141054359Sroberto#endif
141154359Sroberto		/* Got the entire message ? */
141254359Sroberto
141354359Sroberto		if (rcvptr < l)
141454359Sroberto			return;
141554359Sroberto
141682498Sroberto		/* are we at the end of message? should be <Cksum><CR><LF> */
141754359Sroberto
141882498Sroberto		if (rcvbuf[l-2] != '\r' || rcvbuf[l-1] != '\n') {
1419182007Sroberto#ifdef DEBUG
142082498Sroberto			if (debug)
142182498Sroberto				printf("ONCORE[%d]: NO <CR><LF> at end of message\n", instance->unit);
1422182007Sroberto#endif
142382498Sroberto		} else {	/* check the CheckSum */
1424132451Sroberto			if (oncore_checksum_ok(rcvbuf, l)) {
142582498Sroberto				if (instance->shmem != NULL) {
142682498Sroberto					instance->shmem[oncore_messages[m].shmem + 2]++;
142782498Sroberto					memcpy(instance->shmem + oncore_messages[m].shmem + 3,
142882498Sroberto					    rcvbuf, (size_t) l);
142982498Sroberto				}
143082498Sroberto				oncore_msg_any(instance, rcvbuf, (size_t) (l-3), m);
143182498Sroberto				if (oncore_messages[m].handler)
143282498Sroberto					oncore_messages[m].handler(instance, rcvbuf, (size_t) (l-3));
1433182007Sroberto			}
1434182007Sroberto#ifdef DEBUG
1435182007Sroberto			else if (debug) {
1436132451Sroberto				printf("ONCORE[%d]: Checksum mismatch!\n", instance->unit);
143782498Sroberto				printf("ONCORE[%d]: @@%c%c ", instance->unit, rcvbuf[2], rcvbuf[3]);
143882498Sroberto				for (i=4; i<l; i++)
143982498Sroberto					printf("%03o ", rcvbuf[i]);
144082498Sroberto				printf("\n");
144182498Sroberto			}
1442182007Sroberto#endif
144354359Sroberto		}
144454359Sroberto
144554359Sroberto		if (l != rcvptr)
144682498Sroberto			memcpy(rcvbuf, rcvbuf+l, (size_t) (rcvptr-l));
144754359Sroberto		rcvptr -= l;
144854359Sroberto	}
144954359Sroberto}
145054359Sroberto
145154359Sroberto
145254359Sroberto
145354359Srobertostatic void
1454132451Srobertooncore_get_timestamp(
1455132451Sroberto	struct instance *instance,
1456132451Sroberto	long dt1,	/* tick offset THIS time step */
1457132451Sroberto	long dt2	/* tick offset NEXT time step */
145854359Sroberto	)
145954359Sroberto{
1460132451Sroberto	int	Rsm;
1461182007Sroberto	u_long	j;
1462132451Sroberto	l_fp ts, ts_tmp;
1463132451Sroberto	double dmy;
1464132451Sroberto#ifdef HAVE_STRUCT_TIMESPEC
1465132451Sroberto	struct timespec *tsp = 0;
1466132451Sroberto#else
1467132451Sroberto	struct timeval	*tsp = 0;
1468132451Sroberto#endif
1469132451Sroberto	int	current_mode;
1470182007Sroberto	u_long	i;
1471132451Sroberto	pps_params_t current_params;
1472132451Sroberto	struct timespec timeout;
1473132451Sroberto	pps_info_t pps_i;
147454359Sroberto
1475132451Sroberto#if 1
1476132451Sroberto	/* If we are in SiteSurvey mode, then we are in 3D mode, and we fall thru.
1477132451Sroberto	 * If we have Finished the SiteSurvey, then we fall thru for the 14/15
1478132451Sroberto	 *  times we get here in 0D mode (the 1/15 is in 3D for SHMEM).
1479132451Sroberto	 * This gives good time, which gets better when the SS is done.
1480132451Sroberto	 */
1481132451Sroberto
1482132451Sroberto	if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D))
1483132451Sroberto#else
1484132451Sroberto	/* old check, only fall thru for SS_DONE and 0D mode, 2h45m wait for ticks */
1485132451Sroberto
1486132451Sroberto	if ((instance->site_survey != ONCORE_SS_DONE) || (instance->mode != MODE_0D))
1487132451Sroberto#endif
1488132451Sroberto		return;
1489132451Sroberto
1490132451Sroberto	/* Don't do anything without an almanac to define the GPS->UTC delta */
1491132451Sroberto
1492132451Sroberto	if (instance->rsm.bad_almanac)
1493132451Sroberto		return;
1494132451Sroberto
1495182007Sroberto	/* Once the Almanac is valid, the M12+T does not produce valid UTC
1496182007Sroberto	 * immediately.
1497182007Sroberto	 * Wait for UTC offset decode valid, then wait one message more
1498182007Sroberto	 * so we are not off by 13 seconds after  reset.
1499182007Sroberto	 */
1500182007Sroberto
1501182007Sroberto	if (instance->count5) {
1502182007Sroberto		instance->count5--;
1503182007Sroberto		return;
1504182007Sroberto	}
1505182007Sroberto
1506132451Sroberto	j = instance->ev_serial;
1507132451Sroberto	timeout.tv_sec = 0;
1508132451Sroberto	timeout.tv_nsec = 0;
1509132451Sroberto	if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i,
1510132451Sroberto	    &timeout) < 0) {
1511132451Sroberto		printf("ONCORE: time_pps_fetch failed\n");
1512132451Sroberto		return;
1513132451Sroberto	}
1514132451Sroberto
1515132451Sroberto	if (instance->assert) {
1516132451Sroberto		tsp = &pps_i.assert_timestamp;
1517132451Sroberto
1518182007Sroberto#ifdef DEBUG
1519132451Sroberto		if (debug > 2) {
1520132451Sroberto			i = (u_long) pps_i.assert_sequence;
1521182007Sroberto# ifdef HAVE_STRUCT_TIMESPEC
1522132451Sroberto			printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n",
1523132451Sroberto			    instance->unit, i, j,
1524132451Sroberto			    (long)tsp->tv_sec, (long)tsp->tv_nsec);
1525182007Sroberto# else
1526132451Sroberto			printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n",
1527132451Sroberto			    instance->unit, i, j,
1528132451Sroberto			    (long)tsp->tv_sec, (long)tsp->tv_usec);
1529182007Sroberto# endif
1530182007Sroberto		}
1531132451Sroberto#endif
1532132451Sroberto
1533132451Sroberto		if (pps_i.assert_sequence == j) {
1534132451Sroberto			printf("ONCORE: oncore_get_timestamp, error serial pps\n");
1535132451Sroberto			return;
1536132451Sroberto		}
1537132451Sroberto		instance->ev_serial = pps_i.assert_sequence;
1538132451Sroberto	} else {
1539132451Sroberto		tsp = &pps_i.clear_timestamp;
1540132451Sroberto
1541182007Sroberto#ifdef DEBUG
1542132451Sroberto		if (debug > 2) {
1543132451Sroberto			i = (u_long) pps_i.clear_sequence;
1544182007Sroberto# ifdef HAVE_STRUCT_TIMESPEC
1545132451Sroberto			printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n",
1546132451Sroberto			    instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_nsec);
1547182007Sroberto# else
1548132451Sroberto			printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n",
1549132451Sroberto			    instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_usec);
1550182007Sroberto# endif
1551182007Sroberto		}
1552132451Sroberto#endif
1553132451Sroberto
1554132451Sroberto		if (pps_i.clear_sequence == j) {
1555132451Sroberto			printf("ONCORE: oncore_get_timestamp, error serial pps\n");
1556132451Sroberto			return;
1557132451Sroberto		}
1558132451Sroberto		instance->ev_serial = pps_i.clear_sequence;
1559132451Sroberto	}
1560132451Sroberto
1561132451Sroberto	/* convert timespec -> ntp l_fp */
1562132451Sroberto
1563132451Sroberto	dmy = tsp->tv_nsec;
1564132451Sroberto	dmy /= 1e9;
1565182007Sroberto	ts.l_uf = dmy * 4294967296.0;
1566132451Sroberto	ts.l_ui = tsp->tv_sec;
1567182007Sroberto
1568132451Sroberto#if 0
1569132451Sroberto     alternate code for previous 4 lines is
1570132451Sroberto	dmy = 1.0e-9*tsp->tv_nsec;	/* fractional part */
1571132451Sroberto	DTOLFP(dmy, &ts);
1572132451Sroberto	dmy = tsp->tv_sec;		/* integer part */
1573132451Sroberto	DTOLFP(dmy, &ts_tmp);
1574132451Sroberto	L_ADD(&ts, &ts_tmp);
1575132451Sroberto     or more simply
1576132451Sroberto	dmy = 1.0e-9*tsp->tv_nsec;	/* fractional part */
1577132451Sroberto	DTOLFP(dmy, &ts);
1578132451Sroberto	ts.l_ui = tsp->tv_sec;
1579132451Sroberto#endif	/* 0 */
1580132451Sroberto
1581132451Sroberto	/* now have timestamp in ts */
1582132451Sroberto	/* add in saw_tooth and offset, these will be ZERO if no TRAIM */
1583182007Sroberto	/* they will be IGNORED if the PPSAPI cant do PPS_OFFSET/ASSERT/CLEAR */
1584182007Sroberto	/* we just try to add them in and dont test for that here */
1585132451Sroberto
1586132451Sroberto	/* saw_tooth not really necessary if using TIMEVAL */
1587132451Sroberto	/* since its only precise to us, but do it anyway. */
1588132451Sroberto
1589132451Sroberto	/* offset in ns, and is positive (late), we subtract */
1590132451Sroberto	/* to put the PPS time transition back where it belongs */
1591132451Sroberto
1592132451Sroberto	/* must hand the offset for the NEXT sec off to the Kernel to do */
1593132451Sroberto	/* the addition, so that the Kernel PLL sees the offset too */
1594132451Sroberto
1595132451Sroberto	if (instance->assert)
1596132451Sroberto		instance->pps_p.assert_offset.tv_nsec = -dt2;
1597132451Sroberto	else
1598132451Sroberto		instance->pps_p.clear_offset.tv_nsec  = -dt2;
1599132451Sroberto
1600132451Sroberto	/* The following code is necessary, and not just a time_pps_setparams,
1601132451Sroberto	 * using the saved instance->pps_p, since some other process on the
1602132451Sroberto	 * machine may have diddled with the mode bits (say adding something
1603132451Sroberto	 * that it needs).  We take what is there and ADD what we need.
1604132451Sroberto	 * [[ The results from the time_pps_getcap is unlikely to change so
1605132451Sroberto	 *    we could probably just save it, but I choose to do the call ]]
1606132451Sroberto	 * Unfortunately, there is only ONE set of mode bits in the kernel per
1607132451Sroberto	 * interface, and not one set for each open handle.
1608132451Sroberto	 *
1609132451Sroberto	 * There is still a race condition here where we might mess up someone
1610132451Sroberto	 * elses mode, but if he is being careful too, he should survive.
1611132451Sroberto	 */
1612132451Sroberto
1613132451Sroberto	if (time_pps_getcap(instance->pps_h, &current_mode) < 0) {
1614182007Sroberto		msyslog(LOG_ERR, "time_pps_getcap failed: %m");
1615132451Sroberto		return;
1616132451Sroberto	}
1617132451Sroberto
1618132451Sroberto	if (time_pps_getparams(instance->pps_h, &current_params) < 0) {
1619182007Sroberto		msyslog(LOG_ERR, "time_pps_getparams failed: %m");
1620132451Sroberto		return;
1621132451Sroberto	}
1622132451Sroberto
1623132451Sroberto		/* or current and mine */
1624132451Sroberto	current_params.mode |= instance->pps_p.mode;
1625132451Sroberto		/* but only set whats legal */
1626132451Sroberto	current_params.mode &= current_mode;
1627132451Sroberto
1628132451Sroberto	current_params.assert_offset.tv_sec = 0;
1629132451Sroberto	current_params.assert_offset.tv_nsec = -dt2;
1630132451Sroberto	current_params.clear_offset.tv_sec = 0;
1631132451Sroberto	current_params.clear_offset.tv_nsec = -dt2;
1632132451Sroberto
1633132451Sroberto	if (time_pps_setparams(instance->pps_h, &current_params))
1634182007Sroberto		record_clock_stats(&(instance->peer->srcadr), "ONCORE: Error doing time_pps_setparams");
1635132451Sroberto
1636132451Sroberto	/* have time from UNIX origin, convert to NTP origin. */
1637132451Sroberto
1638132451Sroberto	ts.l_ui += JAN_1970;
1639132451Sroberto	instance->pp->lastrec = ts;
1640132451Sroberto
1641132451Sroberto	/* print out information about this timestamp (long line) */
1642132451Sroberto
1643132451Sroberto	ts_tmp = ts;
1644132451Sroberto	ts_tmp.l_ui = 0;	/* zero integer part */
1645132451Sroberto	LFPTOD(&ts_tmp, dmy);	/* convert fractional part to a double */
1646132451Sroberto	j = 1.0e9*dmy;		/* then to integer ns */
1647132451Sroberto
1648132451Sroberto	Rsm = 0;
1649132451Sroberto	if (instance->chan == 6)
1650132451Sroberto		Rsm = instance->BEHa[64];
1651132451Sroberto	else if (instance->chan == 8)
1652132451Sroberto		Rsm = instance->BEHa[72];
1653132451Sroberto	else if (instance->chan == 12)
1654132451Sroberto		Rsm = ((instance->BEHa[129]<<8) | instance->BEHa[130]);
1655132451Sroberto
1656132451Sroberto	if (instance->chan == 6 || instance->chan == 8) {
1657182007Sroberto		char	f1[5], f2[5], f3[5], f4[5];
1658182007Sroberto		if (instance->traim) {
1659182007Sroberto			sprintf(f1, "%d", instance->BEHn[21]);
1660182007Sroberto			sprintf(f2, "%d", instance->BEHn[22]);
1661182007Sroberto			sprintf(f3, "%2d", instance->BEHn[23]*256+instance->BEHn[24]);
1662182007Sroberto			sprintf(f4, "%3d", (s_char) instance->BEHn[25]);
1663182007Sroberto		} else {
1664182007Sroberto			strcpy(f1, "x");
1665182007Sroberto			strcpy(f2, "x");
1666182007Sroberto			strcpy(f3, "xx");
1667182007Sroberto			strcpy(f4, "xxx");
1668182007Sroberto		}
1669182007Sroberto		sprintf(instance->pp->a_lastcode,	/* MAX length 128, currently at 121 */
1670182007Sroberto "%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",
1671132451Sroberto		    ts.l_ui, j,
1672132451Sroberto		    instance->pp->year, instance->pp->day,
1673132451Sroberto		    instance->pp->hour, instance->pp->minute, instance->pp->second,
1674132451Sroberto		    (long) tsp->tv_sec % 60,
1675132451Sroberto		    Rsm, 0.1*(256*instance->BEHa[35]+instance->BEHa[36]),
1676132451Sroberto		    /*rsat	dop */
1677182007Sroberto		    instance->BEHa[38], instance->BEHa[39], instance->traim, f1, f2,
1678182007Sroberto		    /*	nsat visible,	  nsat tracked,     traim,traim,traim */
1679182007Sroberto		    f3, f4,
1680182007Sroberto		    /* sigma neg-sawtooth */
1681132451Sroberto	  /*sat*/   instance->BEHa[41], instance->BEHa[45], instance->BEHa[49], instance->BEHa[53],
1682132451Sroberto		    instance->BEHa[57], instance->BEHa[61], instance->BEHa[65], instance->BEHa[69]
1683132451Sroberto		    );					/* will be 0 for 6 chan */
1684132451Sroberto	} else if (instance->chan == 12) {
1685182007Sroberto		char	f1[5], f2[5], f3[5], f4[5];
1686182007Sroberto		if (instance->traim) {
1687182007Sroberto			sprintf(f1, "%d", instance->BEHn[6]);
1688182007Sroberto			sprintf(f2, "%d", instance->BEHn[7]);
1689182007Sroberto			sprintf(f3, "%d", instance->BEHn[12]*256+instance->BEHn[13]);
1690182007Sroberto			sprintf(f4, "%3d", (s_char) instance->BEHn[14]);
1691182007Sroberto		} else {
1692182007Sroberto			strcpy(f1, "x");
1693182007Sroberto			strcpy(f2, "x");
1694182007Sroberto			strcpy(f3, "x");
1695182007Sroberto			strcpy(f4, "xxx");
1696182007Sroberto		}
1697132451Sroberto		sprintf(instance->pp->a_lastcode,
1698182007Sroberto "%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",
1699132451Sroberto		    ts.l_ui, j,
1700132451Sroberto		    instance->pp->year, instance->pp->day,
1701132451Sroberto		    instance->pp->hour, instance->pp->minute, instance->pp->second,
1702132451Sroberto		    (long) tsp->tv_sec % 60,
1703132451Sroberto		    Rsm, 0.1*(256*instance->BEHa[53]+instance->BEHa[54]),
1704132451Sroberto		    /*rsat	dop */
1705182007Sroberto		    instance->BEHa[55], instance->BEHa[56], instance->traim, f1, f2,
1706182007Sroberto		    /*	nsat visible,	  nsat tracked	 traim,traim,traim */
1707182007Sroberto		    f3, f4,
1708182007Sroberto		    /* sigma neg-sawtooth */
1709132451Sroberto	  /*sat*/   instance->BEHa[58], instance->BEHa[64], instance->BEHa[70], instance->BEHa[76],
1710132451Sroberto		    instance->BEHa[82], instance->BEHa[88], instance->BEHa[94], instance->BEHa[100],
1711132451Sroberto		    instance->BEHa[106], instance->BEHa[112], instance->BEHa[118], instance->BEHa[124]
1712132451Sroberto		    );
1713132451Sroberto	}
1714132451Sroberto
1715182007Sroberto#ifdef DEBUG
1716132451Sroberto	if (debug > 2) {
1717132451Sroberto		int n;
1718182007Sroberto
1719132451Sroberto		n = strlen(instance->pp->a_lastcode);
1720132451Sroberto		printf("ONCORE[%d]: len = %d %s\n", instance->unit, n, instance->pp->a_lastcode);
1721132451Sroberto	}
1722182007Sroberto#endif
1723132451Sroberto
1724182007Sroberto	/* and some things I dont understand (magic ntp things) */
1725132451Sroberto
1726132451Sroberto	if (!refclock_process(instance->pp)) {
1727132451Sroberto		refclock_report(instance->peer, CEVNT_BADTIME);
1728132451Sroberto		return;
1729132451Sroberto	}
1730132451Sroberto
1731132451Sroberto	record_clock_stats(&(instance->peer->srcadr), instance->pp->a_lastcode);
1732132451Sroberto	instance->pollcnt = 2;
1733132451Sroberto
1734132451Sroberto	if (instance->polled) {
1735132451Sroberto		instance->polled = 0;
1736182007Sroberto	     /* instance->pp->dispersion = instance->pp->skew = 0;	*/
1737132451Sroberto		instance->pp->lastref = instance->pp->lastrec;
1738132451Sroberto		refclock_receive(instance->peer);
1739132451Sroberto	}
174054359Sroberto}
174154359Sroberto
174254359Sroberto
1743132451Sroberto/*************** oncore_msg_XX routines start here *******************/
174454359Sroberto
1745132451Sroberto
174682498Sroberto/*
174782498Sroberto * print Oncore response message.
174882498Sroberto */
174982498Sroberto
175054359Srobertostatic void
175154359Srobertooncore_msg_any(
175254359Sroberto	struct instance *instance,
175354359Sroberto	u_char *buf,
175482498Sroberto	size_t len,
175554359Sroberto	int idx
175654359Sroberto	)
175754359Sroberto{
175854359Sroberto	int i;
175954359Sroberto	const char *fmt = oncore_messages[idx].fmt;
176054359Sroberto	const char *p;
176182498Sroberto#ifdef HAVE_GETCLOCK
176282498Sroberto	struct timespec ts;
176382498Sroberto#endif
176454359Sroberto	struct timeval tv;
176554359Sroberto
1766182007Sroberto#ifdef DEBUG
176754359Sroberto	if (debug > 3) {
1768182007Sroberto# ifdef HAVE_GETCLOCK
1769132451Sroberto		(void) getclock(TIMEOFDAY, &ts);
1770132451Sroberto		tv.tv_sec = ts.tv_sec;
1771132451Sroberto		tv.tv_usec = ts.tv_nsec / 1000;
1772182007Sroberto# else
177354359Sroberto		GETTIMEOFDAY(&tv, 0);
1774182007Sroberto# endif
177582498Sroberto		printf("ONCORE[%d]: %ld.%06ld\n", instance->unit, (long) tv.tv_sec, (long) tv.tv_usec);
177654359Sroberto
177754359Sroberto		if (!*fmt) {
177854359Sroberto			printf(">>@@%c%c ", buf[2], buf[3]);
177954359Sroberto			for(i=2; i < len && i < 2400 ; i++)
178054359Sroberto				printf("%02x", buf[i]);
178154359Sroberto			printf("\n");
178254359Sroberto			return;
178354359Sroberto		} else {
178454359Sroberto			printf("##");
178554359Sroberto			for (p = fmt; *p; p++) {
178654359Sroberto				putchar(*p);
178754359Sroberto				putchar('_');
178854359Sroberto			}
178954359Sroberto			printf("\n%c%c", buf[2], buf[3]);
179054359Sroberto			i = 4;
179154359Sroberto			for (p = fmt; *p; p++) {
179254359Sroberto				printf("%02x", buf[i++]);
179354359Sroberto			}
179454359Sroberto			printf("\n");
179554359Sroberto		}
179654359Sroberto	}
1797182007Sroberto#endif
179854359Sroberto}
179954359Sroberto
180054359Sroberto
180154359Sroberto
1802132451Sroberto/* Latitude, Longitude, Height */
180382498Sroberto
180456746Srobertostatic void
1805132451Srobertooncore_msg_Adef(
180656746Sroberto	struct instance *instance,
180756746Sroberto	u_char *buf,
180882498Sroberto	size_t len
180956746Sroberto	)
181056746Sroberto{
1811132451Sroberto}
181256746Sroberto
181356746Sroberto
181456746Sroberto
1815132451Sroberto/* Mask Angle */
181682498Sroberto
1817132451Srobertostatic void
1818132451Srobertooncore_msg_Ag(
1819132451Sroberto	struct instance *instance,
1820132451Sroberto	u_char *buf,
1821132451Sroberto	size_t len
1822132451Sroberto	)
1823132451Sroberto{		char  Msg[160], *cp;
182482498Sroberto
1825132451Sroberto		cp = "set to";
1826132451Sroberto		if (instance->o_state == ONCORE_RUN)
1827132451Sroberto			cp = "is";
182854359Sroberto
1829132451Sroberto		instance->Ag = buf[4];
1830132451Sroberto		sprintf(Msg, "Satellite mask angle %s %d degrees", cp, (int) instance->Ag);
1831132451Sroberto		record_clock_stats(&(instance->peer->srcadr), Msg);
1832132451Sroberto}
183354359Sroberto
1834132451Sroberto
1835132451Sroberto
183682498Sroberto/*
1837132451Sroberto * get Position hold position
183856746Sroberto */
183956746Sroberto
184054359Srobertostatic void
1841132451Srobertooncore_msg_As(
184254359Sroberto	struct instance *instance,
184354359Sroberto	u_char *buf,
184482498Sroberto	size_t len
184554359Sroberto	)
184654359Sroberto{
1847132451Sroberto	instance->ss_lat  = buf_w32(&buf[4]);
1848132451Sroberto	instance->ss_long = buf_w32(&buf[8]);
1849132451Sroberto	instance->ss_ht   = buf_w32(&buf[12]);
185054359Sroberto
1851132451Sroberto	/* Print out Position */
1852132451Sroberto	oncore_print_posn(instance);
185354359Sroberto}
185454359Sroberto
185554359Sroberto
185654359Sroberto
1857132451Sroberto/*
1858132451Sroberto * Try to use Oncore UT+ Auto Survey Feature
1859132451Sroberto *	If its not there (VP), set flag to do it ourselves.
186054359Sroberto */
186182498Sroberto
186254359Srobertostatic void
1863132451Srobertooncore_msg_At(
186454359Sroberto	struct instance *instance,
186554359Sroberto	u_char *buf,
186682498Sroberto	size_t len
186754359Sroberto	)
186854359Sroberto{
1869132451Sroberto	char	*cp;
187054359Sroberto
1871132451Sroberto	instance->saw_At = 1;
1872132451Sroberto	if (instance->site_survey == ONCORE_SS_TESTING) {
1873132451Sroberto		if (buf[4] == 2) {
1874132451Sroberto			record_clock_stats(&(instance->peer->srcadr),
1875132451Sroberto					"Initiating hardware 3D site survey");
187654359Sroberto
1877132451Sroberto			cp = "SSstate = ONCORE_SS_HW";
1878132451Sroberto			record_clock_stats(&(instance->peer->srcadr), cp);
1879132451Sroberto			instance->site_survey = ONCORE_SS_HW;
1880132451Sroberto		}
188156746Sroberto	}
1882132451Sroberto}
188382498Sroberto
188482498Sroberto
188582498Sroberto
1886132451Sroberto/*
1887132451Sroberto * get PPS Offset
1888132451Sroberto * Nb. @@Ay is not supported for early UT (no plus) model
1889132451Sroberto */
189082498Sroberto
1891132451Srobertostatic void
1892132451Srobertooncore_msg_Ay(
1893132451Sroberto	struct instance *instance,
1894132451Sroberto	u_char *buf,
1895132451Sroberto	size_t len
1896132451Sroberto	)
1897132451Sroberto{
1898132451Sroberto	char Msg[120];
189982498Sroberto
1900132451Sroberto	if (instance->saw_Ay)
1901132451Sroberto		return;
190282498Sroberto
1903132451Sroberto	instance->saw_Ay = 1;
190482498Sroberto
1905132451Sroberto	instance->offset = buf_w32(&buf[4]);
190682498Sroberto
1907132451Sroberto	sprintf(Msg, "PPS Offset is set to %ld ns", instance->offset);
190882498Sroberto	record_clock_stats(&(instance->peer->srcadr), Msg);
1909132451Sroberto}
191082498Sroberto
191182498Sroberto
191282498Sroberto
1913132451Sroberto/*
1914132451Sroberto * get Cable Delay
1915132451Sroberto */
191682498Sroberto
1917132451Srobertostatic void
1918132451Srobertooncore_msg_Az(
1919132451Sroberto	struct instance *instance,
1920132451Sroberto	u_char *buf,
1921132451Sroberto	size_t len
1922132451Sroberto	)
1923132451Sroberto{
1924132451Sroberto	char Msg[120];
192582498Sroberto
1926132451Sroberto	if (instance->saw_Az)
1927132451Sroberto		return;
192882498Sroberto
1929132451Sroberto	instance->saw_Az = 1;
193056746Sroberto
1931132451Sroberto	instance->delay = buf_w32(&buf[4]);
193254359Sroberto
1933132451Sroberto	sprintf(Msg, "Cable delay is set to %ld ns", instance->delay);
1934132451Sroberto	record_clock_stats(&(instance->peer->srcadr), Msg);
193582498Sroberto}
193682498Sroberto
193782498Sroberto
193882498Sroberto
1939132451Sroberto/* Ba, Ea and Ha come here, these contain Position */
1940132451Sroberto
194182498Srobertostatic void
1942132451Srobertooncore_msg_BaEaHa(
194382498Sroberto	struct instance *instance,
194482498Sroberto	u_char *buf,
194582498Sroberto	size_t len
194682498Sroberto	)
194782498Sroberto{
1948132451Sroberto	const char	*cp;
1949132451Sroberto	char		Msg[160];
1950132451Sroberto	int		mode;
195182498Sroberto
1952132451Sroberto	/* OK, we are close to the RUN state now.
1953132451Sroberto	 * But we have a few more items to initialize first.
1954132451Sroberto	 *
1955132451Sroberto	 * At the beginning of this routine there are several 'timers'.
1956132451Sroberto	 * We enter this routine 1/sec, and since the upper levels of NTP have usurped
1957132451Sroberto	 * the use of timers, we use the 1/sec entry to do things that
1958132451Sroberto	 * we would normally do with timers...
195982498Sroberto	 */
196082498Sroberto
1961132451Sroberto	if (instance->o_state == ONCORE_CHECK_CHAN) {	/* here while checking for the # chan */
1962132451Sroberto		if (buf[2] == 'B') {		/* 6chan */
1963132451Sroberto			if (instance->chan_ck < 6) instance->chan_ck = 6;
1964132451Sroberto		} else if (buf[2] == 'E') {	/* 8chan */
1965132451Sroberto			if (instance->chan_ck < 8) instance->chan_ck = 8;
1966132451Sroberto		} else if (buf[2] == 'H') {	/* 12chan */
1967132451Sroberto			if (instance->chan_ck < 12) instance->chan_ck = 12;
1968132451Sroberto		}
196982498Sroberto
1970132451Sroberto		if (instance->count3++ < 5)
1971132451Sroberto			return;
197282498Sroberto
1973132451Sroberto		instance->count3 = 0;
1974132451Sroberto
1975132451Sroberto		if (instance->chan_in != -1)	/* set in Input */
1976132451Sroberto			instance->chan = instance->chan_in;
1977132451Sroberto		else				/* set from test */
1978132451Sroberto			instance->chan = instance->chan_ck;
1979132451Sroberto
1980132451Sroberto		sprintf(Msg, "Input   says chan = %d", instance->chan_in);
1981132451Sroberto		record_clock_stats(&(instance->peer->srcadr), Msg);
1982132451Sroberto		sprintf(Msg, "Model # says chan = %d", instance->chan_id);
1983132451Sroberto		record_clock_stats(&(instance->peer->srcadr), Msg);
1984132451Sroberto		sprintf(Msg, "Testing says chan = %d", instance->chan_ck);
1985132451Sroberto		record_clock_stats(&(instance->peer->srcadr), Msg);
1986132451Sroberto		sprintf(Msg, "Using        chan = %d", instance->chan);
1987132451Sroberto		record_clock_stats(&(instance->peer->srcadr), Msg);
1988132451Sroberto
1989132451Sroberto		instance->o_state = ONCORE_HAVE_CHAN;
1990132451Sroberto		cp = "state = ONCORE_HAVE_CHAN";
1991132451Sroberto		record_clock_stats(&(instance->peer->srcadr), cp);
1992132451Sroberto
1993132451Sroberto		instance->timeout = 4;
1994132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
1995132451Sroberto		return;
199682498Sroberto	}
199782498Sroberto
1998132451Sroberto	if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN)
1999132451Sroberto		return;
2000132451Sroberto
2001182007Sroberto	/* PAUSE 5sec - make sure results are stable, before using position */
2002132451Sroberto
2003132451Sroberto	if (instance->count) {
2004182007Sroberto		if (instance->count++ < 5)
2005132451Sroberto			return;
2006132451Sroberto		instance->count = 0;
200782498Sroberto	}
200854359Sroberto
2009132451Sroberto	memcpy(instance->BEHa, buf, (size_t) (len+3));	/* Ba, Ea or Ha */
201054359Sroberto
2011182007Sroberto	/* check the antenna (did it get unplugged) and almanac (is it ready) for changes. */
201282498Sroberto
2013132451Sroberto	oncore_check_almanac(instance);
2014132451Sroberto	oncore_check_antenna(instance);
2015132451Sroberto
2016182007Sroberto	/* If we are in Almanac mode, waiting for Almanac, we can't do anything till we have it */
2017132451Sroberto	/* When we have an almanac, we will start the Bn/En/@@Hn messages */
2018132451Sroberto
2019132451Sroberto	if (instance->o_state == ONCORE_ALMANAC)
2020132451Sroberto		if (oncore_wait_almanac(instance))
2021132451Sroberto			return;
2022132451Sroberto
2023132451Sroberto	/* do some things once when we get this far in BaEaHa */
2024132451Sroberto
2025132451Sroberto	if (instance->once) {
2026132451Sroberto		instance->once = 0;
2027132451Sroberto		instance->count2 = 1;
2028132451Sroberto
2029132451Sroberto		/* Have we seen an @@At (position hold) command response */
2030132451Sroberto		/* if not, message out */
2031132451Sroberto
2032132451Sroberto		if (instance->chan != 12 && !instance->saw_At) {
2033132451Sroberto			cp = "Not Good, no @@At command (no Position Hold), must be a GT/GT+";
2034132451Sroberto			record_clock_stats(&(instance->peer->srcadr), cp);
2035132451Sroberto			oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
2036132451Sroberto		}
2037132451Sroberto
2038132451Sroberto		/* have an Almanac, can start the SiteSurvey
2039132451Sroberto		 * (actually only need to get past the almanac_load where we diddle with At
2040132451Sroberto		 *  command,- we can't change it after we start the HW_SS below
2041132451Sroberto		 */
2042132451Sroberto
2043132451Sroberto		mode = instance->init_type;
2044132451Sroberto		switch (mode) {
2045132451Sroberto		case 0: /* NO initialization, don't change anything */
2046132451Sroberto		case 1: /* Use given Position */
2047132451Sroberto		case 3:
2048132451Sroberto			instance->site_survey = ONCORE_SS_DONE;
2049132451Sroberto			cp = "SSstate = ONCORE_SS_DONE";
2050132451Sroberto			record_clock_stats(&(instance->peer->srcadr), cp);
205182498Sroberto			break;
2052132451Sroberto
205382498Sroberto		case 2:
2054132451Sroberto		case 4: /* Site Survey */
2055132451Sroberto			cp = "SSstate = ONCORE_SS_TESTING";
2056132451Sroberto			record_clock_stats(&(instance->peer->srcadr), cp);
2057132451Sroberto			instance->site_survey = ONCORE_SS_TESTING;
2058132451Sroberto			instance->count1 = 1;
2059132451Sroberto			if (instance->chan == 12)
2060132451Sroberto				oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd3,  sizeof(oncore_cmd_Gd3));  /* M12+T */
2061132451Sroberto			else
2062132451Sroberto				oncore_sendmsg(instance->ttyfd, oncore_cmd_At2,  sizeof(oncore_cmd_At2));  /* not GT, arg not VP */
2063132451Sroberto			break;
2064132451Sroberto		}
206582498Sroberto
2066132451Sroberto		/* Read back PPS Offset for Output */
2067132451Sroberto		/* Nb. This will fail silently for early UT (no plus) and M12 models */
206882498Sroberto
2069132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ayx,  sizeof(oncore_cmd_Ayx));
207082498Sroberto
2071132451Sroberto		/* Read back Cable Delay for Output */
207282498Sroberto
2073132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_Azx,  sizeof(oncore_cmd_Azx));
2074132451Sroberto
2075132451Sroberto		/* Read back Satellite Mask Angle for Output */
2076132451Sroberto
2077132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_Agx,  sizeof(oncore_cmd_Agx));
2078132451Sroberto	}
2079132451Sroberto
2080132451Sroberto
2081182007Sroberto	/* Unfortunately, the Gd3 command returns '3' for the M12 v1.3 firmware where it is
2082182007Sroberto	 * out-of-range and it should return 0-2. (v1.3 can't do a HW Site Survey)
2083182007Sroberto	 * We must do the Gd3, and then wait a cycle or two for things to settle,
2084182007Sroberto	 * then check Ha[130]&0x10 to see if a SS is in progress.
2085182007Sroberto	 * We will set SW if HW has not been set after an appropriate delay.
2086182007Sroberto	 */
2087132451Sroberto
2088182007Sroberto	if (instance->site_survey == ONCORE_SS_TESTING) {
2089182007Sroberto		if (instance->chan == 12) {
2090182007Sroberto			if (instance->count1) {
2091182007Sroberto				if (instance->count1++ > 5 || instance->BEHa[130]&0x10) {
2092182007Sroberto					instance->count1 = 0;
2093182007Sroberto					if (instance->BEHa[130]&0x10) {
2094182007Sroberto						record_clock_stats(&(instance->peer->srcadr),
2095182007Sroberto								"Initiating hardware 3D site survey");
2096132451Sroberto
2097182007Sroberto						record_clock_stats(&(instance->peer->srcadr), "SSstate = ONCORE_SS_HW");
2098182007Sroberto						instance->site_survey = ONCORE_SS_HW;
2099182007Sroberto					} else {
2100182007Sroberto						record_clock_stats(&(instance->peer->srcadr), "SSstate = ONCORE_SS_SW");
2101182007Sroberto						instance->site_survey = ONCORE_SS_SW;
2102182007Sroberto					}
2103132451Sroberto				}
210482498Sroberto			}
2105182007Sroberto		} else {
2106182007Sroberto			if (instance->count1) {
2107182007Sroberto				if (instance->count1++ > 5) {
2108182007Sroberto					instance->count1 = 0;
2109182007Sroberto					/*
2110182007Sroberto					 * For instance->site_survey to still be ONCORE_SS_TESTING, then after a 5sec
2111182007Sroberto					 * wait after the @@At2/@@Gd3 command we have not changed the state to
2112182007Sroberto					 * ONCORE_SS_HW.  If the Hardware is capable of doing a Site Survey, then
2113182007Sroberto					 * the variable would have been changed by now.
2114182007Sroberto					 * There are three possibilities:
2115182007Sroberto					 * 6/8chan
2116182007Sroberto					 *   (a) We did not get a response to the @@At0 or @@At2 commands,
2117182007Sroberto					 *	   and it must be a GT/GT+/SL with no position hold mode.
2118182007Sroberto					 *	   We will have to do it ourselves.
2119182007Sroberto					 *   (b) We saw the @@At0, @@At2 commands, but @@At2 failed,
2120182007Sroberto					 *	   must be a VP or older UT which doesn't have Site Survey mode.
2121182007Sroberto					 *	   We will have to do it ourselves.
2122182007Sroberto					 * 12chan
2123182007Sroberto					 *   (c) We saw the @@Gd command, and saw H[13]*0x10
2124182007Sroberto					 *	   We will have to do it ourselves (done above)
2125182007Sroberto					 */
2126182007Sroberto
2127182007Sroberto					sprintf(Msg, "Initiating software 3D site survey (%d samples)",
2128182007Sroberto						POS_HOLD_AVERAGE);
2129182007Sroberto					record_clock_stats(&(instance->peer->srcadr), Msg);
2130182007Sroberto
2131182007Sroberto					record_clock_stats(&(instance->peer->srcadr), "SSstate = ONCORE_SS_SW");
2132182007Sroberto					instance->site_survey = ONCORE_SS_SW;
2133182007Sroberto
2134182007Sroberto					instance->ss_lat = instance->ss_long = instance->ss_ht = 0;
2135182007Sroberto					if (instance->chan == 12)
2136182007Sroberto						oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* disable */
2137182007Sroberto					else {
2138182007Sroberto						oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* disable */
2139182007Sroberto						oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* disable */
2140182007Sroberto					}
2141182007Sroberto				}
2142182007Sroberto			}
214382498Sroberto		}
214482498Sroberto	}
214582498Sroberto
2146132451Sroberto	/* check the mode we are in 0/2/3D */
214782498Sroberto
2148132451Sroberto	if (instance->chan == 6) {
2149132451Sroberto		if (instance->BEHa[64]&0x8)
2150132451Sroberto			instance->mode = MODE_0D;
2151132451Sroberto		else if (instance->BEHa[64]&0x10)
2152132451Sroberto			instance->mode = MODE_2D;
2153132451Sroberto		else if (instance->BEHa[64]&0x20)
2154132451Sroberto			instance->mode = MODE_3D;
2155132451Sroberto	} else if (instance->chan == 8) {
2156132451Sroberto		if (instance->BEHa[72]&0x8)
2157132451Sroberto			instance->mode = MODE_0D;
2158132451Sroberto		else if (instance->BEHa[72]&0x10)
2159132451Sroberto			instance->mode = MODE_2D;
2160132451Sroberto		else if (instance->BEHa[72]&0x20)
2161132451Sroberto			instance->mode = MODE_3D;
2162132451Sroberto	} else if (instance->chan == 12) {
2163132451Sroberto		int bits;
216454359Sroberto
2165132451Sroberto		bits = (instance->BEHa[129]>>5) & 0x7;	/* actually Ha */
2166132451Sroberto		if (bits == 0x4)
2167132451Sroberto			instance->mode = MODE_0D;
2168132451Sroberto		else if (bits == 0x6)
2169132451Sroberto			instance->mode = MODE_2D;
2170132451Sroberto		else if (bits == 0x7)
2171132451Sroberto			instance->mode = MODE_3D;
2172132451Sroberto	}
217354359Sroberto
2174132451Sroberto	/* copy the record to the (extra) location in SHMEM */
2175132451Sroberto
2176132451Sroberto	if (instance->shmem) {
2177132451Sroberto		int	i;
2178132451Sroberto		u_char	*smp;	 /* pointer to start of shared mem for Ba/Ea/Ha */
2179132451Sroberto
2180132451Sroberto		switch(instance->chan) {
2181132451Sroberto		case 6:   smp = &instance->shmem[instance->shmem_Ba]; break;
2182132451Sroberto		case 8:   smp = &instance->shmem[instance->shmem_Ea]; break;
2183132451Sroberto		case 12:  smp = &instance->shmem[instance->shmem_Ha]; break;
2184182007Sroberto		default:  smp = (u_char *) NULL;		      break;
218554359Sroberto		}
2186132451Sroberto
2187132451Sroberto		switch (instance->mode) {
2188132451Sroberto		case MODE_0D:	i = 1; break;	/* 0D, Position Hold */
2189132451Sroberto		case MODE_2D:	i = 2; break;	/* 2D, Altitude Hold */
2190132451Sroberto		case MODE_3D:	i = 3; break;	/* 3D fix */
2191132451Sroberto		default:	i = 0; break;
2192132451Sroberto		}
2193132451Sroberto
2194182007Sroberto		if (i && smp != NULL) {
2195132451Sroberto			i *= (len+6);
2196132451Sroberto			smp[i + 2]++;
2197132451Sroberto			memcpy(&smp[i+3], buf, (size_t) (len+3));
2198132451Sroberto		}
219954359Sroberto	}
220054359Sroberto
2201132451Sroberto	/*
2202182007Sroberto	 * check if traim timer active
2203132451Sroberto	 * if it hasn't been cleared, then @@Bn/@@En/@@Hn did not respond
2204132451Sroberto	 */
220554359Sroberto
2206132451Sroberto	if (instance->traim_delay) {
2207132451Sroberto		if (instance->traim_delay++ > 5) {
2208132451Sroberto			instance->traim = 0;
2209132451Sroberto			instance->traim_delay = 0;
2210132451Sroberto			cp = "ONCORE: Did not detect TRAIM response, TRAIM = OFF";
2211132451Sroberto			record_clock_stats(&(instance->peer->srcadr), cp);
2212132451Sroberto
2213132451Sroberto			oncore_set_traim(instance);
2214132451Sroberto		} else
2215132451Sroberto			return;
2216132451Sroberto
2217132451Sroberto	}
2218132451Sroberto
2219132451Sroberto	/* by now should have a @@Ba/@@Ea/@@Ha with good data in it */
2220132451Sroberto
2221132451Sroberto	if (!instance->have_dH && !instance->traim_delay)
2222132451Sroberto		oncore_compute_dH(instance);
2223132451Sroberto
2224132451Sroberto	/*
2225132451Sroberto	 * must be ONCORE_RUN if we are here.
2226132451Sroberto	 * Have # chan and TRAIM by now.
2227132451Sroberto	 */
2228132451Sroberto
2229132451Sroberto	instance->pp->year   = buf[6]*256+buf[7];
2230132451Sroberto	instance->pp->day    = ymd2yd(buf[6]*256+buf[7], buf[4], buf[5]);
2231132451Sroberto	instance->pp->hour   = buf[8];
2232132451Sroberto	instance->pp->minute = buf[9];
2233132451Sroberto	instance->pp->second = buf[10];
2234132451Sroberto
2235132451Sroberto	/*
2236132451Sroberto	 * Are we doing a Hardware or Software Site Survey?
2237132451Sroberto	 */
2238132451Sroberto
2239132451Sroberto	if (instance->site_survey == ONCORE_SS_HW || instance->site_survey == ONCORE_SS_SW)
2240132451Sroberto		oncore_ss(instance);
2241132451Sroberto
2242132451Sroberto	/* see if we ever saw a response from the @@Ayx above */
2243132451Sroberto
2244132451Sroberto	if (instance->count2) {
2245132451Sroberto		if (instance->count2++ > 5) {	/* this delay to check on @@Ay command */
2246132451Sroberto			instance->count2 = 0;
2247132451Sroberto
2248132451Sroberto			/* Have we seen an Ay (1PPS time offset) command response */
2249132451Sroberto			/* if not, and non-zero offset, zero the offset, and send message */
2250132451Sroberto
2251132451Sroberto			if (!instance->saw_Ay && instance->offset) {
2252132451Sroberto				cp = "No @@Ay command, PPS OFFSET ignored";
225382498Sroberto				record_clock_stats(&(instance->peer->srcadr), cp);
225482498Sroberto				instance->offset = 0;
225582498Sroberto			}
225682498Sroberto		}
225754359Sroberto	}
225854359Sroberto
2259132451Sroberto	/*
2260132451Sroberto	 * Check the leap second status once per day.
2261132451Sroberto	 */
226254359Sroberto
2263132451Sroberto	oncore_check_leap_sec(instance);
226454359Sroberto
2265132451Sroberto	/*
2266132451Sroberto	 * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn.
2267132451Sroberto	 */
2268132451Sroberto
2269132451Sroberto	if (instance->shmem && !instance->shmem_bad_Ea && instance->shmem_Posn && (instance->site_survey == ONCORE_SS_DONE))
2270132451Sroberto		oncore_shmem_get_3D(instance);
2271132451Sroberto
2272132451Sroberto	if (!instance->traim)	/* NO traim, no BnEnHn, go get tick */
2273132451Sroberto		oncore_get_timestamp(instance, instance->offset, instance->offset);
227454359Sroberto}
227554359Sroberto
227654359Sroberto
227754359Sroberto
2278132451Sroberto/* Almanac Status */
2279132451Sroberto
2280132451Srobertostatic void
2281132451Srobertooncore_msg_Bd(
2282132451Sroberto	struct instance *instance,
2283132451Sroberto	u_char *buf,
2284132451Sroberto	size_t len
2285132451Sroberto	)
2286132451Sroberto{
2287132451Sroberto	char Msg[160];
2288132451Sroberto
2289132451Sroberto	sprintf(Msg, "Bd: Almanac %s, week = %d, t = %d, %d SVs: %x",
2290132451Sroberto		((buf[4]) ? "LOADED" : "(NONE)"), buf[5], buf[6], buf[7], w32(&buf[8]) );
2291132451Sroberto	record_clock_stats(&(instance->peer->srcadr), Msg);
2292132451Sroberto}
2293132451Sroberto
2294132451Sroberto
2295132451Sroberto
2296132451Sroberto/* get leap-second warning message */
2297132451Sroberto
229882498Sroberto/*
2299132451Sroberto * @@Bj does NOT behave as documented in current Oncore firmware.
2300132451Sroberto * It turns on the LEAP indicator when the data is set, and does not,
2301132451Sroberto * as documented, wait until the beginning of the month when the
2302132451Sroberto * leap second will occur.
2303132451Sroberto * Since this firmware bug will never be fixed in all the outstanding Oncore receivers
2304132451Sroberto * @@Bj is only called in June/December.
230582498Sroberto */
230682498Sroberto
230754359Srobertostatic void
2308132451Srobertooncore_msg_Bj(
230954359Sroberto	struct instance *instance,
231054359Sroberto	u_char *buf,
231182498Sroberto	size_t len
231254359Sroberto	)
231354359Sroberto{
2314132451Sroberto	const char	*cp;
231582498Sroberto
2316132451Sroberto	switch(buf[4]) {
2317132451Sroberto	case 1:
2318182007Sroberto		instance->pp->leap = LEAP_ADDSECOND;
2319182007Sroberto		cp = "Set pp.leap to LEAP_ADDSECOND";
2320132451Sroberto		break;
2321132451Sroberto	case 2:
2322182007Sroberto		instance->pp->leap = LEAP_DELSECOND;
2323182007Sroberto		cp = "Set pp.leap to LEAP_DELSECOND";
2324132451Sroberto		break;
2325132451Sroberto	case 0:
2326132451Sroberto	default:
2327182007Sroberto		instance->pp->leap = LEAP_NOWARNING;
2328182007Sroberto		cp = "Set pp.leap to LEAP_NOWARNING";
2329132451Sroberto		break;
2330132451Sroberto	}
2331132451Sroberto	record_clock_stats(&(instance->peer->srcadr), cp);
2332132451Sroberto}
233382498Sroberto
2334132451Sroberto
2335132451Sroberto
2336132451Srobertostatic void
2337132451Srobertooncore_msg_BnEnHn(
2338132451Sroberto	struct instance *instance,
2339132451Sroberto	u_char *buf,
2340132451Sroberto	size_t	len
2341132451Sroberto	)
2342132451Sroberto{
2343132451Sroberto	long	dt1, dt2;
2344132451Sroberto	char	*cp;
2345132451Sroberto
2346132451Sroberto	if (instance->o_state != ONCORE_RUN)
2347132451Sroberto		return;
2348132451Sroberto
2349132451Sroberto	if (instance->traim_delay) {	 /* flag that @@Bn/@@En/Hn returned */
2350132451Sroberto			instance->traim_ck = 1;
2351132451Sroberto			instance->traim_delay = 0;
2352132451Sroberto			cp = "ONCORE: Detected TRAIM, TRAIM = ON";
2353132451Sroberto			record_clock_stats(&(instance->peer->srcadr), cp);
2354132451Sroberto
2355132451Sroberto			oncore_set_traim(instance);
235682498Sroberto	}
2357132451Sroberto
2358132451Sroberto	memcpy(instance->BEHn, buf, (size_t) len);	/* Bn or En or Hn */
2359132451Sroberto
2360182007Sroberto	if (!instance->traim)	/* BnEnHn will be turned off in any case */
2361182007Sroberto		return;
2362182007Sroberto
2363132451Sroberto	/* If Time RAIM doesn't like it, don't trust it */
2364132451Sroberto
2365132451Sroberto	if (buf[2] == 'H') {
2366132451Sroberto		if (instance->BEHn[6])	/* bad TRAIM */
2367132451Sroberto			return;
2368132451Sroberto
2369132451Sroberto		dt1 = instance->saw_tooth + instance->offset;	 /* dt this time step */
2370182007Sroberto		instance->saw_tooth = (s_char) instance->BEHn[14]; /* update for next time Hn[14] */
2371132451Sroberto		dt2 = instance->saw_tooth + instance->offset;	 /* dt next time step */
2372132451Sroberto	} else {
2373132451Sroberto		if (instance->BEHn[21]) /* bad TRAIM */
2374132451Sroberto			return;
2375132451Sroberto
2376132451Sroberto		dt1 = instance->saw_tooth + instance->offset;	 /* dt this time step */
2377182007Sroberto		instance->saw_tooth = (s_char) instance->BEHn[25]; /* update for next time Bn[25], En[25] */
2378132451Sroberto		dt2 = instance->saw_tooth + instance->offset;	 /* dt next time step */
2379132451Sroberto	}
2380132451Sroberto
2381132451Sroberto	oncore_get_timestamp(instance, dt1, dt2);
238282498Sroberto}
238382498Sroberto
238482498Sroberto
238582498Sroberto
238682498Sroberto/* Here for @@Ca, @@Fa and @@Ia messages */
238782498Sroberto
2388132451Sroberto/* These are Self test Commands for 6, 8, and 12 chan receivers.
2389132451Sroberto * There are good reasons NOT to do a @@Ca, @@Fa or @@Ia command with the ONCORE.
2390132451Sroberto * It was found that under some circumstances the following
239182498Sroberto * command would fail if issued immediately after the return from the
239282498Sroberto * @@Fa, but a 2sec delay seemed to fix things.  Since simply calling
2393132451Sroberto * sleep(2) is wasteful, and may cause trouble for some OS's, repeating
2394132451Sroberto * itimer, we set a flag, and test it at the next POLL.  If it hasn't
239582498Sroberto * been cleared, we reissue the @@Cj that is issued below.
239682498Sroberto * Note that we do a @@Cj at the beginning, and again here.
239782498Sroberto * The first is to get the info, the 2nd is just used as a safe command
239882498Sroberto * after the @@Fa for all Oncores (and it was in this posn in the
239982498Sroberto * original code).
240082498Sroberto */
240182498Sroberto
240282498Srobertostatic void
240382498Srobertooncore_msg_CaFaIa(
240482498Sroberto	struct instance *instance,
240582498Sroberto	u_char *buf,
240682498Sroberto	size_t len
240782498Sroberto	)
240882498Sroberto{
240982498Sroberto	char *cp;
2410132451Sroberto	int	i;
241182498Sroberto
241282498Sroberto	if (instance->o_state == ONCORE_TEST_SENT) {
2413132451Sroberto		enum antenna_state antenna;
241482498Sroberto
241582498Sroberto		instance->timeout = 0;
241682498Sroberto
2417182007Sroberto#ifdef DEBUG
241882498Sroberto		if (debug > 2) {
241982498Sroberto			if (buf[2] == 'I')
242082498Sroberto				printf("ONCORE[%d]: >>@@%ca %x %x %x\n", instance->unit, buf[2], buf[4], buf[5], buf[6]);
242182498Sroberto			else
242282498Sroberto				printf("ONCORE[%d]: >>@@%ca %x %x\n", instance->unit, buf[2], buf[4], buf[5]);
242382498Sroberto		}
2424182007Sroberto#endif
242582498Sroberto
2426132451Sroberto		antenna = (buf[4] & 0xc0) >> 6;
242782498Sroberto		buf[4] &= ~0xc0;
242882498Sroberto
2429132451Sroberto		i = buf[4] || buf[5];
2430132451Sroberto		if (buf[2] == 'I') i = i || buf[6];
2431132451Sroberto		if (i) {
2432132451Sroberto			if (buf[2] == 'I') {
2433132451Sroberto				msyslog(LOG_ERR, "ONCORE[%d]: self test failed: result %02x %02x %02x",
2434132451Sroberto					instance->unit, buf[4], buf[5], buf[6]);
2435132451Sroberto			} else {
2436132451Sroberto				msyslog(LOG_ERR, "ONCORE[%d]: self test failed: result %02x %02x",
2437132451Sroberto					instance->unit, buf[4], buf[5]);
2438132451Sroberto			}
2439132451Sroberto			cp = "ONCORE: self test failed, shutting down driver";
2440132451Sroberto			record_clock_stats(&instance->peer->srcadr, cp);
2441132451Sroberto
2442132451Sroberto			refclock_report(instance->peer, CEVNT_FAULT);
244382498Sroberto			oncore_shutdown(instance->unit, instance->peer);
244482498Sroberto			return;
244582498Sroberto		}
244682498Sroberto
2447132451Sroberto		/* report the current antenna state */
244882498Sroberto
2449132451Sroberto		oncore_antenna_report(instance, antenna);
245082498Sroberto
245182498Sroberto		instance->o_state = ONCORE_INIT;
245282498Sroberto		cp = "state = ONCORE_INIT";
245382498Sroberto		record_clock_stats(&(instance->peer->srcadr), cp);
2454132451Sroberto
2455132451Sroberto		instance->timeout = 4;
2456132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
245782498Sroberto	}
245882498Sroberto}
245982498Sroberto
246082498Sroberto
246182498Sroberto
2462132451Sroberto/*
2463132451Sroberto * Demultiplex the almanac into shmem
2464132451Sroberto */
246582498Sroberto
246682498Srobertostatic void
2467132451Srobertooncore_msg_Cb(
246882498Sroberto	struct instance *instance,
246982498Sroberto	u_char *buf,
247082498Sroberto	size_t len
247182498Sroberto	)
247282498Sroberto{
2473132451Sroberto	int i;
247454359Sroberto
2475132451Sroberto	if (instance->shmem == NULL)
2476132451Sroberto		return;
247782498Sroberto
2478132451Sroberto	if (buf[4] == 5 && buf[5] > 0 && buf[5] < 26)
2479132451Sroberto		i = buf[5];
2480132451Sroberto	else if (buf[4] == 4 && buf[5] <= 5)
2481132451Sroberto		i = buf[5] + 24;
2482132451Sroberto	else if (buf[4] == 4 && buf[5] <= 10)
2483132451Sroberto		i = buf[5] + 23;
2484132451Sroberto	else if (buf[4] == 4 && buf[5] == 25)
2485132451Sroberto		i = 34;
2486132451Sroberto	else {
2487132451Sroberto		char *cp;
248882498Sroberto
2489132451Sroberto		cp = "Cb: Response is NO ALMANAC";
2490132451Sroberto		record_clock_stats(&(instance->peer->srcadr), cp);
249154359Sroberto		return;
2492132451Sroberto	}
249354359Sroberto
2494132451Sroberto	i *= 36;
2495132451Sroberto	instance->shmem[instance->shmem_Cb + i + 2]++;
2496132451Sroberto	memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3));
249754359Sroberto
2498132451Sroberto#if 1
2499132451Sroberto	{
2500132451Sroberto	char Msg[160];
2501132451Sroberto	sprintf(Msg, "See Cb [%d,%d]", buf[4], buf[5]);
2502132451Sroberto	record_clock_stats(&(instance->peer->srcadr), Msg);
250382498Sroberto	}
2504132451Sroberto#endif
2505132451Sroberto}
250682498Sroberto
250782498Sroberto
2508132451Sroberto
2509132451Sroberto/*
2510132451Sroberto * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup
2511132451Sroberto *	not so for VP (eeprom) or any unit with a battery
2512132451Sroberto */
2513132451Sroberto
2514132451Srobertostatic void
2515132451Srobertooncore_msg_Cf(
2516132451Sroberto	struct instance *instance,
2517132451Sroberto	u_char *buf,
2518132451Sroberto	size_t len
2519132451Sroberto	)
2520132451Sroberto{
2521132451Sroberto	const char *cp;
2522132451Sroberto
2523132451Sroberto	if (instance->o_state == ONCORE_RESET_SENT) {
2524132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to  Posn Fix mode */
2525132451Sroberto										       /* Reset set VP to IDLE */
2526132451Sroberto		instance->o_state = ONCORE_TEST_SENT;
2527132451Sroberto		cp = "state = ONCORE_TEST_SENT";
2528132451Sroberto		record_clock_stats(&(instance->peer->srcadr), cp);
2529132451Sroberto
2530132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
253182498Sroberto	}
2532132451Sroberto}
253382498Sroberto
253482498Sroberto
253582498Sroberto
2536132451Sroberto/*
2537132451Sroberto * This is the Grand Central Station for the Preliminary Initialization.
2538132451Sroberto * Once done here we move on to oncore_msg_BaEaHa for final Initialization and Running.
2539132451Sroberto *
2540132451Sroberto * We do an @@Cj whenever we need a safe command for all Oncores.
2541132451Sroberto * The @@Cj gets us back here where we can switch to the next phase of setup.
2542132451Sroberto *
2543132451Sroberto * o Once at the very beginning (in start) to get the Model number.
2544132451Sroberto *   This info is printed, but no longer used.
2545132451Sroberto * o Again after we have determined the number of Channels in the receiver.
2546132451Sroberto * o And once later after we have done a reset and test, (which may hang),
2547132451Sroberto *   as we are about to initialize the Oncore and start it running.
2548132451Sroberto * o We have one routine below for each case.
2549132451Sroberto */
255082498Sroberto
2551132451Srobertostatic void
2552132451Srobertooncore_msg_Cj(
2553132451Sroberto	struct instance *instance,
2554132451Sroberto	u_char *buf,
2555132451Sroberto	size_t len
2556132451Sroberto	)
2557132451Sroberto{
2558132451Sroberto	int	mode;
2559132451Sroberto	char	*cp;
256082498Sroberto
2561132451Sroberto	memcpy(instance->Cj, buf, len);
256282498Sroberto
2563132451Sroberto	instance->timeout = 0;
2564132451Sroberto	if (instance->o_state == ONCORE_CHECK_ID) {
2565132451Sroberto		oncore_msg_Cj_id(instance, buf, len);
2566132451Sroberto		oncore_chan_test(instance);
2567132451Sroberto	} else if (instance->o_state == ONCORE_HAVE_CHAN) {
2568132451Sroberto		mode = instance->init_type;
2569132451Sroberto		if (mode == 3 || mode == 4) {	/* Cf will return here to check for TEST */
2570132451Sroberto			instance->o_state = ONCORE_RESET_SENT;
2571132451Sroberto			cp = "state = ONCORE_RESET_SENT";
257282498Sroberto			record_clock_stats(&(instance->peer->srcadr), cp);
2573132451Sroberto			oncore_sendmsg(instance->ttyfd, oncore_cmd_Cf, sizeof(oncore_cmd_Cf));
2574132451Sroberto		} else {
2575132451Sroberto			instance->o_state = ONCORE_TEST_SENT;
2576132451Sroberto			cp = "state = ONCORE_TEST_SENT";
2577132451Sroberto			record_clock_stats(&(instance->peer->srcadr), cp);
257882498Sroberto		}
257982498Sroberto	}
258082498Sroberto
2581132451Sroberto	if (instance->o_state == ONCORE_TEST_SENT) {
2582132451Sroberto		if (instance->chan == 6)
2583132451Sroberto			oncore_sendmsg(instance->ttyfd, oncore_cmd_Ca, sizeof(oncore_cmd_Ca));
2584132451Sroberto		else if (instance->chan == 8)
2585132451Sroberto			oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof(oncore_cmd_Fa));
2586132451Sroberto		else if (instance->chan == 12)
2587132451Sroberto			oncore_sendmsg(instance->ttyfd, oncore_cmd_Ia, sizeof(oncore_cmd_Ia));
2588132451Sroberto	} else if (instance->o_state == ONCORE_INIT)
2589132451Sroberto		oncore_msg_Cj_init(instance, buf, len);
2590132451Sroberto}
259182498Sroberto
259282498Sroberto
259382498Sroberto
2594132451Sroberto/* The information on determining a Oncore 'Model', viz VP, UT, etc, from
2595132451Sroberto *	the Model Number comes from "Richard M. Hambly" <rick@cnssys.com>
2596132451Sroberto *	and from Motorola.  Until recently Rick was the only source of
2597132451Sroberto *	this information as Motorola didn't give the information out.
2598132451Sroberto *
2599132451Sroberto * Determine the Type from the Model #, this determines #chan and if TRAIM is
2600132451Sroberto *   available.
2601132451Sroberto *
2602132451Sroberto * The Information from this routine is NO LONGER USED.
2603132451Sroberto * The RESULTS are PRINTED, BUT NOT USED, and the routine COULD BE DELETED
2604132451Sroberto */
260582498Sroberto
2606132451Srobertostatic void
2607132451Srobertooncore_msg_Cj_id(
2608132451Sroberto	struct instance *instance,
2609132451Sroberto	u_char *buf,
2610132451Sroberto	size_t len
2611132451Sroberto	)
2612132451Sroberto{
2613132451Sroberto	char *cp, *cp1, *cp2, Model[21], Msg[160];
2614132451Sroberto
2615132451Sroberto	/* Write Receiver ID message to clockstats file */
2616132451Sroberto
2617132451Sroberto	instance->Cj[294] = '\0';
2618132451Sroberto	for (cp=(char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) {
2619132451Sroberto		cp1 = strchr(cp, '\r');
2620132451Sroberto		if (!cp1)
2621132451Sroberto			cp1 = (char *)&instance->Cj[294];
2622132451Sroberto		*cp1 = '\0';
2623132451Sroberto		record_clock_stats(&(instance->peer->srcadr), cp);
2624132451Sroberto		*cp1 = '\r';
2625132451Sroberto		cp = cp1+2;
262682498Sroberto	}
262782498Sroberto
2628132451Sroberto	/* next, the Firmware Version and Revision numbers */
262982498Sroberto
2630182007Sroberto	instance->version  = atoi((char *) &instance->Cj[83]);
2631182007Sroberto	instance->revision = atoi((char *) &instance->Cj[111]);
263282498Sroberto
2633132451Sroberto	/* from model number decide which Oncore this is,
2634132451Sroberto		and then the number of channels */
263582498Sroberto
2636182007Sroberto	for (cp= (char *) &instance->Cj[160]; *cp == ' '; cp++)   /* start right after 'Model #' */
2637132451Sroberto		;
2638132451Sroberto	cp1 = cp;
2639132451Sroberto	cp2 = Model;
2640132451Sroberto	for (; !isspace((int)*cp) && cp-cp1 < 20; cp++, cp2++)
2641132451Sroberto		*cp2 = *cp;
2642132451Sroberto	*cp2 = '\0';
2643132451Sroberto
2644132451Sroberto	cp = 0;
2645132451Sroberto	if (!strncmp(Model, "PVT6", (size_t) 4)) {
2646132451Sroberto		cp = "PVT6";
2647132451Sroberto		instance->model = ONCORE_PVT6;
2648132451Sroberto	} else if (Model[0] == 'A') {
2649132451Sroberto		cp = "Basic";
2650132451Sroberto		instance->model = ONCORE_BASIC;
2651132451Sroberto	} else if (Model[0] == 'B' || !strncmp(Model, "T8", (size_t) 2)) {
2652132451Sroberto		cp = "VP";
2653132451Sroberto		instance->model = ONCORE_VP;
2654132451Sroberto	} else if (Model[0] == 'P') {
2655132451Sroberto		cp = "M12";
2656132451Sroberto		instance->model = ONCORE_M12;
2657132451Sroberto	} else if (Model[0] == 'R' || Model[0] == 'D' || Model[0] == 'S') {
2658132451Sroberto		if (Model[5] == 'N') {
2659132451Sroberto			cp = "GT";
2660132451Sroberto			instance->model = ONCORE_GT;
2661132451Sroberto		} else if ((Model[1] == '3' || Model[1] == '4') && Model[5] == 'G') {
2662132451Sroberto			cp = "GT+";
2663132451Sroberto			instance->model = ONCORE_GTPLUS;
2664132451Sroberto		} else if ((Model[1] == '5' && Model[5] == 'U') || (Model[1] == '1' && Model[5] == 'A')) {
2665132451Sroberto				cp = "UT";
2666132451Sroberto				instance->model = ONCORE_UT;
2667132451Sroberto		} else if (Model[1] == '5' && Model[5] == 'G') {
2668132451Sroberto			cp = "UT+";
2669132451Sroberto			instance->model = ONCORE_UTPLUS;
2670132451Sroberto		} else if (Model[1] == '6' && Model[5] == 'G') {
2671132451Sroberto			cp = "SL";
2672132451Sroberto			instance->model = ONCORE_SL;
2673132451Sroberto		} else {
2674132451Sroberto			cp = "Unknown";
2675132451Sroberto			instance->model = ONCORE_UNKNOWN;
267654359Sroberto		}
2677132451Sroberto	} else	{
2678132451Sroberto		cp = "Unknown";
2679132451Sroberto		instance->model = ONCORE_UNKNOWN;
268054359Sroberto	}
268154359Sroberto
2682132451Sroberto	/* use MODEL to set CHAN and TRAIM and possibly zero SHMEM */
268354359Sroberto
2684132451Sroberto	sprintf(Msg, "This looks like an Oncore %s with version %d.%d firmware.", cp, instance->version, instance->revision);
2685132451Sroberto	record_clock_stats(&(instance->peer->srcadr), Msg);
268682498Sroberto
2687132451Sroberto	instance->chan_id = 8;	   /* default */
2688132451Sroberto	if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
2689132451Sroberto		instance->chan_id = 6;
2690132451Sroberto	else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS)
2691132451Sroberto		instance->chan_id = 8;
2692132451Sroberto	else if (instance->model == ONCORE_M12)
2693132451Sroberto		instance->chan_id = 12;
269482498Sroberto
2695132451Sroberto	instance->traim_id = 0;    /* default */
2696132451Sroberto	if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
2697132451Sroberto		instance->traim_id = 0;
2698132451Sroberto	else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS)
2699132451Sroberto		instance->traim_id = 1;
2700132451Sroberto	else if (instance->model == ONCORE_M12)
2701132451Sroberto		instance->traim_id = -1;
270282498Sroberto
2703132451Sroberto	sprintf(Msg, "Channels = %d, TRAIM = %s", instance->chan_id,
2704132451Sroberto		((instance->traim_id < 0) ? "UNKNOWN" : ((instance->traim_id > 0) ? "ON" : "OFF")));
2705132451Sroberto	record_clock_stats(&(instance->peer->srcadr), Msg);
2706132451Sroberto}
2707132451Sroberto
2708132451Sroberto
2709132451Sroberto
2710132451Sroberto/* OK, know type of Oncore, have possibly reset it, and have tested it.
2711132451Sroberto * We know the number of channels.
2712132451Sroberto * We will determine whether we have TRAIM before we actually start.
2713132451Sroberto * Now initialize.
2714132451Sroberto */
2715132451Sroberto
2716132451Srobertostatic void
2717132451Srobertooncore_msg_Cj_init(
2718132451Sroberto	struct instance *instance,
2719132451Sroberto	u_char *buf,
2720132451Sroberto	size_t len
2721132451Sroberto	)
2722132451Sroberto{
2723182007Sroberto	char *cp, Msg[160];
2724182007Sroberto	u_char Cmd[20];
2725132451Sroberto	int	mode;
2726132451Sroberto
2727132451Sroberto
2728132451Sroberto	/* The M12 with 1.3 or 2.0 Firmware, loses track of all Satellites and has to
2729132451Sroberto	 * start again if we go from 0D -> 3D, then loses them again when we
2730132451Sroberto	 * go from 3D -> 0D.  We do this to get a @@Ea message for SHMEM.
2731132451Sroberto	 * For NOW we will turn this aspect of filling SHMEM off for the M12
273282498Sroberto	 */
273382498Sroberto
2734132451Sroberto	if (instance->chan == 12) {
2735132451Sroberto		instance->shmem_bad_Ea = 1;
2736132451Sroberto		sprintf(Msg, "*** SHMEM partially enabled for ONCORE M12 s/w v%d.%d ***", instance->version, instance->revision);
2737132451Sroberto		record_clock_stats(&(instance->peer->srcadr), Msg);
273854359Sroberto	}
273954359Sroberto
2740132451Sroberto	oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to  Posn Fix mode */
2741132451Sroberto	oncore_sendmsg(instance->ttyfd, oncore_cmd_Bb, sizeof(oncore_cmd_Bb)); /* turn on for shmem (6/8/12) */
2742132451Sroberto	oncore_sendmsg(instance->ttyfd, oncore_cmd_Ek, sizeof(oncore_cmd_Ek)); /* turn off (VP) */
2743132451Sroberto	oncore_sendmsg(instance->ttyfd, oncore_cmd_Aw, sizeof(oncore_cmd_Aw)); /* UTC time (6/8/12) */
2744132451Sroberto	oncore_sendmsg(instance->ttyfd, oncore_cmd_AB, sizeof(oncore_cmd_AB)); /* Appl type static (VP) */
2745132451Sroberto	oncore_sendmsg(instance->ttyfd, oncore_cmd_Be, sizeof(oncore_cmd_Be)); /* Tell us the Almanac for shmem (6/8/12) */
2746132451Sroberto	oncore_sendmsg(instance->ttyfd, oncore_cmd_Bd, sizeof(oncore_cmd_Bd)); /* Tell us when Almanac changes */
274782498Sroberto
2748132451Sroberto	mode = instance->init_type;
274982498Sroberto
2750132451Sroberto	/* If there is Position input in the Config file
2751132451Sroberto	 * and mode = (1,3) set it as posn hold posn, goto 0D mode.
2752132451Sroberto	 *  or mode = (2,4) set it as INITIAL position, and do Site Survey.
275382498Sroberto	 */
275454359Sroberto
2755132451Sroberto	if (instance->posn_set) {
2756132451Sroberto		record_clock_stats(&(instance->peer->srcadr), "Setting Posn from input data");
2757132451Sroberto		oncore_set_posn(instance);	/* this should print posn indirectly thru the As cmd */
2758132451Sroberto	} else	/* must issue an @@At here to check on 6/8 Position Hold, set_posn would have */
2759132451Sroberto		if (instance->chan != 12)
2760132451Sroberto			oncore_sendmsg(instance->ttyfd, oncore_cmd_Atx, sizeof(oncore_cmd_Atx));
276182498Sroberto
2762132451Sroberto	if (mode != 0) {
2763132451Sroberto			/* cable delay in ns */
2764132451Sroberto		memcpy(Cmd, oncore_cmd_Az, (size_t) sizeof(oncore_cmd_Az));
2765132451Sroberto		w32_buf(&Cmd[-2+4], instance->delay);
2766132451Sroberto		oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Az));	/* 6,8,12 */
276782498Sroberto
2768132451Sroberto			/* PPS offset in ns */
2769132451Sroberto		if (instance->offset) {
2770132451Sroberto			memcpy(Cmd, oncore_cmd_Ay, (size_t) sizeof(oncore_cmd_Ay));	/* some have it, some don't */
2771132451Sroberto			w32_buf(&Cmd[-2+4], instance->offset);			/* will check for hw response */
2772132451Sroberto			oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Ay));
277382498Sroberto		}
2774132451Sroberto
2775132451Sroberto		/* Satellite mask angle */
2776132451Sroberto
2777132451Sroberto		if (instance->Ag != 0xff) {	/* will have 0xff in it if not set by user */
2778132451Sroberto			memcpy(Cmd, oncore_cmd_Ag, (size_t) sizeof(oncore_cmd_Ag));
2779132451Sroberto			Cmd[-2+4] = instance->Ag;
2780132451Sroberto			oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Ag));
2781132451Sroberto		}
278282498Sroberto	}
278382498Sroberto
2784132451Sroberto	/* 6, 8 12 chan - Position/Status/Data Output Message, 1/s
2785132451Sroberto	 * now we're really running
2786132451Sroberto	 * these were ALL started in the chan test,
2787132451Sroberto	 * However, if we had mode=3,4 then commands got turned off, so we turn
2788132451Sroberto	 * them on again here just in case
278954359Sroberto	 */
279054359Sroberto
2791132451Sroberto	if (instance->chan == 6) { /* start 6chan, kill 8,12chan commands, possibly testing VP in 6chan mode */
2792132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0));
2793132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_En0, sizeof(oncore_cmd_En0));
2794132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0));
2795132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
2796132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba,	sizeof(oncore_cmd_Ba ));
2797132451Sroberto	} else if (instance->chan == 8) {  /* start 8chan, kill 6,12chan commands */
2798132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0));
2799132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0));
2800132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0));
2801132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
2802132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea,	sizeof(oncore_cmd_Ea ));
2803132451Sroberto	} else if (instance->chan == 12){  /* start 12chan, kill 6,12chan commands */
2804132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0));
2805132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0));
2806132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0));
2807132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_En0, sizeof(oncore_cmd_En0));
2808132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha,	sizeof(oncore_cmd_Ha ));
280954359Sroberto	}
281054359Sroberto
2811132451Sroberto	instance->count = 1;
2812132451Sroberto	instance->o_state = ONCORE_ALMANAC;
2813132451Sroberto	cp = "state = ONCORE_ALMANAC";
2814132451Sroberto	record_clock_stats(&(instance->peer->srcadr), cp);
2815132451Sroberto}
281682498Sroberto
281754359Sroberto
281854359Sroberto
2819132451Sroberto/* 12chan position */
282054359Sroberto
2821132451Srobertostatic void
2822132451Srobertooncore_msg_Ga(
2823132451Sroberto	struct instance *instance,
2824132451Sroberto	u_char *buf,
2825132451Sroberto	size_t len
2826132451Sroberto	)
2827132451Sroberto{
2828132451Sroberto	char Msg[160];
2829132451Sroberto	long lat, lon, ht;
2830132451Sroberto	double Lat, Lon, Ht;
283154359Sroberto
283254359Sroberto
2833132451Sroberto	lat = buf_w32(&buf[4]);
2834132451Sroberto	lon = buf_w32(&buf[8]);
2835132451Sroberto	ht  = buf_w32(&buf[12]);  /* GPS ellipsoid */
283654359Sroberto
2837132451Sroberto	Lat = lat;
2838132451Sroberto	Lon = lon;
2839132451Sroberto	Ht  = ht;
284054359Sroberto
2841132451Sroberto	Lat /= 3600000;
2842132451Sroberto	Lon /= 3600000;
2843132451Sroberto	Ht  /= 100;
2844132451Sroberto
2845132451Sroberto
2846132451Sroberto	sprintf(Msg, "Ga Posn Lat = %.7f, Lon = %.7f, Ht  = %.2f", Lat, Lon, Ht);
284756746Sroberto	record_clock_stats(&(instance->peer->srcadr), Msg);
284856746Sroberto
2849132451Sroberto	instance->ss_lat  = lat;
2850132451Sroberto	instance->ss_long = lon;
2851132451Sroberto	instance->ss_ht   = ht;
285254359Sroberto
2853132451Sroberto	oncore_print_posn(instance);
2854132451Sroberto}
285582498Sroberto
285682498Sroberto
285782498Sroberto
2858132451Sroberto/* 12 chan time/date */
285982498Sroberto
2860132451Srobertostatic void
2861132451Srobertooncore_msg_Gb(
2862132451Sroberto	struct instance *instance,
2863132451Sroberto	u_char *buf,
2864132451Sroberto	size_t len
2865132451Sroberto	)
2866132451Sroberto{
2867132451Sroberto	char	Msg[160], *gmts;
2868132451Sroberto	int	mo, d, y, h, m, s, gmth, gmtm;
286982498Sroberto
2870132451Sroberto	mo = buf[4];
2871132451Sroberto	d  = buf[5];
2872132451Sroberto	y  = 256*buf[6]+buf[7];
2873132451Sroberto
2874132451Sroberto	h  = buf[8];
2875132451Sroberto	m  = buf[9];
2876132451Sroberto	s  = buf[10];
2877132451Sroberto
2878132451Sroberto	gmts = ((buf[11] == 0) ? "+" : "-");
2879132451Sroberto	gmth = buf[12];
2880132451Sroberto	gmtm = buf[13];
2881132451Sroberto
2882132451Sroberto	sprintf(Msg, "Date/Time set to: %d%s%d %2d:%02d:%02d GMT (GMT offset is %s%02d:%02d)",
2883182007Sroberto		d, Month[mo-1], y, h, m, s, gmts, gmth, gmtm);
2884132451Sroberto	record_clock_stats(&(instance->peer->srcadr), Msg);
288554359Sroberto}
288654359Sroberto
288754359Sroberto
288854359Sroberto
2889132451Sroberto/* Leap Second for M12, gives all info from satellite message */
2890132451Sroberto/* also in UT v3.0 */
289182498Sroberto
289282498Srobertostatic void
2893132451Srobertooncore_msg_Gj(
289482498Sroberto	struct instance *instance,
2895132451Sroberto	u_char *buf,
2896132451Sroberto	size_t len
289782498Sroberto	)
289882498Sroberto{
2899132451Sroberto	int dt;
2900132451Sroberto	char Msg[160], *cp;
290154359Sroberto
2902132451Sroberto	instance->saw_Gj = 1; /* flag, saw_Gj, dont need to try Bj in check_leap */
290354359Sroberto
2904132451Sroberto	/* print the message to verify whats there */
290554359Sroberto
2906132451Sroberto	dt = buf[5] - buf[4];
290754359Sroberto
2908132451Sroberto#if 1
2909132451Sroberto	sprintf(Msg, "ONCORE[%d]: Leap Sec Msg: %d %d %d %d %d %d %d %d %d %d",
2910132451Sroberto			instance->unit,
2911132451Sroberto			buf[4], buf[5], 256*buf[6]+buf[7], buf[8], buf[9], buf[10],
2912132451Sroberto			(buf[14]+256*(buf[13]+256*(buf[12]+256*buf[11]))),
2913132451Sroberto			buf[15], buf[16], buf[17]);
2914132451Sroberto	record_clock_stats(&(instance->peer->srcadr), Msg);
2915132451Sroberto#endif
2916132451Sroberto	if (dt) {
2917132451Sroberto		sprintf(Msg, "ONCORE[%d]: Leap second (%d) scheduled for %d%s%d at %d:%d:%d",
2918132451Sroberto			instance->unit,
2919182007Sroberto			dt, buf[9], Month[buf[8]-1], 256*buf[6]+buf[7],
2920132451Sroberto			buf[15], buf[16], buf[17]);
2921132451Sroberto		record_clock_stats(&(instance->peer->srcadr), Msg);
292254359Sroberto	}
292354359Sroberto
2924132451Sroberto	/* Only raise warning within a month of the leap second */
292554359Sroberto
2926182007Sroberto	instance->pp->leap = LEAP_NOWARNING;
2927182007Sroberto	cp = "Set pp.leap to LEAP_NOWARNING";
292854359Sroberto
2929132451Sroberto	if (buf[6] == instance->BEHa[6] && buf[7] == instance->BEHa[7] && /* year */
2930132451Sroberto	    buf[8] == instance->BEHa[4]) {	/* month */
2931132451Sroberto		if (dt) {
2932132451Sroberto			if (dt < 0) {
2933182007Sroberto				instance->pp->leap = LEAP_DELSECOND;
2934182007Sroberto				cp = "Set pp.leap to LEAP_DELSECOND";
2935132451Sroberto			} else {
2936182007Sroberto				instance->pp->leap = LEAP_ADDSECOND;
2937182007Sroberto				cp = "Set pp.leap to LEAP_ADDSECOND";
2938132451Sroberto			}
293954359Sroberto		}
2940132451Sroberto	}
2941132451Sroberto	record_clock_stats(&(instance->peer->srcadr), cp);
2942132451Sroberto}
294354359Sroberto
294454359Sroberto
294554359Sroberto
2946132451Sroberto/* Power on failure */
294754359Sroberto
2948132451Srobertostatic void
2949132451Srobertooncore_msg_Sz(
2950132451Sroberto	struct instance *instance,
2951132451Sroberto	u_char *buf,
2952132451Sroberto	size_t len
2953132451Sroberto	)
2954132451Sroberto{
2955132451Sroberto	const char *cp;
2956132451Sroberto
2957132451Sroberto	cp = "Oncore: System Failure at Power On";
2958132451Sroberto	if (instance && instance->peer) {
2959132451Sroberto		record_clock_stats(&(instance->peer->srcadr), cp);
2960132451Sroberto		oncore_shutdown(instance->unit, instance->peer);
296154359Sroberto	}
2962132451Sroberto}
296354359Sroberto
2964132451Sroberto/************** Small Subroutines ***************/
296554359Sroberto
296654359Sroberto
2967132451Srobertostatic void
2968132451Srobertooncore_antenna_report(
2969132451Sroberto	struct instance *instance,
2970132451Sroberto	enum antenna_state new_state)
2971132451Sroberto{
2972132451Sroberto	char *cp;
2973132451Sroberto
2974132451Sroberto	if (instance->ant_state == new_state)
297554359Sroberto		return;
297654359Sroberto
2977132451Sroberto	switch (new_state) {
2978132451Sroberto	case ONCORE_ANTENNA_OK: cp = "GPS antenna: OK";                   break;
2979132451Sroberto	case ONCORE_ANTENNA_OC: cp = "GPS antenna: short (overcurrent)";  break;
2980132451Sroberto	case ONCORE_ANTENNA_UC: cp = "GPS antenna: open (not connected)"; break;
2981132451Sroberto	case ONCORE_ANTENNA_NV: cp = "GPS antenna: short (no voltage)";   break;
2982132451Sroberto	default:		cp = "GPS antenna: ?";                    break;
298356746Sroberto	}
298454359Sroberto
2985132451Sroberto	instance->ant_state = new_state;
2986132451Sroberto	record_clock_stats(&instance->peer->srcadr, cp);
2987132451Sroberto}
298854359Sroberto
298954359Sroberto
299054359Sroberto
2991132451Srobertostatic void
2992132451Srobertooncore_chan_test(
2993132451Sroberto	struct instance *instance
2994132451Sroberto	)
2995132451Sroberto{
2996132451Sroberto	char	*cp;
299782498Sroberto
2998132451Sroberto	/* subroutine oncore_Cj_id has determined the number of channels from the
2999132451Sroberto	 * model number of the attached oncore.  This is not always correct since
3000132451Sroberto	 * the oncore could have non-standard firmware.  Here we check (independently) by
3001132451Sroberto	 * trying a 6, 8, and 12 chan command, and see which responds.
3002132451Sroberto	 * Caution: more than one CAN respond.
300382498Sroberto	 *
3004132451Sroberto	 * This #chan is used by the code rather than that calculated from the model number.
300582498Sroberto	 */
300682498Sroberto
3007132451Sroberto	instance->o_state = ONCORE_CHECK_CHAN;
3008132451Sroberto	cp = "state = ONCORE_CHECK_CHAN";
3009132451Sroberto	record_clock_stats(&(instance->peer->srcadr), cp);
301054359Sroberto
3011132451Sroberto	instance->count3 = 1;
3012132451Sroberto	oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba, sizeof(oncore_cmd_Ba));
3013132451Sroberto	oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea, sizeof(oncore_cmd_Ea));
3014132451Sroberto	oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha, sizeof(oncore_cmd_Ha));
3015132451Sroberto}
301682498Sroberto
301782498Sroberto
301882498Sroberto
3019132451Sroberto/* check for a GOOD Almanac, have we got one yet? */
302054359Sroberto
3021132451Srobertostatic void
3022132451Srobertooncore_check_almanac(
3023132451Sroberto	struct instance *instance
3024132451Sroberto	)
3025132451Sroberto{
3026132451Sroberto	if (instance->chan == 6) {
3027132451Sroberto		instance->rsm.bad_almanac = instance->BEHa[64]&0x1;
3028132451Sroberto		instance->rsm.bad_fix	  = instance->BEHa[64]&0x52;
3029132451Sroberto	} else if (instance->chan == 8) {
3030132451Sroberto		instance->rsm.bad_almanac = instance->BEHa[72]&0x1;
3031132451Sroberto		instance->rsm.bad_fix	  = instance->BEHa[72]&0x52;
3032132451Sroberto	} else if (instance->chan == 12) {
3033182007Sroberto		int bits1, bits2, bits3;
3034132451Sroberto
3035132451Sroberto		bits1 = (instance->BEHa[129]>>5) & 0x7; 	/* actually Ha */
3036132451Sroberto		bits2 = instance->BEHa[130];
3037132451Sroberto		instance->rsm.bad_almanac = (bits2 & 0x80);
3038132451Sroberto		instance->rsm.bad_fix	  = (bits2 & 0x8) || (bits1 == 0x2);
3039132451Sroberto					  /* too few sat     Bad Geom	  */
3040182007Sroberto
3041182007Sroberto		bits3 = instance->BEHa[141];	/* UTC parameters */
3042182007Sroberto		if (!instance->count5_set && (bits3 & 0xC0)) {
3043182007Sroberto			instance->count5 = 2;
3044182007Sroberto			instance->count5_set = 1;
3045182007Sroberto		}
3046132451Sroberto#if 0
3047182007Sroberto{
3048182007Sroberto		char Msg[160];
3049182007Sroberto
3050182007Sroberto		sprintf(Msg, "ONCORE[%d]: DEBUG BITS: (%x %x), (%x %x %x),  %x %x %x %x %x\n",
3051132451Sroberto		instance->unit,
3052182007Sroberto		instance->BEHa[129], instance->BEHa[130], bits1, bits2, bits3, instance->mode == MODE_0D,
3053132451Sroberto		instance->mode == MODE_2D, instance->mode == MODE_3D,
3054132451Sroberto		instance->rsm.bad_almanac, instance->rsm.bad_fix);
3055182007Sroberto		record_clock_stats(&(instance->peer->srcadr), Msg);
3056182007Sroberto}
305754359Sroberto#endif
3058132451Sroberto	}
3059132451Sroberto}
306054359Sroberto
306154359Sroberto
306254359Sroberto
3063132451Sroberto/* check the antenna for changes (did it get unplugged?) */
306454359Sroberto
3065132451Srobertostatic void
3066132451Srobertooncore_check_antenna(
3067132451Sroberto	struct instance *instance
3068132451Sroberto	)
3069132451Sroberto{
3070132451Sroberto	enum antenna_state antenna;		/* antenna state */
307182498Sroberto
3072132451Sroberto	antenna = instance->ant_state;
3073132451Sroberto	if (instance->chan == 12)
3074132451Sroberto		antenna = (instance->BEHa[130] & 0x6 ) >> 1;
3075132451Sroberto	else
3076132451Sroberto		antenna = (instance->BEHa[37] & 0xc0) >> 6;  /* prob unset 6, set GT, UT unset VP */
307754359Sroberto
3078132451Sroberto	oncore_antenna_report (instance, antenna);
3079132451Sroberto}
3080132451Sroberto
3081132451Sroberto
3082132451Sroberto
3083132451Sroberto/*
3084132451Sroberto * Check the leap second status once per day.
3085132451Sroberto *
3086132451Sroberto * Note that the ONCORE firmware for the Bj command is wrong at
3087132451Sroberto * least in the VP.
3088132451Sroberto * It starts advertising a LEAP SECOND as soon as the GPS satellite
3089132451Sroberto * data message (page 18, subframe 4) is updated to a date in the
3090132451Sroberto * future, and does not wait for the month that it will occur.
3091132451Sroberto * The event will usually be advertised several months in advance.
3092132451Sroberto * Since there is a one bit flag, there is no way to tell if it is
3093132451Sroberto * this month, or when...
3094132451Sroberto *
3095132451Sroberto * As such, we have the workaround below, of only checking for leap
3096132451Sroberto * seconds with the Bj command in June/December.
3097132451Sroberto *
3098132451Sroberto * The Gj command gives more information, and we can tell in which
3099132451Sroberto * month to apply the correction.
3100132451Sroberto *
3101132451Sroberto * Note that with the VP we COULD read the raw data message, and
3102132451Sroberto * interpret it ourselves, but since this is specific to this receiver
3103132451Sroberto * only, and the above workaround is adequate, we don't bother.
3104132451Sroberto */
3105132451Sroberto
3106132451Srobertostatic void
3107132451Srobertooncore_check_leap_sec(
3108132451Sroberto	struct instance *instance
3109132451Sroberto	)
3110132451Sroberto{
3111132451Sroberto	if (instance->Bj_day != instance->BEHa[5]) {	 /* do this 1/day */
3112132451Sroberto		instance->Bj_day = instance->BEHa[5];
3113132451Sroberto
3114132451Sroberto		if (instance->saw_Gj < 0) {	/* -1 DONT have Gj use Bj */
3115132451Sroberto			if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12))
3116132451Sroberto				oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof(oncore_cmd_Bj));
3117132451Sroberto			return;
3118132451Sroberto		}
3119132451Sroberto
3120132451Sroberto		if (instance->saw_Gj == 0)	/* 0 is dont know if we have Gj */
3121132451Sroberto			instance->count4 = 1;
3122132451Sroberto
3123132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_Gj, sizeof(oncore_cmd_Gj));
312454359Sroberto		return;
312554359Sroberto	}
312654359Sroberto
3127132451Sroberto	/* Gj works for some 6/8 chan UT and the M12	  */
3128132451Sroberto	/* if no response from Gj in 5 sec, we try Bj	  */
3129132451Sroberto	/* which isnt implemented in all the GT/UT either */
313054359Sroberto
3131132451Sroberto	if (instance->count4) { 	/* delay, waiting for Gj response */
3132132451Sroberto		if (instance->saw_Gj == 1)
3133132451Sroberto			instance->count4 = 0;
3134132451Sroberto		else if (instance->count4++ > 5) {	/* delay, waiting for Gj response */
3135132451Sroberto			instance->saw_Gj = -1;		/* didnt see it, will use Bj */
3136132451Sroberto			instance->count4 = 0;
3137132451Sroberto			if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12))
3138132451Sroberto				oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof(oncore_cmd_Bj));
3139132451Sroberto		}
314054359Sroberto	}
314154359Sroberto}
314254359Sroberto
314354359Sroberto
314454359Sroberto
3145132451Sroberto/* check the message checksum,
3146132451Sroberto *  buf points to START of message ( @@ )
3147132451Sroberto *  len is length WITH CR/LF.
314854359Sroberto */
314982498Sroberto
3150132451Srobertostatic int
3151132451Srobertooncore_checksum_ok(
315254359Sroberto	u_char *buf,
3153132451Sroberto	int	len
315454359Sroberto	)
315554359Sroberto{
3156132451Sroberto	int	i, j;
315754359Sroberto
3158132451Sroberto	j = 0;
3159132451Sroberto	for (i = 2; i < len-3; i++)
3160132451Sroberto		j ^= buf[i];
316154359Sroberto
3162132451Sroberto	return(j == buf[len-3]);
3163132451Sroberto}
316454359Sroberto
316554359Sroberto
316654359Sroberto
316754359Srobertostatic void
3168132451Srobertooncore_compute_dH(
3169132451Sroberto	struct instance *instance
317054359Sroberto	)
317154359Sroberto{
3172132451Sroberto	int GPS, MSL;
3173132451Sroberto	char	Msg[160];
317454359Sroberto
3175132451Sroberto	/* Here calculate dH = GPS - MSL for output message */
3176132451Sroberto	/* also set Altitude Hold mode if GT */
3177132451Sroberto
3178132451Sroberto	instance->have_dH = 1;
3179132451Sroberto	if (instance->chan == 12) {
3180132451Sroberto		GPS = buf_w32(&instance->BEHa[39]);
3181132451Sroberto		MSL = buf_w32(&instance->BEHa[43]);
3182132451Sroberto	} else {
3183132451Sroberto		GPS = buf_w32(&instance->BEHa[23]);
3184132451Sroberto		MSL = buf_w32(&instance->BEHa[27]);
318554359Sroberto	}
3186132451Sroberto	instance->dH = GPS - MSL;
3187132451Sroberto	instance->dH /= 100.;
3188132451Sroberto
3189132451Sroberto	/* if MSL is not set, the calculation is meaningless */
3190132451Sroberto
3191132451Sroberto	if (MSL) {	/* not set ! */
3192132451Sroberto		sprintf(Msg, "dH = (GPS - MSL) = %.2fm", instance->dH);
3193132451Sroberto		record_clock_stats(&(instance->peer->srcadr), Msg);
3194132451Sroberto	}
319554359Sroberto}
319654359Sroberto
319754359Sroberto
3198132451Sroberto
3199132451Sroberto/*
3200132451Sroberto * try loading Almanac from shmem (where it was copied from shmem_old
3201132451Sroberto */
3202132451Sroberto
320382498Srobertostatic void
3204132451Srobertooncore_load_almanac(
3205132451Sroberto	struct instance *instance
320682498Sroberto	)
320782498Sroberto{
3208132451Sroberto	u_char	*cp, Cmd[20];
3209132451Sroberto	int	n;
3210132451Sroberto	struct timeval tv;
3211132451Sroberto	struct tm *tm;
321254359Sroberto
3213132451Sroberto	if (!instance->shmem)
3214132451Sroberto		return;
321582498Sroberto
321682498Sroberto#if 1
3217132451Sroberto	for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) {
3218182007Sroberto		if (!strncmp((char *) cp, "@@Cb", 4) &&
3219132451Sroberto		    oncore_checksum_ok(cp, 33) &&
3220132451Sroberto		    (*(cp+4) == 4 || *(cp+4) == 5)) {
3221132451Sroberto			write(instance->ttyfd, cp, n);
3222132451Sroberto#if 1
3223132451Sroberto			oncore_print_Cb(instance, cp);
322482498Sroberto#endif
3225132451Sroberto		}
3226132451Sroberto	}
3227132451Sroberto#else
3228132451Sroberto/************DEBUG************/
3229132451Sroberto	for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) {
3230132451Sroberto		char Msg[160];
3231132451Sroberto
3232132451Sroberto		sprintf(Msg, "See %c%c%c%c %d", *(cp), *(cp+1), *(cp+2), *(cp+3), *(cp+4));
323382498Sroberto		record_clock_stats(&(instance->peer->srcadr), Msg);
3234132451Sroberto
3235132451Sroberto		if (!strncmp(cp, "@@Cb", 4)) {
3236132451Sroberto			oncore_print_Cb(instance, cp);
3237132451Sroberto			if (oncore_checksum_ok(cp, 33)) {
3238132451Sroberto				if (*(cp+4) == 4 || *(cp+4) == 5) {
3239132451Sroberto					record_clock_stats(&(instance->peer->srcadr), "GOOD SF");
3240132451Sroberto					write(instance->ttyfd, cp, n);
3241132451Sroberto				} else
3242132451Sroberto					record_clock_stats(&(instance->peer->srcadr), "BAD SF");
3243132451Sroberto			} else
3244132451Sroberto				record_clock_stats(&(instance->peer->srcadr), "BAD CHECKSUM");
3245132451Sroberto		}
324682498Sroberto	}
3247132451Sroberto/************DEBUG************/
3248132451Sroberto#endif
324982498Sroberto
3250132451Sroberto	/* Must load position and time or the Almanac doesn't do us any good */
325182498Sroberto
3252132451Sroberto	if (!instance->posn_set) {	/* if we input a posn use it, else from SHMEM */
3253132451Sroberto		record_clock_stats(&(instance->peer->srcadr), "Loading Posn from SHMEM");
3254132451Sroberto		for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2));  cp+=(n+3)) {
3255182007Sroberto			if ((instance->chan == 6  && (!strncmp((char *) cp, "@@Ba", 4) && oncore_checksum_ok(cp,  68))) ||
3256182007Sroberto			    (instance->chan == 8  && (!strncmp((char *) cp, "@@Ea", 4) && oncore_checksum_ok(cp,  76))) ||
3257182007Sroberto			    (instance->chan == 12 && (!strncmp((char *) cp, "@@Ha", 4) && oncore_checksum_ok(cp, 154)))) {
3258132451Sroberto				int ii, jj, kk;
325982498Sroberto
3260132451Sroberto				instance->posn_set = 1;
3261132451Sroberto				ii = buf_w32(cp + 15);
3262132451Sroberto				jj = buf_w32(cp + 19);
3263132451Sroberto				kk = buf_w32(cp + 23);
3264182007Sroberto#if 0
3265132451Sroberto{
3266132451Srobertochar Msg[160];
3267182007Srobertosprintf(Msg, "SHMEM posn = %ld (%d, %d, %d)", (long) (cp-instance->shmem), ii, jj, kk);
3268132451Srobertorecord_clock_stats(&(instance->peer->srcadr), Msg);
3269132451Sroberto}
3270182007Sroberto#endif
3271132451Sroberto				if (ii != 0 || jj != 0 || kk != 0) { /* phk asked for this test */
3272132451Sroberto					instance->ss_lat  = ii;
3273132451Sroberto					instance->ss_long = jj;
3274132451Sroberto					instance->ss_ht   = kk;
3275132451Sroberto				}
327682498Sroberto			}
327782498Sroberto		}
327882498Sroberto	}
3279132451Sroberto	oncore_set_posn(instance);
3280132451Sroberto
3281132451Sroberto	/* and set time to time from Computer clock */
3282132451Sroberto
3283132451Sroberto	gettimeofday(&tv, 0);
3284132451Sroberto	tm = gmtime((const time_t *) &tv.tv_sec);
3285132451Sroberto#if 1
3286132451Sroberto	{
3287132451Sroberto	char Msg[160];
3288132451Sroberto	sprintf(Msg, "DATE %d %d %d, %d %d %d", 1900+tm->tm_year, tm->tm_mon, tm->tm_mday,
3289132451Sroberto		tm->tm_hour, tm->tm_min, tm->tm_sec);
3290132451Sroberto	record_clock_stats(&(instance->peer->srcadr), Msg);
3291132451Sroberto	}
3292132451Sroberto#endif
3293132451Sroberto	if (instance->chan == 12) {
3294132451Sroberto		memcpy(Cmd, oncore_cmd_Gb, (size_t) sizeof(oncore_cmd_Gb));
3295182007Sroberto		Cmd[-2+4]  = tm->tm_mon + 1;
3296132451Sroberto		Cmd[-2+5]  = tm->tm_mday;
3297132451Sroberto		Cmd[-2+6]  = (1900+tm->tm_year)/256;
3298132451Sroberto		Cmd[-2+7]  = (1900+tm->tm_year)%256;
3299132451Sroberto		Cmd[-2+8]  = tm->tm_hour;
3300132451Sroberto		Cmd[-2+9]  = tm->tm_min;
3301132451Sroberto		Cmd[-2+10] = tm->tm_sec;
3302132451Sroberto		Cmd[-2+11] = 0;
3303132451Sroberto		Cmd[-2+12] = 0;
3304132451Sroberto		Cmd[-2+13] = 0;
3305132451Sroberto		oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Gb));
3306132451Sroberto	} else {
3307132451Sroberto		/* First set GMT offset to zero */
3308132451Sroberto
3309132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ab,	sizeof(oncore_cmd_Ab));
3310132451Sroberto
3311132451Sroberto		memcpy(Cmd, oncore_cmd_Ac, (size_t) sizeof(oncore_cmd_Ac));
3312182007Sroberto		Cmd[-2+4] = tm->tm_mon + 1;
3313132451Sroberto		Cmd[-2+5] = tm->tm_mday;
3314132451Sroberto		Cmd[-2+6] = (1900+tm->tm_year)/256;
3315132451Sroberto		Cmd[-2+7] = (1900+tm->tm_year)%256;
3316132451Sroberto		oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Ac));
3317132451Sroberto
3318132451Sroberto		memcpy(Cmd, oncore_cmd_Aa, (size_t) sizeof(oncore_cmd_Aa));
3319132451Sroberto		Cmd[-2+4] = tm->tm_hour;
3320132451Sroberto		Cmd[-2+5] = tm->tm_min;
3321132451Sroberto		Cmd[-2+6] = tm->tm_sec;
3322132451Sroberto		oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Aa));
3323132451Sroberto	}
3324132451Sroberto
3325132451Sroberto	record_clock_stats(&(instance->peer->srcadr), "Setting Posn and Time after Loading Almanac");
332682498Sroberto}
332782498Sroberto
332882498Sroberto
332982498Sroberto
3330132451Sroberto/* Almanac data input */
333182498Sroberto
333254359Srobertostatic void
3333132451Srobertooncore_print_Cb(
333454359Sroberto	struct instance *instance,
3335132451Sroberto	u_char *cp
333654359Sroberto	)
333754359Sroberto{
3338132451Sroberto#if 0
3339132451Sroberto	int	ii;
3340132451Sroberto	char	Msg[160];
334154359Sroberto
3342132451Sroberto	printf("DEBUG: See: %c%c%c%c\n", *(cp), *(cp+1), *(cp+2), *(cp+3));
3343132451Sroberto	printf("DEBUG: Cb: [%d,%d]", *(cp+4), *(cp+5));
3344132451Sroberto	for(ii=0; ii<33; ii++)
3345132451Sroberto		printf(" %d", *(cp+ii));
3346132451Sroberto	printf("\n");
334754359Sroberto
3348132451Sroberto	sprintf(Msg, "Debug: Cb: [%d,%d]", *(cp+4), *(cp+5));
3349132451Sroberto	record_clock_stats(&(instance->peer->srcadr), Msg);
3350132451Sroberto#endif
3351132451Sroberto}
335254359Sroberto
3353132451Sroberto
3354132451Sroberto#if 0
3355132451Srobertostatic void
3356132451Srobertooncore_print_array(
3357132451Sroberto	u_char *cp,
3358132451Sroberto	int	n
3359132451Sroberto	)
3360132451Sroberto{
3361132451Sroberto	int	jj, i, j, nn;
3362132451Sroberto
3363132451Sroberto	nn = 0;
3364132451Sroberto	printf("\nTOP\n");
3365132451Sroberto	jj = n/16;
3366132451Sroberto	for (j=0; j<jj; j++) {
3367132451Sroberto		printf("%4d: ", nn);
3368132451Sroberto		nn += 16;
3369132451Sroberto		for (i=0; i<16; i++)
3370132451Sroberto			printf(" %o", *cp++);
3371132451Sroberto		printf("\n");
3372132451Sroberto	}
337382498Sroberto}
3374132451Sroberto#endif
337554359Sroberto
337654359Sroberto
337782498Srobertostatic void
3378132451Srobertooncore_print_posn(
337982498Sroberto	struct instance *instance
338082498Sroberto	)
338182498Sroberto{
338282498Sroberto	char Msg[120], ew, ns;
338382498Sroberto	double xd, xm, xs, yd, ym, ys, hm, hft;
338482498Sroberto	int idx, idy, is, imx, imy;
338582498Sroberto	long lat, lon;
338654359Sroberto
338754359Sroberto	record_clock_stats(&(instance->peer->srcadr), "Posn:");
338854359Sroberto	ew = 'E';
338954359Sroberto	lon = instance->ss_long;
339054359Sroberto	if (lon < 0) {
339154359Sroberto		ew = 'W';
339254359Sroberto		lon = -lon;
339354359Sroberto	}
339454359Sroberto
339554359Sroberto	ns = 'N';
339654359Sroberto	lat = instance->ss_lat;
339754359Sroberto	if (lat < 0) {
339854359Sroberto		ns = 'S';
339954359Sroberto		lat = -lat;
340054359Sroberto	}
340154359Sroberto
340254359Sroberto	hm = instance->ss_ht/100.;
340354359Sroberto	hft= hm/0.3048;
340454359Sroberto
340554359Sroberto	xd = lat/3600000.;	/* lat, lon in int msec arc, ht in cm. */
340654359Sroberto	yd = lon/3600000.;
340782498Sroberto	sprintf(Msg, "Lat = %c %11.7fdeg,    Long = %c %11.7fdeg,    Alt = %5.2fm (%5.2fft) GPS", ns, xd, ew, yd, hm, hft);
340854359Sroberto	record_clock_stats(&(instance->peer->srcadr), Msg);
340954359Sroberto
341054359Sroberto	idx = xd;
341154359Sroberto	idy = yd;
341254359Sroberto	imx = lat%3600000;
341354359Sroberto	imy = lon%3600000;
341454359Sroberto	xm = imx/60000.;
341554359Sroberto	ym = imy/60000.;
3416132451Sroberto	sprintf(Msg,
3417132451Sroberto	    "Lat = %c %3ddeg %7.4fm,   Long = %c %3ddeg %8.5fm,  Alt = %7.2fm (%7.2fft) GPS", ns, idx, xm, ew, idy, ym, hm, hft);
341854359Sroberto	record_clock_stats(&(instance->peer->srcadr), Msg);
341954359Sroberto
342054359Sroberto	imx = xm;
342154359Sroberto	imy = ym;
342254359Sroberto	is  = lat%60000;
342354359Sroberto	xs  = is/1000.;
342454359Sroberto	is  = lon%60000;
342554359Sroberto	ys  = is/1000.;
3426132451Sroberto	sprintf(Msg,
3427132451Sroberto	    "Lat = %c %3ddeg %2dm %5.2fs, Long = %c %3ddeg %2dm %5.2fs, Alt = %7.2fm (%7.2fft) GPS", ns, idx, imx, xs, ew, idy, imy, ys, hm, hft);
342854359Sroberto	record_clock_stats(&(instance->peer->srcadr), Msg);
342956746Sroberto}
343054359Sroberto
343154359Sroberto
343254359Sroberto
343356746Sroberto/*
3434132451Sroberto * write message to Oncore.
343556746Sroberto */
343682498Sroberto
343756746Srobertostatic void
3438132451Srobertooncore_sendmsg(
3439132451Sroberto	int	fd,
3440132451Sroberto	u_char *ptr,
344182498Sroberto	size_t len
344256746Sroberto	)
344356746Sroberto{
3444132451Sroberto	u_char cs = 0;
344556746Sroberto
3446182007Sroberto#ifdef DEBUG
3447132451Sroberto	if (debug > 4)
3448132451Sroberto		printf("ONCORE: Send @@%c%c %d\n", ptr[0], ptr[1], (int) len);
3449182007Sroberto#endif
3450132451Sroberto	write(fd, "@@", (size_t) 2);
3451132451Sroberto	write(fd, ptr, len);
3452132451Sroberto	while (len--)
3453132451Sroberto		cs ^= *ptr++;
3454132451Sroberto	write(fd, &cs, (size_t) 1);
3455132451Sroberto	write(fd, "\r\n", (size_t) 2);
3456132451Sroberto}
345756746Sroberto
345856746Sroberto
345956746Sroberto
3460132451Srobertostatic void
3461132451Srobertooncore_set_posn(
3462132451Sroberto	struct instance *instance
3463132451Sroberto	)
3464132451Sroberto{
3465132451Sroberto	int	mode;
3466182007Sroberto	u_char	  Cmd[20];
3467132451Sroberto
3468132451Sroberto	/* Turn OFF position hold, it needs to be off to set position (for some units),
3469132451Sroberto	   will get set ON in @@Ea later */
3470132451Sroberto
3471132451Sroberto	if (instance->chan == 12)
3472132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* (12) */
3473132451Sroberto	else {
3474132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* (6/8) */
3475132451Sroberto		oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* (6/8) */
3476132451Sroberto	}
3477132451Sroberto
3478132451Sroberto	mode = instance->init_type;
3479132451Sroberto
3480132451Sroberto	if (mode != 0) {	/* first set posn hold position */
3481132451Sroberto		memcpy(Cmd, oncore_cmd_As, (size_t) sizeof(oncore_cmd_As));	/* don't modify static variables */
3482132451Sroberto		w32_buf(&Cmd[-2+4],  (int) instance->ss_lat);
3483132451Sroberto		w32_buf(&Cmd[-2+8],  (int) instance->ss_long);
3484132451Sroberto		w32_buf(&Cmd[-2+12], (int) instance->ss_ht);
3485132451Sroberto		Cmd[-2+16] = 0;
3486132451Sroberto		oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_As));	/* posn hold 3D posn (6/8/12) */
3487132451Sroberto
3488132451Sroberto		memcpy(Cmd, oncore_cmd_Au, (size_t) sizeof(oncore_cmd_Au));
3489132451Sroberto		w32_buf(&Cmd[-2+4], (int) instance->ss_ht);
3490132451Sroberto		Cmd[-2+8] = 0;
3491132451Sroberto		oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Au));	/* altitude hold (6/8/12 not UT, M12T) */
3492132451Sroberto
3493132451Sroberto		/* next set current position */
3494132451Sroberto
3495132451Sroberto		if (instance->chan == 12) {
3496132451Sroberto			memcpy(Cmd, oncore_cmd_Ga, (size_t) sizeof(oncore_cmd_Ga));
3497132451Sroberto			w32_buf(&Cmd[-2+4], (int) instance->ss_lat);
3498132451Sroberto			w32_buf(&Cmd[-2+8], (int) instance->ss_long);
3499132451Sroberto			w32_buf(&Cmd[-2+12],(int) instance->ss_ht);
3500132451Sroberto			Cmd[-2+16] = 0;
3501132451Sroberto			oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Ga));		  /* 3d posn (12) */
3502132451Sroberto		} else {
3503132451Sroberto			memcpy(Cmd, oncore_cmd_Ad, (size_t) sizeof(oncore_cmd_Ad));
3504132451Sroberto			w32_buf(&Cmd[-2+4], (int) instance->ss_lat);
3505132451Sroberto			oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Ad));	/* lat (6/8) */
3506132451Sroberto
3507132451Sroberto			memcpy(Cmd, oncore_cmd_Ae, (size_t) sizeof(oncore_cmd_Ae));
3508132451Sroberto			w32_buf(&Cmd[-2+4], (int) instance->ss_long);
3509132451Sroberto			oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Ae));	/* long (6/8) */
3510132451Sroberto
3511132451Sroberto			memcpy(Cmd, oncore_cmd_Af, (size_t) sizeof(oncore_cmd_Af));
3512132451Sroberto			w32_buf(&Cmd[-2+4], (int) instance->ss_ht);
3513132451Sroberto			Cmd[-2+8] = 0;
3514132451Sroberto			oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Af));	/* ht (6/8) */
3515132451Sroberto		}
3516132451Sroberto
3517132451Sroberto		/* Finally, turn on position hold */
3518132451Sroberto
3519132451Sroberto		if (instance->chan == 12)
3520132451Sroberto			oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1,  sizeof(oncore_cmd_Gd1));
3521132451Sroberto		else
3522132451Sroberto			oncore_sendmsg(instance->ttyfd, oncore_cmd_At1,  sizeof(oncore_cmd_At1));
3523132451Sroberto	}
3524132451Sroberto}
3525132451Sroberto
3526132451Sroberto
3527132451Sroberto
3528132451Srobertostatic void
3529132451Srobertooncore_set_traim(
3530132451Sroberto	struct instance *instance
3531132451Sroberto	)
3532132451Sroberto{
3533132451Sroberto	char	Msg[160];
3534132451Sroberto
3535132451Sroberto	if (instance->traim_in != -1)	/* set in Input */
3536132451Sroberto		instance->traim = instance->traim_in;
3537132451Sroberto	else
3538132451Sroberto		instance->traim = instance->traim_ck;
3539132451Sroberto
3540132451Sroberto	sprintf(Msg, "Input   says TRAIM = %d", instance->traim_in);
354154359Sroberto	record_clock_stats(&(instance->peer->srcadr), Msg);
3542132451Sroberto	sprintf(Msg, "Model # says TRAIM = %d", instance->traim_id);
3543132451Sroberto	record_clock_stats(&(instance->peer->srcadr), Msg);
3544132451Sroberto	sprintf(Msg, "Testing says TRAIM = %d", instance->traim_ck);
3545132451Sroberto	record_clock_stats(&(instance->peer->srcadr), Msg);
3546132451Sroberto	sprintf(Msg, "Using        TRAIM = %d", instance->traim);
3547132451Sroberto	record_clock_stats(&(instance->peer->srcadr), Msg);
3548132451Sroberto
3549132451Sroberto	if (instance->traim_ck == 1 && instance->traim == 0) {
3550132451Sroberto		/* if it should be off, and I turned it on during testing,
3551132451Sroberto		   then turn it off again */
3552132451Sroberto		if (instance->chan == 6)
3553132451Sroberto			oncore_sendmsg(instance->ttyfd, oncore_cmd_Bnx, sizeof(oncore_cmd_Bnx));
3554132451Sroberto		else if (instance->chan == 8)
3555132451Sroberto			oncore_sendmsg(instance->ttyfd, oncore_cmd_Enx, sizeof(oncore_cmd_Enx));
3556132451Sroberto		else	/* chan == 12 */
3557132451Sroberto			oncore_sendmsg(instance->ttyfd, oncore_cmd_Ge0, sizeof(oncore_cmd_Ge0));
3558182007Sroberto			oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
3559132451Sroberto	}
356056746Sroberto}
356154359Sroberto
356256746Sroberto
356356746Sroberto
356456746Sroberto/*
3565132451Sroberto * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn.
356656746Sroberto */
356782498Sroberto
356856746Srobertostatic void
3569132451Srobertooncore_shmem_get_3D(
3570132451Sroberto	struct instance *instance
357156746Sroberto	)
357256746Sroberto{
3573132451Sroberto	if (instance->pp->second%15 == 3) {	/* start the sequence */			/* by changing mode */
3574132451Sroberto		instance->shmem_reset = 1;
3575132451Sroberto		if (instance->chan == 12) {
3576132451Sroberto			if (instance->shmem_Posn == 2)
3577132451Sroberto				oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd2,  sizeof(oncore_cmd_Gd2));  /* 2D */
3578132451Sroberto			else
3579132451Sroberto				oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0,  sizeof(oncore_cmd_Gd0));  /* 3D */
3580132451Sroberto		} else {
3581132451Sroberto			if (instance->saw_At) { 		/* out of 0D -> 3D mode */
3582132451Sroberto				oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0));
3583132451Sroberto				if (instance->shmem_Posn == 2)	/* 3D -> 2D mode */
3584132451Sroberto					oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
3585132451Sroberto			} else
3586132451Sroberto				oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
3587132451Sroberto		}
3588132451Sroberto	} else if (instance->shmem_reset || (instance->mode != MODE_0D)) {
3589132451Sroberto		instance->shmem_reset = 0;
3590132451Sroberto		if (instance->chan == 12)
3591132451Sroberto			oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1,  sizeof(oncore_cmd_Gd1));	/* 0D */
3592132451Sroberto		else {
3593132451Sroberto			if (instance->saw_At) {
3594132451Sroberto				if (instance->mode == MODE_2D)	/* 2D -> 3D or 0D mode */
3595132451Sroberto					oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
3596132451Sroberto				oncore_sendmsg(instance->ttyfd, oncore_cmd_At1,  sizeof(oncore_cmd_At1)); /* to 0D mode */
3597132451Sroberto			} else
3598132451Sroberto				oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1,  sizeof(oncore_cmd_Av1));
3599132451Sroberto		}
3600132451Sroberto	}
3601132451Sroberto}
360256746Sroberto
360356746Sroberto
360456746Sroberto
3605132451Sroberto/*
3606132451Sroberto * Here we do the Software SiteSurvey.
3607132451Sroberto * We have to average our own position for the Position Hold Mode
3608132451Sroberto *   We use Heights from the GPS ellipsoid.
3609132451Sroberto * We check for the END of either HW or SW SiteSurvey.
3610132451Sroberto */
361156746Sroberto
361282498Srobertostatic void
3613132451Srobertooncore_ss(
3614132451Sroberto	struct instance *instance
361582498Sroberto	)
361682498Sroberto{
3617132451Sroberto	char	*cp, Msg[160];
3618132451Sroberto	double	lat, lon, ht;
361982498Sroberto
3620132451Sroberto
3621132451Sroberto	if (instance->site_survey == ONCORE_SS_HW) {
3622132451Sroberto		/*
3623132451Sroberto		 * Check to see if Hardware SiteSurvey has Finished.
3624132451Sroberto		 */
3625132451Sroberto
3626132451Sroberto		if ((instance->chan == 8  && !(instance->BEHa[37]  & 0x20)) ||
3627132451Sroberto		    (instance->chan == 12 && !(instance->BEHa[130] & 0x10))) {
3628132451Sroberto			record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
3629132451Sroberto
3630132451Sroberto			if (instance->chan == 12)
3631132451Sroberto				oncore_sendmsg(instance->ttyfd, oncore_cmd_Gax, sizeof(oncore_cmd_Gax));
3632132451Sroberto			else
3633132451Sroberto				oncore_sendmsg(instance->ttyfd, oncore_cmd_Asx, sizeof(oncore_cmd_Asx));
3634132451Sroberto
3635132451Sroberto			cp = "SSstate = ONCORE_SS_DONE";
3636132451Sroberto			record_clock_stats(&(instance->peer->srcadr), cp);
3637132451Sroberto			instance->site_survey = ONCORE_SS_DONE;
3638132451Sroberto		}
3639132451Sroberto	} else {
3640132451Sroberto		/*
3641132451Sroberto		 * Must be a Software Site Survey.
3642132451Sroberto		 */
3643132451Sroberto
3644132451Sroberto		if (instance->rsm.bad_fix)	/* Not if poor geometry or less than 3 sats */
3645132451Sroberto			return;
3646132451Sroberto
3647132451Sroberto		if (instance->mode != MODE_3D)	/* Use only 3D Fixes */
3648132451Sroberto			return;
3649132451Sroberto
3650132451Sroberto		instance->ss_lat  += buf_w32(&instance->BEHa[15]);
3651132451Sroberto		instance->ss_long += buf_w32(&instance->BEHa[19]);
3652132451Sroberto		instance->ss_ht   += buf_w32(&instance->BEHa[23]);  /* GPS ellipsoid */
3653132451Sroberto		instance->ss_count++;
3654132451Sroberto
3655132451Sroberto		if (instance->ss_count != POS_HOLD_AVERAGE)
3656132451Sroberto			return;
3657132451Sroberto
3658132451Sroberto		instance->ss_lat  /= POS_HOLD_AVERAGE;
3659132451Sroberto		instance->ss_long /= POS_HOLD_AVERAGE;
3660132451Sroberto		instance->ss_ht   /= POS_HOLD_AVERAGE;
3661132451Sroberto
3662132451Sroberto		sprintf(Msg, "Surveyed posn: lat %.3f (mas) long %.3f (mas) ht %.3f (cm)",
3663132451Sroberto			instance->ss_lat, instance->ss_long, instance->ss_ht);
3664132451Sroberto		record_clock_stats(&(instance->peer->srcadr), Msg);
3665132451Sroberto		lat = instance->ss_lat/3600000.;
3666132451Sroberto		lon = instance->ss_long/3600000.;
3667132451Sroberto		ht  = instance->ss_ht/100;
3668132451Sroberto		sprintf(Msg, "Surveyed posn: lat %.7f (deg) long %.7f (deg) ht %.2f (m)",
3669132451Sroberto			lat, lon, ht);
3670132451Sroberto		record_clock_stats(&(instance->peer->srcadr), Msg);
3671132451Sroberto
3672132451Sroberto		oncore_set_posn(instance);
3673132451Sroberto
3674132451Sroberto		record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
3675132451Sroberto
3676132451Sroberto		cp = "SSstate = ONCORE_SS_DONE";
367782498Sroberto		record_clock_stats(&(instance->peer->srcadr), cp);
3678132451Sroberto		instance->site_survey = ONCORE_SS_DONE;
367982498Sroberto	}
368082498Sroberto}
368182498Sroberto
3682132451Sroberto
3683132451Sroberto
3684132451Srobertostatic int
3685132451Srobertooncore_wait_almanac(
3686132451Sroberto	struct instance *instance
3687132451Sroberto	)
3688132451Sroberto{
3689132451Sroberto	if (instance->rsm.bad_almanac) {
3690182007Sroberto#ifdef DEBUG
3691132451Sroberto		if (debug)
3692132451Sroberto			printf("ONCORE[%d]: waiting for almanac\n", instance->unit);
3693182007Sroberto#endif
3694132451Sroberto
3695132451Sroberto		/*
3696132451Sroberto		 * If we get here (first time) then we don't have an almanac in memory.
3697132451Sroberto		 * Check if we have a SHMEM, and if so try to load whatever is there.
3698132451Sroberto		 */
3699132451Sroberto
3700132451Sroberto		if (!instance->almanac_from_shmem) {
3701132451Sroberto			instance->almanac_from_shmem = 1;
3702132451Sroberto			oncore_load_almanac(instance);
3703132451Sroberto		}
3704132451Sroberto		return(1);
3705132451Sroberto	} else {  /* Here we have the Almanac, we will be starting the @@Bn/@@En/@@Hn
3706132451Sroberto		     commands, and can finally check for TRAIM.  Again, we set a delay
3707132451Sroberto		     (5sec) and wait for things to settle down */
3708132451Sroberto
3709132451Sroberto		if (instance->chan == 6)
3710132451Sroberto			oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn, sizeof(oncore_cmd_Bn));
3711132451Sroberto		else if (instance->chan == 8)
3712132451Sroberto			oncore_sendmsg(instance->ttyfd, oncore_cmd_En, sizeof(oncore_cmd_En));
3713132451Sroberto		else if (instance->chan == 12) {
3714132451Sroberto			oncore_sendmsg(instance->ttyfd, oncore_cmd_Gc, sizeof(oncore_cmd_Gc));	/* 1PPS on, continuous */
3715132451Sroberto			oncore_sendmsg(instance->ttyfd, oncore_cmd_Ge, sizeof(oncore_cmd_Ge));	/* TRAIM on */
3716132451Sroberto			oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn, sizeof(oncore_cmd_Hn));	/* TRAIM status 1/s */
3717132451Sroberto		}
3718132451Sroberto		instance->traim_delay = 1;
3719132451Sroberto
3720132451Sroberto		record_clock_stats(&(instance->peer->srcadr), "Have now loaded an ALMANAC");
3721132451Sroberto
3722132451Sroberto		instance->o_state = ONCORE_RUN;
3723132451Sroberto		record_clock_stats(&(instance->peer->srcadr), "state = ONCORE_RUN");
3724132451Sroberto	}
3725132451Sroberto	return(0);
3726132451Sroberto}
3727132451Sroberto
3728132451Sroberto
3729132451Sroberto
373054359Sroberto#else
373154359Srobertoint refclock_oncore_bs;
373254359Sroberto#endif /* REFCLOCK */
3733