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