PageRenderTime 112ms CodeModel.GetById 23ms app.highlight 72ms RepoModel.GetById 2ms app.codeStats 0ms

/contrib/ntp/ntpd/refclock_oncore.c

https://bitbucket.org/freebsd/freebsd-head/
C | 3732 lines | 2485 code | 595 blank | 652 comment | 703 complexity | c5431bce34bce5c87b214f45f81694fc MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*
   2 * ----------------------------------------------------------------------------
   3 * "THE BEER-WARE LICENSE" (Revision 42):
   4 * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
   5 * can do whatever you want with this stuff. If we meet some day, and you think
   6 * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
   7 * ----------------------------------------------------------------------------
   8 *
   9 * refclock_oncore.c
  10 *
  11 * Driver for some of the various the Motorola Oncore GPS receivers.
  12 *   should work with Basic, PVT6, VP, UT, UT+, GT, GT+, SL, M12, M12+T
  13 *	The receivers with TRAIM (VP, UT, UT+, M12+T), will be more accurate
  14 *	than the others.
  15 *	The receivers without position hold (GT, GT+) will be less accurate.
  16 *
  17 * Tested with:
  18 *
  19 *		(UT)				   (VP)
  20 *   COPYRIGHT 1991-1997 MOTOROLA INC.	COPYRIGHT 1991-1996 MOTOROLA INC.
  21 *   SFTW P/N #     98-P36848P		SFTW P/N # 98-P36830P
  22 *   SOFTWARE VER # 2			SOFTWARE VER # 8
  23 *   SOFTWARE REV # 2			SOFTWARE REV # 8
  24 *   SOFTWARE DATE  APR 24 1998 	SOFTWARE DATE  06 Aug 1996
  25 *   MODEL #	R1121N1114		MODEL #    B4121P1155
  26 *   HWDR P/N # 1			HDWR P/N # _
  27 *   SERIAL #	R0010A			SERIAL #   SSG0226478
  28 *   MANUFACTUR DATE 6H07		MANUFACTUR DATE 7E02
  29 *					OPTIONS LIST	IB
  30 *
  31 *	      (Basic)				   (M12)
  32 *   COPYRIGHT 1991-1994 MOTOROLA INC.	COPYRIGHT 1991-2000 MOTOROLA INC.
  33 *   SFTW P/N # 98-P39949M		SFTW P/N # 61-G10002A
  34 *   SOFTWARE VER # 5			SOFTWARE VER # 1
  35 *   SOFTWARE REV # 0			SOFTWARE REV # 3
  36 *   SOFTWARE DATE  20 JAN 1994 	SOFTWARE DATE  Mar 13 2000
  37 *   MODEL #	A11121P116		MODEL #    P143T12NR1
  38 *   HDWR P/N # _			HWDR P/N # 1
  39 *   SERIAL #	SSG0049809		SERIAL #   P003UD
  40 *   MANUFACTUR DATE 417AMA199		MANUFACTUR DATE 0C27
  41 *   OPTIONS LIST    AB
  42 *
  43 *	      (M12+T)				  (M12+T later version)
  44 *   COPYRIGHT 1991-2002 MOTOROLA INC.	COPYRIGHT 1991-2003 MOTOROLA INC.
  45 *   SFTW P/N #     61-G10268A		SFTW P/N #     61-G10268A
  46 *   SOFTWARE VER # 2			SOFTWARE VER # 2
  47 *   SOFTWARE REV # 0			SOFTWARE REV # 1
  48 *   SOFTWARE DATE  AUG 14 2002 	SOFTWARE DATE  APR 16 2003
  49 *   MODEL #	P283T12T11		MODEL #    P273T12T12
  50 *   HWDR P/N # 2			HWDR P/N # 2
  51 *   SERIAL #	P04DC2			SERIAL #   P05Z7Z
  52 *   MANUFACTUR DATE 2J17		MANUFACTUR DATE 3G15
  53 *
  54 * --------------------------------------------------------------------------
  55 * Reg Clemens (Feb 2006)
  56 * Fix some gcc4 compiler complaints
  57 * Fix possible segfault in oncore_init_shmem
  58 * change all (possible) fprintf(stderr, to record_clock_stats
  59 * Apply patch from Russell J. Yount <rjy@cmu.edu> Fixed (new) MT12+T UTC not correct
  60 *   immediately after new Almanac Read.
  61 * Apply patch for new PPS implementation by Rodolfo Giometti <giometti@linux.it>
  62 *   now code can use old Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de> or
  63 *   the new one.  Compiles depending on timepps.h seen.
  64 * --------------------------------------------------------------------------
  65 * Luis Batanero Guerrero <luisba@rao.es> (Dec 2005) Patch for leap seconds
  66 * (the oncore driver was setting the wrong ntpd variable)
  67 * --------------------------------------------------------------------------
  68 * Reg.Clemens (Mar 2004)
  69 * Support for interfaces other than PPSAPI removed, for Solaris, SunOS,
  70 * SCO, you now need to use one of the timepps.h files in the root dir.
  71 * this driver will 'grab' it for you if you dont have one in /usr/include
  72 * --------------------------------------------------------------------------
  73 * This code uses the two devices
  74 *	/dev/oncore.serial.n
  75 *	/dev/oncore.pps.n
  76 * which may be linked to the same device.
  77 * and can read initialization data from the file
  78 *	/etc/ntp.oncoreN, /etc/ntp.oncore.N, or /etc/ntp.oncore, where
  79 *	n or N are the unit number, viz 127.127.30.N.
  80 * --------------------------------------------------------------------------
  81 * Reg.Clemens <reg@dwf.com> Sep98.
  82 *  Original code written for FreeBSD.
  83 *  With these mods it works on FreeBSD, SunOS, Solaris and Linux
  84 *    (SunOS 4.1.3 + ppsclock)
  85 *    (Solaris7 + MU4)
  86 *    (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + or later).
  87 *
  88 *  Lat,Long,Ht, cable-delay, offset, and the ReceiverID (along with the
  89 *  state machine state) are printed to CLOCKSTATS if that file is enabled
  90 *  in /etc/ntp.conf.
  91 *
  92 * --------------------------------------------------------------------------
  93 *
  94 * According to the ONCORE manual (TRM0003, Rev 3.2, June 1998, page 3.13)
  95 * doing an average of 10000 valid 2D and 3D fixes is what the automatic
  96 * site survey mode does.  Looking at the output from the receiver
  97 * it seems like it is only using 3D fixes.
  98 * When we do it ourselves, take 10000 3D fixes.
  99 */
 100
 101#define POS_HOLD_AVERAGE	10000	/* nb, 10000s ~= 2h45m */
 102
 103/*
 104 * ONCORE_SHMEM_STATUS will create a mmap(2)'ed file named according to a
 105 * "STATUS" line in the oncore config file, which contains the most recent
 106 * copy of all types of messages we recognize.	This file can be mmap(2)'ed
 107 * by monitoring and statistics programs.
 108 *
 109 * See separate HTML documentation for this option.
 110 */
 111
 112#ifdef HAVE_CONFIG_H
 113#include <config.h>
 114#endif
 115
 116#if defined(REFCLOCK) && defined(CLOCK_ONCORE)
 117
 118#include "ntpd.h"
 119#include "ntp_io.h"
 120#include "ntp_unixtime.h"
 121#include "ntp_refclock.h"
 122#include "ntp_stdlib.h"
 123
 124#include <stdio.h>
 125#include <ctype.h>
 126#include <sys/stat.h>
 127#ifdef ONCORE_SHMEM_STATUS
 128# ifdef HAVE_SYS_MMAN_H
 129#  include <sys/mman.h>
 130#  ifndef MAP_FAILED
 131#   define MAP_FAILED ((u_char *) -1)
 132#  endif  /* MAP_FAILED */
 133# endif /* HAVE_SYS_MMAN_H */
 134#endif /* ONCORE_SHMEM_STATUS */
 135
 136#ifdef HAVE_PPSAPI
 137# include "ppsapi_timepps.h"
 138#endif
 139
 140#ifdef HAVE_SYS_SIO_H
 141# include <sys/sio.h>
 142#endif
 143
 144enum receive_state {
 145	ONCORE_NO_IDEA,
 146	ONCORE_CHECK_ID,
 147	ONCORE_CHECK_CHAN,
 148	ONCORE_HAVE_CHAN,
 149	ONCORE_RESET_SENT,
 150	ONCORE_TEST_SENT,
 151	ONCORE_INIT,
 152	ONCORE_ALMANAC,
 153	ONCORE_RUN
 154};
 155
 156enum site_survey_state {
 157	ONCORE_SS_UNKNOWN,
 158	ONCORE_SS_TESTING,
 159	ONCORE_SS_HW,
 160	ONCORE_SS_SW,
 161	ONCORE_SS_DONE
 162};
 163
 164enum antenna_state {
 165      ONCORE_ANTENNA_UNKNOWN = -1,
 166      ONCORE_ANTENNA_OK      =	0,
 167      ONCORE_ANTENNA_OC      =	1,
 168      ONCORE_ANTENNA_UC      =	2,
 169      ONCORE_ANTENNA_NV      =	3
 170};
 171
 172/* Model Name, derived from the @@Cj message.
 173 * Used to initialize some variables.
 174 */
 175
 176enum oncore_model {
 177	ONCORE_BASIC,
 178	ONCORE_PVT6,
 179	ONCORE_VP,
 180	ONCORE_UT,
 181	ONCORE_UTPLUS,
 182	ONCORE_GT,
 183	ONCORE_GTPLUS,
 184	ONCORE_SL,
 185	ONCORE_M12,
 186	ONCORE_UNKNOWN
 187};
 188
 189/* the bits that describe these properties are in the same place
 190 * on the VP/UT, but have moved on the M12.  As such we extract
 191 * them, and use them from this struct.
 192 *
 193 */
 194
 195struct RSM {
 196	u_char	posn0D;
 197	u_char	posn2D;
 198	u_char	posn3D;
 199	u_char	bad_almanac;
 200	u_char	bad_fix;
 201};
 202
 203/* It is possible to test the VP/UT each cycle (@@Ea or equivalent) to
 204 * see what mode it is in.  The bits on the M12 are multiplexed with
 205 * other messages, so we have to 'keep' the last known mode here.
 206 */
 207
 208enum posn_mode {
 209	MODE_UNKNOWN,
 210	MODE_0D,
 211	MODE_2D,
 212	MODE_3D
 213};
 214
 215struct instance {
 216	int	unit;		/* 127.127.30.unit */
 217	struct	refclockproc *pp;
 218	struct	peer *peer;
 219
 220	int	ttyfd;		/* TTY file descriptor */
 221	int	ppsfd;		/* PPS file descriptor */
 222	int	shmemfd;	/* Status shm descriptor */
 223	pps_handle_t pps_h;
 224	pps_params_t pps_p;
 225	enum receive_state o_state;		/* Receive state */
 226	enum posn_mode mode;			/* 0D, 2D, 3D */
 227	enum site_survey_state site_survey;	/* Site Survey state */
 228	enum antenna_state ant_state;		/* antenna state */
 229
 230	int	Bj_day;
 231
 232	u_long	delay;		/* ns */
 233	long	offset; 	/* ns */
 234
 235	u_char	*shmem;
 236	char	*shmem_fname;
 237	u_int	shmem_Cb;
 238	u_int	shmem_Ba;
 239	u_int	shmem_Ea;
 240	u_int	shmem_Ha;
 241	u_char	shmem_reset;
 242	u_char	shmem_Posn;
 243	u_char	shmem_bad_Ea;
 244	u_char	almanac_from_shmem;
 245
 246	double	ss_lat;
 247	double	ss_long;
 248	double	ss_ht;
 249	double	dH;
 250	int	ss_count;
 251	u_char	posn_set;
 252
 253	enum oncore_model model;
 254	u_int	version;
 255	u_int	revision;
 256
 257	u_char	chan;		/* 6 for PVT6 or BASIC, 8 for UT/VP, 12 for m12, 0 if unknown */
 258	s_char	traim;		/* do we have traim? yes UT/VP, M12+T, no BASIC, GT, M12, -1 unknown, 0 no, +1 yes */
 259				/* the following 7 are all timing counters */
 260	u_char	traim_delay;	/* seconds counter, waiting for reply */
 261	u_char	count;		/* cycles thru Ea before starting */
 262	u_char	count1; 	/* cycles thru Ea after SS_TESTING, waiting for SS_HW */
 263	u_char	count2; 	/* cycles thru Ea after count, to check for @@Ea */
 264	u_char	count3; 	/* cycles thru Ea checking for # channels */
 265	u_char	count4; 	/* cycles thru leap after Gj to issue Bj */
 266	u_char	count5; 	/* cycles thru get_timestamp waiting for valid UTC correction */
 267	u_char	count5_set;	/* only set count5 once */
 268	u_char	pollcnt;
 269	u_char	timeout;	/* count to retry Cj after Fa self-test */
 270
 271	struct	RSM rsm;	/* bits extracted from Receiver Status Msg in @@Ea */
 272	u_char	printed;
 273	u_char	polled;
 274	u_long	ev_serial;
 275	int	Rcvptr;
 276	u_char	Rcvbuf[500];
 277	u_char	BEHa[160];	/* Ba, Ea or Ha */
 278	u_char	BEHn[80];	/* Bn , En , or Hn */
 279	u_char	Cj[300];
 280	u_char	Ag;		/* Satellite mask angle */
 281	u_char	saw_At;
 282	u_char	saw_Ay;
 283	u_char	saw_Az;
 284	s_char	saw_Gj;
 285	u_char	have_dH;
 286	u_char	init_type;
 287	s_char	saw_tooth;
 288	s_char	chan_in;	/* chan number from INPUT, will always use it */
 289	u_char	chan_id;	/* chan number determined from part number */
 290	u_char	chan_ck;	/* chan number determined by sending commands to hardware */
 291	s_char	traim_in;	/* TRAIM from INPUT, will always use ON/OFF specified */
 292	s_char	traim_id;	/* TRAIM determined from part number */
 293	u_char	traim_ck;	/* TRAIM determined by sending commands to hardware */
 294	u_char	once;		/* one pass code at top of BaEaHa */
 295	s_char	assert;
 296	u_char	hardpps;
 297};
 298
 299#define rcvbuf	instance->Rcvbuf
 300#define rcvptr	instance->Rcvptr
 301
 302static	int	oncore_start	      P((int, struct peer *));
 303static	void	oncore_poll	      P((int, struct peer *));
 304static	void	oncore_shutdown       P((int, struct peer *));
 305static	void	oncore_consume	      P((struct instance *));
 306static	void	oncore_read_config    P((struct instance *));
 307static	void	oncore_receive	      P((struct recvbuf *));
 308static	int	oncore_ppsapi	      P((struct instance *));
 309static	void	oncore_get_timestamp  P((struct instance *, long, long));
 310static	void	oncore_init_shmem     P((struct instance *));
 311
 312static	void	oncore_antenna_report P((struct instance *, enum antenna_state));
 313static	void	oncore_chan_test      P((struct instance *));
 314static	void	oncore_check_almanac  P((struct instance *));
 315static	void	oncore_check_antenna  P((struct instance *));
 316static	void	oncore_check_leap_sec P((struct instance *));
 317static	int	oncore_checksum_ok    P((u_char *, int));
 318static	void	oncore_compute_dH     P((struct instance *));
 319static	void	oncore_load_almanac   P((struct instance *));
 320static	void	oncore_print_Cb       P((struct instance *, u_char *));
 321/* static  void    oncore_print_array	 P((u_char *, int));	*/
 322static	void	oncore_print_posn     P((struct instance *));
 323static	void	oncore_sendmsg	      P((int, u_char *, size_t));
 324static	void	oncore_set_posn       P((struct instance *));
 325static	void	oncore_set_traim      P((struct instance *));
 326static	void	oncore_shmem_get_3D   P((struct instance *));
 327static	void	oncore_ss	      P((struct instance *));
 328static	int	oncore_wait_almanac   P((struct instance *));
 329
 330static	void	oncore_msg_any	   P((struct instance *, u_char *, size_t, int));
 331static	void	oncore_msg_Adef    P((struct instance *, u_char *, size_t));
 332static	void	oncore_msg_Ag	   P((struct instance *, u_char *, size_t));
 333static	void	oncore_msg_As	   P((struct instance *, u_char *, size_t));
 334static	void	oncore_msg_At	   P((struct instance *, u_char *, size_t));
 335static	void	oncore_msg_Ay	   P((struct instance *, u_char *, size_t));
 336static	void	oncore_msg_Az	   P((struct instance *, u_char *, size_t));
 337static	void	oncore_msg_BaEaHa  P((struct instance *, u_char *, size_t));
 338static	void	oncore_msg_Bd	   P((struct instance *, u_char *, size_t));
 339static	void	oncore_msg_Bj	   P((struct instance *, u_char *, size_t));
 340static	void	oncore_msg_BnEnHn  P((struct instance *, u_char *, size_t));
 341static	void	oncore_msg_CaFaIa  P((struct instance *, u_char *, size_t));
 342static	void	oncore_msg_Cb	   P((struct instance *, u_char *, size_t));
 343static	void	oncore_msg_Cf	   P((struct instance *, u_char *, size_t));
 344static	void	oncore_msg_Cj	   P((struct instance *, u_char *, size_t));
 345static	void	oncore_msg_Cj_id   P((struct instance *, u_char *, size_t));
 346static	void	oncore_msg_Cj_init P((struct instance *, u_char *, size_t));
 347static	void	oncore_msg_Ga	   P((struct instance *, u_char *, size_t));
 348static	void	oncore_msg_Gb	   P((struct instance *, u_char *, size_t));
 349static	void	oncore_msg_Gj	   P((struct instance *, u_char *, size_t));
 350static	void	oncore_msg_Sz	   P((struct instance *, u_char *, size_t));
 351
 352struct	refclock refclock_oncore = {
 353	oncore_start,		/* start up driver */
 354	oncore_shutdown,	/* shut down driver */
 355	oncore_poll,		/* transmit poll message */
 356	noentry,		/* not used */
 357	noentry,		/* not used */
 358	noentry,		/* not used */
 359	NOFLAGS 		/* not used */
 360};
 361
 362/*
 363 * Understanding the next bit here is not easy unless you have a manual
 364 * for the the various Oncore Models.
 365 */
 366
 367static struct msg_desc {
 368	const char	flag[3];
 369	const int	len;
 370	void		(*handler) P((struct instance *, u_char *, size_t));
 371	const char	*fmt;
 372	int		shmem;
 373} oncore_messages[] = {
 374			/* Ea and En first since they're most common */
 375	{ "Ea",  76,    oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" },
 376	{ "Ba",  68,    oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC" },
 377	{ "Ha", 154,    oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC" },
 378	{ "Bn",  59,    oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC" },
 379	{ "En",  69,    oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" },
 380	{ "Hn",  78,    oncore_msg_BnEnHn, "" },
 381	{ "Ab",  10,    0,                 "" },
 382	{ "Ac",  11,    0,                 "" },
 383	{ "Ad",  11,    oncore_msg_Adef,   "" },
 384	{ "Ae",  11,    oncore_msg_Adef,   "" },
 385	{ "Af",  15,    oncore_msg_Adef,   "" },
 386	{ "Ag",   8,    oncore_msg_Ag,     "" }, /* Satellite mask angle */
 387	{ "As",  20,    oncore_msg_As,     "" },
 388	{ "At",   8,    oncore_msg_At,     "" },
 389	{ "Au",  12,    0,                 "" },
 390	{ "Av",   8,    0,                 "" },
 391	{ "Aw",   8,    0,                 "" },
 392	{ "Ay",  11,    oncore_msg_Ay,     "" },
 393	{ "Az",  11,    oncore_msg_Az,     "" },
 394	{ "AB",   8,    0,                 "" },
 395	{ "Bb",  92,    0,                 "" },
 396	{ "Bd",  23,    oncore_msg_Bd,     "" },
 397	{ "Bj",   8,    oncore_msg_Bj,     "" },
 398	{ "Ca",   9,    oncore_msg_CaFaIa, "" },
 399	{ "Cb",  33,    oncore_msg_Cb,     "" },
 400	{ "Cf",   7,    oncore_msg_Cf,     "" },
 401	{ "Cg",   8,    0,                 "" },
 402	{ "Ch",   9,    0,                 "" },
 403	{ "Cj", 294,    oncore_msg_Cj,     "" },
 404	{ "Ek",  71,    0,                 "" },
 405	{ "Fa",   9,    oncore_msg_CaFaIa, "" },
 406	{ "Ga",  20,    oncore_msg_Ga,     "" },
 407	{ "Gb",  17,    oncore_msg_Gb,     "" },
 408	{ "Gc",   8,    0,                 "" },
 409	{ "Gd",   8,    0,                 "" },
 410	{ "Ge",   8,    0,                 "" },
 411	{ "Gj",  21,    oncore_msg_Gj,     "" },
 412	{ "Ia",  10,    oncore_msg_CaFaIa, "" },
 413	{ "Sz",   8,    oncore_msg_Sz,     "" },
 414	{ {0},	  7,	0,		   "" }
 415};
 416
 417
 418static u_char oncore_cmd_Aa[]  = { 'A', 'a', 0, 0, 0 }; 			    /* 6/8	Time of Day				*/
 419static u_char oncore_cmd_Ab[]  = { 'A', 'b', 0, 0, 0 }; 			    /* 6/8	GMT Correction				*/
 420static u_char oncore_cmd_AB[]  = { 'A', 'B', 4 };				    /* VP	Application Type: Static		*/
 421static u_char oncore_cmd_Ac[]  = { 'A', 'c', 0, 0, 0, 0 };			    /* 6/8	Date					*/
 422static u_char oncore_cmd_Ad[]  = { 'A', 'd', 0,0,0,0 }; 			    /* 6/8	Latitude				*/
 423static u_char oncore_cmd_Ae[]  = { 'A', 'e', 0,0,0,0 }; 			    /* 6/8	Longitude				*/
 424static u_char oncore_cmd_Af[]  = { 'A', 'f', 0,0,0,0, 0 };			    /* 6/8	Height					*/
 425static u_char oncore_cmd_Ag[]  = { 'A', 'g', 0 };				    /* 6/8/12	Satellite Mask Angle			*/
 426static u_char oncore_cmd_Agx[] = { 'A', 'g', 0xff };				    /* 6/8/12	Satellite Mask Angle: read		*/
 427static u_char oncore_cmd_As[]  = { 'A', 's', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 };	    /* 6/8/12	Posn Hold Parameters			*/
 428static u_char oncore_cmd_Asx[] = { 'A', 's', 0x7f,0xff,0xff,0xff,		    /* 6/8/12	Posn Hold Readback			*/
 429					     0x7f,0xff,0xff,0xff,		    /*		 on UT+ this doesnt work with 0xff	*/
 430					     0x7f,0xff,0xff,0xff, 0xff };	    /*		 but does work with 0x7f (sigh).	*/
 431static u_char oncore_cmd_At0[] = { 'A', 't', 0 };				    /* 6/8	Posn Hold: off				*/
 432static u_char oncore_cmd_At1[] = { 'A', 't', 1 };				    /* 6/8	Posn Hold: on				*/
 433static u_char oncore_cmd_At2[] = { 'A', 't', 2 };				    /* 6/8	Posn Hold: Start Site Survey		*/
 434static u_char oncore_cmd_Atx[] = { 'A', 't', 0xff };				    /* 6/8	Posn Hold: Read Back			*/
 435static u_char oncore_cmd_Au[]  = { 'A', 'u', 0,0,0,0, 0 };			    /* GT/M12	Altitude Hold Ht.			*/
 436static u_char oncore_cmd_Av0[] = { 'A', 'v', 0 };				    /* VP/GT	Altitude Hold: off			*/
 437static u_char oncore_cmd_Av1[] = { 'A', 'v', 1 };				    /* VP/GT	Altitude Hold: on			*/
 438static u_char oncore_cmd_Aw[]  = { 'A', 'w', 1 };				    /* 6/8/12	UTC/GPS time selection			*/
 439static u_char oncore_cmd_Ay[]  = { 'A', 'y', 0, 0, 0, 0 };			    /* Timing	1PPS time offset: set			*/
 440static u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff };		    /* Timing	1PPS time offset: Read			*/
 441static u_char oncore_cmd_Az[]  = { 'A', 'z', 0, 0, 0, 0 };			    /* 6/8UT/12 1PPS Cable Delay: set			*/
 442static u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff };		    /* 6/8UT/12 1PPS Cable Delay: Read			*/
 443static u_char oncore_cmd_Ba0[] = { 'B', 'a', 0 };				    /* 6	Position/Data/Status: off		*/
 444static u_char oncore_cmd_Ba[]  = { 'B', 'a', 1 };				    /* 6	Position/Data/Status: on		*/
 445static u_char oncore_cmd_Bb[]  = { 'B', 'b', 1 };				    /* 6/8/12	Visible Satellites			*/
 446static u_char oncore_cmd_Bd[]  = { 'B', 'd', 1 };				    /* 6/8/12?	Almanac Status Msg.			*/
 447static u_char oncore_cmd_Be[]  = { 'B', 'e', 1 };				    /* 6/8/12	Request Almanac Data			*/
 448static u_char oncore_cmd_Bj[]  = { 'B', 'j', 0 };				    /* 6/8	Leap Second Pending			*/
 449static u_char oncore_cmd_Bn0[] = { 'B', 'n', 0, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6	TRAIM setup/status: msg off, traim on	*/
 450static u_char oncore_cmd_Bn[]  = { 'B', 'n', 1, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6	TRAIM setup/status: msg on,  traim on	*/
 451static u_char oncore_cmd_Bnx[] = { 'B', 'n', 0, 0, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6	TRAIM setup/status: msg off, traim off	*/
 452static u_char oncore_cmd_Ca[]  = { 'C', 'a' };					    /* 6	Self Test				*/
 453static u_char oncore_cmd_Cf[]  = { 'C', 'f' };					    /* 6/8/12	Set to Defaults 			*/
 454static u_char oncore_cmd_Cg[]  = { 'C', 'g', 1 };				    /* VP	Posn Fix/Idle Mode			*/
 455static u_char oncore_cmd_Cj[]  = { 'C', 'j' };					    /* 6/8/12	Receiver ID				*/
 456static u_char oncore_cmd_Ea0[] = { 'E', 'a', 0 };				    /* 8	Position/Data/Status: off		*/
 457static u_char oncore_cmd_Ea[]  = { 'E', 'a', 1 };				    /* 8	Position/Data/Status: on		*/
 458static u_char oncore_cmd_Ek[]  = { 'E', 'k', 0 }; /* just turn off */		    /* 8	Posn/Status/Data - extension		*/
 459static u_char oncore_cmd_En0[] = { 'E', 'n', 0, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT	TRAIM setup/status: msg off, traim on	*/
 460static u_char oncore_cmd_En[]  = { 'E', 'n', 1, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT	TRAIM setup/status: msg on,  traim on	*/
 461static u_char oncore_cmd_Enx[] = { 'E', 'n', 0, 0, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT	TRAIM setup/status: msg off, traim off	*/
 462static u_char oncore_cmd_Fa[]  = { 'F', 'a' };					    /* 8	Self Test				*/
 463static u_char oncore_cmd_Ga[]  = { 'G', 'a', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 };	    /* 12	Position Set				*/
 464static u_char oncore_cmd_Gax[] = { 'G', 'a', 0xff, 0xff, 0xff, 0xff,		    /* 12	Position Set: Read			*/
 465					     0xff, 0xff, 0xff, 0xff,		    /*							*/
 466					     0xff, 0xff, 0xff, 0xff, 0xff };	    /*							*/
 467static u_char oncore_cmd_Gb[]  = { 'G', 'b', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };	    /* 12	set Date/Time				*/
 468static u_char oncore_cmd_Gc[]  = { 'G', 'c', 1 };				    /* 12	PPS Control: On Cont			*/
 469static u_char oncore_cmd_Gd0[] = { 'G', 'd', 0 };				    /* 12	Position Control: 3D (no hold)		*/
 470static u_char oncore_cmd_Gd1[] = { 'G', 'd', 1 };				    /* 12	Position Control: 0D (3D hold)		*/
 471static u_char oncore_cmd_Gd2[] = { 'G', 'd', 2 };				    /* 12	Position Control: 2D (Alt Hold) 	*/
 472static u_char oncore_cmd_Gd3[] = { 'G', 'd', 3 };				    /* 12	Position Coltrol: Start Site Survey	*/
 473static u_char oncore_cmd_Ge0[] = { 'G', 'e', 0 };				    /* M12+T	TRAIM: off				*/
 474static u_char oncore_cmd_Ge[]  = { 'G', 'e', 1 };				    /* M12+T	TRAIM: on				*/
 475static u_char oncore_cmd_Gj[]  = { 'G', 'j' };					    /* 8?/12	Leap Second Pending			*/
 476static u_char oncore_cmd_Ha0[] = { 'H', 'a', 0 };				    /* 12	Position/Data/Status: off		*/
 477static u_char oncore_cmd_Ha[]  = { 'H', 'a', 1 };				    /* 12	Position/Data/Status: on		*/
 478static u_char oncore_cmd_Hn0[] = { 'H', 'n', 0 };				    /* 12	TRAIM Status: off			*/
 479static u_char oncore_cmd_Hn[]  = { 'H', 'n', 1 };				    /* 12	TRAIM Status: on			*/
 480static u_char oncore_cmd_Ia[]  = { 'I', 'a' };					    /* 12	Self Test				*/
 481
 482/* it appears that as of 1997/1998, the UT had As,At, but not Au,Av
 483 *				    the GT had Au,Av, but not As,At
 484 * This was as of v2.0 of both firmware sets. possibly 1.3 for UT.
 485 * Bj in UT at v1.3
 486 * dont see Bd in UT/GT thru 1999
 487 * Gj in UT as of 3.0, 1999 , Bj as of 1.3
 488 */
 489
 490static char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jly",
 491	"Aug", "Sep", "Oct", "Nov", "Dec" };
 492
 493#define DEVICE1 	"/dev/oncore.serial.%d" /* name of serial device */
 494#define DEVICE2 	"/dev/oncore.pps.%d"    /* name of pps device */
 495
 496#define SPEED		B9600		/* Oncore Binary speed (9600 bps) */
 497
 498/*
 499 * Assemble and disassemble 32bit signed quantities from a buffer.
 500 *
 501 */
 502
 503	/* to buffer, int w, u_char *buf */
 504#define w32_buf(buf,w)	{ u_int i_tmp;			   \
 505			  i_tmp = (w<0) ? (~(-w)+1) : (w); \
 506			  (buf)[0] = (i_tmp >> 24) & 0xff; \
 507			  (buf)[1] = (i_tmp >> 16) & 0xff; \
 508			  (buf)[2] = (i_tmp >>	8) & 0xff; \
 509			  (buf)[3] = (i_tmp	 ) & 0xff; \
 510			}
 511
 512#define w32(buf)      (((buf)[0]&0xff) << 24 | \
 513		       ((buf)[1]&0xff) << 16 | \
 514		       ((buf)[2]&0xff) <<  8 | \
 515		       ((buf)[3]&0xff) )
 516
 517	/* from buffer, char *buf, result to an int */
 518#define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf))
 519
 520
 521/*
 522 * oncore_start - initialize data for processing
 523 */
 524
 525static int
 526oncore_start(
 527	int unit,
 528	struct peer *peer
 529	)
 530{
 531#define STRING_LEN	32
 532	register struct instance *instance;
 533	struct refclockproc *pp;
 534	int fd1, fd2, num;
 535	char device1[STRING_LEN], device2[STRING_LEN], Msg[160];
 536	const char *cp;
 537	struct stat stat1, stat2;
 538
 539	/* create instance structure for this unit */
 540
 541	if (!(instance = (struct instance *) malloc(sizeof *instance))) {
 542		perror("malloc");
 543		return (0);
 544	}
 545	memset((char *) instance, 0, sizeof *instance);
 546
 547	/* initialize miscellaneous variables */
 548
 549	pp = peer->procptr;
 550	pp->unitptr    = (caddr_t) instance;
 551	instance->pp   = pp;
 552	instance->unit = unit;
 553	instance->peer = peer;
 554	instance->assert = 1;
 555	instance->once = 1;
 556
 557	instance->Bj_day = -1;
 558	instance->traim = -1;
 559	instance->traim_in = -1;
 560	instance->chan_in = -1;
 561	instance->model = ONCORE_UNKNOWN;
 562	instance->mode = MODE_UNKNOWN;
 563	instance->site_survey = ONCORE_SS_UNKNOWN;
 564	instance->Ag = 0xff;		/* Satellite mask angle, unset by user */
 565	instance->ant_state = ONCORE_ANTENNA_UNKNOWN;
 566
 567	peer->precision = -26;
 568	peer->minpoll = 4;
 569	peer->maxpoll = 4;
 570	pp->clockdesc = "Motorola Oncore GPS Receiver";
 571	memcpy((char *)&pp->refid, "GPS\0", (size_t) 4);
 572
 573	cp = "ONCORE DRIVER -- CONFIGURING";
 574	record_clock_stats(&(instance->peer->srcadr), cp);
 575
 576	instance->o_state = ONCORE_NO_IDEA;
 577	cp = "state = ONCORE_NO_IDEA";
 578	record_clock_stats(&(instance->peer->srcadr), cp);
 579
 580	/* Now open files.
 581	 * This is a bit complicated, a we dont want to open the same file twice
 582	 * (its a problem on some OS), and device2 may not exist for the new PPS
 583	 */
 584
 585	(void)sprintf(device1, DEVICE1, unit);
 586	(void)sprintf(device2, DEVICE2, unit);
 587
 588	/* OPEN DEVICES */
 589	/* opening different devices for fd1 and fd2 presents no problems */
 590	/* opening the SAME device twice, seems to be OS dependent.
 591		(a) on Linux (no streams) no problem
 592		(b) on SunOS (and possibly Solaris, untested), (streams)
 593			never see the line discipline.
 594	   Since things ALWAYS work if we only open the device once, we check
 595	     to see if the two devices are in fact the same, then proceed to
 596	     do one open or two.
 597	*/
 598
 599	if (stat(device1, &stat1)) {
 600		sprintf(Msg, "Can't stat fd1 (%s)\n", device1);
 601		record_clock_stats(&(instance->peer->srcadr), Msg);
 602		exit(1);
 603	}
 604
 605	if (stat(device2, &stat2)) {
 606		sprintf(Msg, "Can't stat fd2 (%s)\n", device2);
 607		record_clock_stats(&(instance->peer->srcadr), Msg);
 608		exit(1);
 609	}
 610
 611	if (!(fd1 = refclock_open(device1, SPEED, LDISC_RAW))) {
 612		sprintf(Msg, "Can't open fd1 (%s)\n", device1);
 613		record_clock_stats(&(instance->peer->srcadr), Msg);
 614		exit(1);
 615	}
 616
 617	if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino))	/* same device here */
 618		fd2 = fd1;
 619	else {	/* different devices here */
 620		if ((fd2=open(device2, O_RDWR)) < 0) {
 621			sprintf(Msg, "Can't open fd2 (%s)\n", device2);
 622			record_clock_stats(&(instance->peer->srcadr), Msg);
 623			exit(1);
 624		}
 625	}
 626	num = fd2;
 627
 628	/* open ppsapi soure */
 629
 630	if (time_pps_create(num, &instance->pps_h) < 0) {
 631		record_clock_stats(&(instance->peer->srcadr), "PPSAPI not found in kernel");
 632		return(0);
 633	}
 634
 635	/* continue initialization */
 636
 637	instance->ttyfd = fd1;
 638	instance->ppsfd = fd2;
 639
 640	/* go read any input data in /etc/ntp.oncoreX or /etc/ntp/oncore.X */
 641
 642	oncore_read_config(instance);
 643
 644	if (!oncore_ppsapi(instance))
 645		return(0);
 646
 647	pp->io.clock_recv = oncore_receive;
 648	pp->io.srcclock = (caddr_t)peer;
 649	pp->io.datalen = 0;
 650	pp->io.fd = fd1;
 651	if (!io_addclock(&pp->io)) {
 652		record_clock_stats(&(instance->peer->srcadr), "ONCORE: io_addclock");
 653		(void) close(fd1);
 654		free(instance);
 655		return (0);
 656	}
 657
 658#ifdef ONCORE_SHMEM_STATUS
 659	/*
 660	 * Before starting ONCORE, lets setup SHMEM
 661	 * This will include merging an old SHMEM into the new one if
 662	 * an old one is found.
 663	 */
 664
 665	oncore_init_shmem(instance);
 666#endif
 667
 668	/*
 669	 * This will return the Model of the Oncore receiver.
 670	 * and start the Initialization loop in oncore_msg_Cj.
 671	 */
 672
 673	instance->o_state = ONCORE_CHECK_ID;
 674	cp = "state = ONCORE_CHECK_ID";
 675	record_clock_stats(&(instance->peer->srcadr), cp);
 676
 677	instance->timeout = 4;
 678	oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Set Posn Fix mode (not Idle (VP)) */
 679	oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
 680
 681	instance->pollcnt = 2;
 682	return (1);
 683}
 684
 685
 686/*
 687 * oncore_shutdown - shut down the clock
 688 */
 689
 690static void
 691oncore_shutdown(
 692	int unit,
 693	struct peer *peer
 694	)
 695{
 696	register struct instance *instance;
 697	struct refclockproc *pp;
 698
 699	pp = peer->procptr;
 700	instance = (struct instance *) pp->unitptr;
 701
 702	io_closeclock(&pp->io);
 703
 704	time_pps_destroy (instance->pps_h);
 705
 706	close(instance->ttyfd);
 707
 708	if ((instance->ppsfd != -1) && (instance->ppsfd != instance->ttyfd))
 709		close(instance->ppsfd);
 710
 711	if (instance->shmemfd)
 712		close(instance->shmemfd);
 713
 714	free(instance);
 715}
 716
 717
 718
 719/*
 720 * oncore_poll - called by the transmit procedure
 721 */
 722
 723static void
 724oncore_poll(
 725	int unit,
 726	struct peer *peer
 727	)
 728{
 729	struct instance *instance;
 730
 731	instance = (struct instance *) peer->procptr->unitptr;
 732	if (instance->timeout) {
 733		char	*cp;
 734
 735		instance->timeout--;
 736		if (instance->timeout == 0) {
 737			cp = "Oncore: No response from @@Cj, shutting down driver";
 738			record_clock_stats(&(instance->peer->srcadr), cp);
 739			oncore_shutdown(unit, peer);
 740		} else {
 741			oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
 742			cp = "Oncore: Resend @@Cj";
 743			record_clock_stats(&(instance->peer->srcadr), cp);
 744		}
 745		return;
 746	}
 747
 748	if (!instance->pollcnt)
 749		refclock_report(peer, CEVNT_TIMEOUT);
 750	else
 751		instance->pollcnt--;
 752	peer->procptr->polls++;
 753	instance->polled = 1;
 754}
 755
 756
 757
 758/*
 759 * Initialize PPSAPI
 760 */
 761
 762static int
 763oncore_ppsapi(
 764	struct instance *instance
 765	)
 766{
 767	int cap, mode, mode1;
 768	char *cp, Msg[160];
 769
 770	if (time_pps_getcap(instance->pps_h, &cap) < 0) {
 771		msyslog(LOG_ERR, "time_pps_getcap failed: %m");
 772		return (0);
 773	}
 774
 775	if (time_pps_getparams(instance->pps_h, &instance->pps_p) < 0) {
 776		msyslog(LOG_ERR, "time_pps_getparams failed: %m");
 777		return (0);
 778	}
 779
 780	/* nb. only turn things on, if someone else has turned something
 781	 *	on before we get here, leave it alone!
 782	 */
 783
 784	if (instance->assert) {
 785		cp = "Assert.";
 786		mode = PPS_CAPTUREASSERT;
 787		mode1 = PPS_OFFSETASSERT;
 788	} else {
 789		cp = "Clear.";
 790		mode = PPS_CAPTURECLEAR;
 791		mode1 = PPS_OFFSETCLEAR;
 792	}
 793	sprintf(Msg, "Initializing timeing to %s.", cp);
 794	record_clock_stats(&(instance->peer->srcadr), Msg);
 795
 796	if (!(mode & cap)) {
 797		sprintf(Msg, "Can't set timeing to %s, exiting...", cp);
 798		record_clock_stats(&(instance->peer->srcadr), Msg);
 799		return(0);
 800	}
 801
 802	if (!(mode1 & cap)) {
 803		sprintf(Msg, "Can't set PPS_%sCLEAR, this will increase jitter.", cp);
 804		record_clock_stats(&(instance->peer->srcadr), Msg);
 805		mode1 = 0;
 806	}
 807
 808	/* only set what is legal */
 809
 810	instance->pps_p.mode = (mode | mode1 | PPS_TSFMT_TSPEC) & cap;
 811
 812	if (time_pps_setparams(instance->pps_h, &instance->pps_p) < 0) {
 813		record_clock_stats(&(instance->peer->srcadr), "ONCORE: time_pps_setparams fails");
 814		exit(1);
 815	}
 816
 817	/* If HARDPPS is on, we tell kernel */
 818
 819	if (instance->hardpps) {
 820		int	i;
 821
 822		record_clock_stats(&(instance->peer->srcadr), "HARDPPS Set.");
 823
 824		if (instance->assert)
 825			i = PPS_CAPTUREASSERT;
 826		else
 827			i = PPS_CAPTURECLEAR;
 828
 829		/* we know that 'i' is legal from above */
 830
 831		if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i,
 832		    PPS_TSFMT_TSPEC) < 0) {
 833			msyslog(LOG_ERR, "time_pps_kcbind failed: %m");
 834			record_clock_stats(&(instance->peer->srcadr), "HARDPPS failed, abort...");
 835			return (0);
 836		}
 837		pps_enable = 1;
 838	}
 839	return(1);
 840}
 841
 842
 843
 844#ifdef ONCORE_SHMEM_STATUS
 845static void
 846oncore_init_shmem(
 847	struct instance *instance
 848	)
 849{
 850	int i, l, n, fd, shmem_old_size, n1;
 851	char Msg[160];
 852	u_char *cp, *cp1, *buf, *shmem_old;
 853	struct msg_desc *mp;
 854	struct stat sbuf;
 855	size_t shmem_length;
 856
 857       /*
 858	* The first thing we do is see if there is an instance->shmem_fname file (still)
 859	* out there from a previous run.  If so, we copy it in and use it to initialize
 860	* shmem (so we won't lose our almanac if we need it).
 861	*/
 862
 863	shmem_old = 0;
 864	shmem_old_size = 0;
 865	if ((fd = open(instance->shmem_fname, O_RDONLY)) < 0)
 866		record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't open SHMEM file");
 867	else {
 868		fstat(fd, &sbuf);
 869		shmem_old_size = sbuf.st_size;
 870		if (shmem_old_size != 0) {
 871			shmem_old = (u_char *) malloc((unsigned) sbuf.st_size);
 872			if (shmem_old == NULL)
 873				record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't malloc buffer for shmem_old");
 874			else
 875				read(fd, shmem_old, shmem_old_size);
 876		}
 877		close(fd);
 878	}
 879
 880	/* OK, we now create the NEW SHMEM. */
 881
 882	if ((instance->shmemfd = open(instance->shmem_fname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) {
 883		record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't open shmem");
 884		if (shmem_old)
 885			free(shmem_old);
 886
 887		return;
 888	}
 889
 890	/* see how big it needs to be */
 891
 892	n = 1;
 893	for (mp=oncore_messages; mp->flag[0]; mp++) {
 894		mp->shmem = n;
 895		/* Allocate space for multiplexed almanac, and 0D/2D/3D @@Ea records */
 896		if (!strcmp(mp->flag, "Cb")) {
 897			instance->shmem_Cb = n;
 898			n += (mp->len + 3) * 34;
 899		}
 900		if (!strcmp(mp->flag, "Ba")) {
 901			instance->shmem_Ba = n;
 902			n += (mp->len + 3) * 3;
 903		}
 904		if (!strcmp(mp->flag, "Ea")) {
 905			instance->shmem_Ea = n;
 906			n += (mp->len + 3) * 3;
 907		}
 908		if (!strcmp(mp->flag, "Ha")) {
 909			instance->shmem_Ha = n;
 910			n += (mp->len + 3) * 3;
 911		}
 912		n += (mp->len + 3);
 913	}
 914	shmem_length = n + 2;
 915
 916	buf = malloc(shmem_length);
 917	if (buf == NULL) {
 918		record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't malloc buffer for shmem");
 919		close(instance->shmemfd);
 920		if (shmem_old)
 921			free(shmem_old);
 922
 923		return;
 924	}
 925
 926	memset(buf, 0, shmem_length);
 927
 928	/* next build the new SHMEM buffer in memory */
 929
 930	for (mp=oncore_messages; mp->flag[0]; mp++) {
 931		l = mp->shmem;
 932		buf[l + 0] = mp->len >> 8;
 933		buf[l + 1] = mp->len & 0xff;
 934		buf[l + 2] = 0;
 935		buf[l + 3] = '@';
 936		buf[l + 4] = '@';
 937		buf[l + 5] = mp->flag[0];
 938		buf[l + 6] = mp->flag[1];
 939		if (!strcmp(mp->flag, "Cb") || !strcmp(mp->flag, "Ba") || !strcmp(mp->flag, "Ea") || !strcmp(mp->flag, "Ha")) {
 940			if (!strcmp(mp->flag, "Cb"))
 941				n = 35;
 942			else
 943				n = 4;
 944			for (i=1; i<n; i++) {
 945				buf[l + i * (mp->len+3) + 0] = mp->len >> 8;
 946				buf[l + i * (mp->len+3) + 1] = mp->len & 0xff;
 947				buf[l + i * (mp->len+3) + 2] = 0;
 948				buf[l + i * (mp->len+3) + 3] = '@';
 949				buf[l + i * (mp->len+3) + 4] = '@';
 950				buf[l + i * (mp->len+3) + 5] = mp->flag[0];
 951				buf[l + i * (mp->len+3) + 6] = mp->flag[1];
 952			}
 953		}
 954	}
 955
 956	/* we now walk thru the two buffers (shmem_old and buf, soon to become shmem)
 957	 * copying the data in shmem_old to buf.
 958	 * When we are done we write it out and free both buffers.
 959	 * If the structure sizes dont agree, I will not copy.
 960	 * This could be due to an addition/deletion or a problem with the disk file.
 961	 */
 962
 963	if (shmem_old) {
 964		if (shmem_old_size == shmem_length) {
 965			for (cp=buf+4, cp1=shmem_old+4; (n = 256*(*(cp-3)) + *(cp-2));	cp+=(n+3), cp1+=(n+3)) {
 966				n1 = 256*(*(cp1-3)) + *(cp1-2);
 967				if (n == 0 || n1 != n || strncmp((char *) cp, (char *) cp1, 4))
 968					break;
 969
 970				memcpy(cp, cp1, (size_t) n);
 971			}
 972		}
 973		free(shmem_old);
 974	}
 975
 976	i = write(instance->shmemfd, buf, shmem_length);
 977	free(buf);
 978
 979	if (i != shmem_length) {
 980		record_clock_stats(&(instance->peer->srcadr), "ONCORE: error writing shmem");
 981		close(instance->shmemfd);
 982		return;
 983	}
 984
 985	instance->shmem = (u_char *) mmap(0, shmem_length,
 986		PROT_READ | PROT_WRITE,
 987#ifdef MAP_HASSEMAPHORE
 988		MAP_HASSEMAPHORE |
 989#endif
 990		MAP_SHARED, instance->shmemfd, (off_t)0);
 991
 992	if (instance->shmem == (u_char *)MAP_FAILED) {
 993		instance->shmem = 0;
 994		close(instance->shmemfd);
 995		return;
 996	}
 997
 998	sprintf(Msg, "SHMEM (size = %ld) is CONFIGURED and available as %s",
 999		(u_long) shmem_length, instance->shmem_fname);
1000	record_clock_stats(&(instance->peer->srcadr), Msg);
1001}
1002#endif /* ONCORE_SHMEM_STATUS */
1003
1004
1005
1006/*
1007 * Read Input file if it exists.
1008 */
1009
1010static void
1011oncore_read_config(
1012	struct instance *instance
1013	)
1014{
1015/*
1016 * First we try to open the configuration file
1017 *    /etc/oncoreN
1018 * where N is the unit number viz 127.127.30.N.
1019 * If we don't find it we try
1020 *    /etc/ntp.oncore.N
1021 * and then
1022 *    /etc/ntp.oncore
1023 *
1024 * If we don't find any then we don't have the cable delay or PPS offset
1025 * and we choose MODE (4) below.
1026 *
1027 * Five Choices for MODE
1028 *    (0) ONCORE is preinitialized, don't do anything to change it.
1029 *	    nb, DON'T set 0D mode, DON'T set Delay, position...
1030 *    (1) NO RESET, Read Position, delays from data file, lock it in, go to 0D mode.
1031 *    (2) NO RESET, Read Delays from data file, do SITE SURVEY to get position,
1032 *		    lock this in, go to 0D mode.
1033 *    (3) HARD RESET, Read Position, delays from data file, lock it in, go to 0D mode.
1034 *    (4) HARD RESET, Read Delays from data file, do SITE SURVEY to get position,
1035 *		    lock this in, go to 0D mode.
1036 *     NB. If a POSITION is specified in the config file with mode=(2,4) [SITE SURVEY]
1037 *	   then this position is set as the INITIAL position of the ONCORE.
1038 *	   This can reduce the time to first fix.
1039 * -------------------------------------------------------------------------------
1040 * Note that an Oncore UT without a battery backup retains NO information if it is
1041 *   power cycled, with a Battery Backup it remembers the almanac, etc.
1042 * For an Oncore VP, there is an eeprom that will contain this data, along with the
1043 *   option of Battery Backup.
1044 * So a UT without Battery Backup is equivalent to doing a HARD RESET on each
1045 *   power cycle, since there is nowhere to store the data.
1046 * -------------------------------------------------------------------------------
1047 *
1048 * If we open one or the other of the files, we read it looking for
1049 *   MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET, ASSERT, CLEAR, HARDPPS,
1050 *   STATUS, POSN3D, POSN2D, CHAN, TRAIM
1051 * then initialize using method MODE.  For Mode = (1,3) all of (LAT, LON, HT) must
1052 *   be present or mode reverts to (2,4).
1053 *
1054 * Read input file.
1055 *
1056 *	# is comment to end of line
1057 *	= allowed between 1st and 2nd fields.
1058 *
1059 *	Expect to see one line with 'MODE' as first field, followed by an integer
1060 *	   in the range 0-4 (default = 4).
1061 *
1062 *	Expect to see two lines with 'LONG', 'LAT' followed by 1-3 fields.
1063 *	All numbers are floating point.
1064 *		DDD.ddd
1065 *		DDD  MMM.mmm
1066 *		DDD  MMM  SSS.sss
1067 *
1068 *	Expect to see one line with 'HT' as first field,
1069 *	   followed by 1-2 fields.  First is a number, the second is 'FT' or 'M'
1070 *	   for feet or meters.	HT is the height above the GPS ellipsoid.
1071 *	   If the receiver reports height in both GPS and MSL, then we will report
1072 *	   the difference GPS-MSL on the clockstats file.
1073 *
1074 *	There is an optional line, starting with DELAY, followed
1075 *	   by 1 or two fields.	The first is a number (a time) the second is
1076 *	   'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
1077 *	    DELAY  is cable delay, typically a few tens of ns.
1078 *
1079 *	There is an optional line, starting with OFFSET, followed
1080 *	   by 1 or two fields.	The first is a number (a time) the second is
1081 *	   'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
1082 *	   OFFSET is the offset of the PPS pulse from 0. (only fully implemented
1083 *		with the PPSAPI, we need to be able to tell the Kernel about this
1084 *		offset if the Kernel PLL is in use, but can only do this presently
1085 *		when using the PPSAPI interface.  If not using the Kernel PLL,
1086 *		then there is no problem.
1087 *
1088 *	There is an optional line, with either ASSERT or CLEAR on it, which
1089 *	   determine which transition of the PPS signal is used for timing by the
1090 *	   PPSAPI.  If neither is present, then ASSERT is assumed.
1091 *	   ASSERT/CLEAR can also be set with FLAG2 of the ntp.conf input.
1092 *	   For Flag2, ASSERT=0, and hence is default.
1093 *
1094 *	There is an optional line, with HARDPPS on it.	Including this line causes
1095 *	   the PPS signal to control the kernel PLL.
1096 *	   HARDPPS can also be set with FLAG3 of the ntp.conf input.
1097 *	   For Flag3, 0 is disabled, and the default.
1098 *
1099 *	There are three options that have to do with using the shared memory option.
1100 *	   First, to enable the option there must be a SHMEM line with a file name.
1101 *	   The file name is the file associated with the shared memory.
1102 *
1103 *	In shared memory, there is one 'record' for each returned variable.
1104 *	For the @@Ea data there are three 'records' containing position data.
1105 *	   There will always be data in the record corresponding to the '0D' @@Ea record,
1106 *	   and the user has a choice of filling the '3D' record by specifying POSN3D,
1107 *	   or the '2D' record by specifying POSN2D.  In either case the '2D' or '3D'
1108 *	   record is filled once every 15s.
1109 *
1110 *	Two additional variables that can be set are CHAN and TRAIM.  These should be
1111 *	   set correctly by the code examining the @@Cj record, but we bring them out here
1112 *	   to allow the user to override either the # of channels, or the existence of TRAIM.
1113 *	   CHAN expects to be followed by in integer: 6, 8, or 12. TRAIM expects to be
1114 *	   followed by YES or NO.
1115 *
1116 *	There is an optional line with MASK on it followed by one integer field in the
1117 *	   range 0 to 89. This sets the satellite mask angle and will determine the minimum
1118 *	   elevation angle for satellites to be tracked by the receiver. The default value
1119 *	   is 10 deg for the VP and 0 deg for all other receivers.
1120 *
1121 * So acceptable input would be
1122 *	# these are my coordinates (RWC)
1123 *	LON  -106 34.610
1124 *	LAT    35 08.999
1125 *	HT	1589	# could equally well say HT 5215 FT
1126 *	DELAY  60 ns
1127 */
1128
1129	FILE	*fd;
1130	char	*cp, *cc, *ca, line[100], units[2], device[20], Msg[160], **cpp;
1131	char	*dirs[] = { "/etc/ntp", "/etc", 0 };
1132	int	i, sign, lat_flg, long_flg, ht_flg, mode, mask;
1133	double	f1, f2, f3;
1134
1135	fd = NULL;	/* just to shutup gcc complaint */
1136	for (cpp=dirs; *cpp; cpp++) {
1137		cp = *cpp;
1138		sprintf(device, "%s/ntp.oncore.%d", cp, instance->unit); /* try "ntp.oncore.0 */
1139		if ((fd=fopen(device, "r")))
1140			break;
1141		sprintf(device, "%s/ntp.oncore%d", cp, instance->unit);  /* try "ntp.oncore0" */
1142		if ((fd=fopen(device, "r")))
1143			break;
1144		sprintf(device, "%s/ntp.oncore", cp);   /* and finally "ntp.oncore" */
1145		if ((fd=fopen(device, "r")))
1146			break;
1147	}
1148
1149	if (!fd) {	/* no inputfile, default to the works ... */
1150		instance->init_type = 4;
1151		return;
1152	}
1153
1154	mode = mask = 0;
1155	lat_flg = long_flg = ht_flg = 0;
1156	while (fgets(line, 100, fd)) {
1157
1158		/* Remove comments */
1159		if ((cp = strchr(line, '#')))
1160			*cp = '\0';
1161
1162		/* Remove trailing space */
1163		for (i = strlen(line);
1164		     i > 0 && isascii((int)line[i - 1]) && isspace((int)line[i - 1]);
1165			)
1166			line[--i] = '\0';
1167
1168		/* Remove leading space */
1169		for (cc = line; *cc && isascii((int)*cc) && isspace((int)*cc); cc++)
1170			continue;
1171
1172		/* Stop if nothing left */
1173		if (!*cc)
1174			continue;
1175
1176		/* Uppercase the command and find the arg */
1177		for (ca = cc; *ca; ca++) {
1178			if (isascii((int)*ca)) {
1179				if (islower((int)*ca)) {
1180					*ca = toupper(*ca);
1181				} else if (isspace((int)*ca) || (*ca == '='))
1182					break;
1183			}
1184		}
1185
1186		/* Remove space (and possible =) leading the arg */
1187		for (; *ca && isascii((int)*ca) && (isspace((int)*ca) || (*ca == '=')); ca++)
1188			continue;
1189
1190		if (!strncmp(cc, "STATUS", (size_t) 6) || !strncmp(cc, "SHMEM", (size_t) 5)) {
1191			i = strlen(ca);
1192			instance->shmem_fname = (char *) malloc((unsigned) (i+1));
1193			strcpy(instance->shmem_fname, ca);
1194			continue;
1195		}
1196
1197		/* Uppercase argument as well */
1198		for (cp = ca; *cp; cp++)
1199			if (isascii((int)*cp) && islower((int)*cp))
1200				*cp = toupper(*cp);
1201
1202		if (!strncmp(cc, "LAT", (size_t) 3)) {
1203			f1 = f2 = f3 = 0;
1204			sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
1205			sign = 1;
1206			if (f1 < 0) {
1207				f1 = -f1;
1208				sign = -1;
1209			}
1210			instance->ss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
1211			lat_flg++;
1212		} else if (!strncmp(cc, "LON", (size_t) 3)) {
1213			f1 = f2 = f3 = 0;
1214			sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
1215			sign = 1;
1216			if (f1 < 0) {
1217				f1 = -f1;
1218				sign = -1;
1219			}
1220			instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
1221			long_flg++;
1222		} else if (!strncmp(cc, "HT", (size_t) 2)) {
1223			f1 = 0;
1224			units[0] = '\0';
1225			sscanf(ca, "%lf %1s", &f1, units);
1226			if (units[0] == 'F')
1227				f1 = 0.3048 * f1;
1228			instance->ss_ht = 100 * f1;    /* cm */
1229			ht_flg++;
1230		} else if (!strncmp(cc, "DELAY", (size_t) 5)) {
1231			f1 = 0;
1232			units[0] = '\0';
1233			sscanf(ca, "%lf %1s", &f1, units);
1234			if (units[0] == 'N')
1235				;
1236			else if (units[0] == 'U')
1237				f1 = 1000 * f1;
1238			else if (units[0] == 'M')
1239				f1 = 1000000 * f1;
1240			else
1241				f1 = 1000000000 * f1;
1242			if (f1 < 0 || f1 > 1.e9)
1243				f1 = 0;
1244			if (f1 < 0 || f1 > 999999) {
1245				sprintf(Msg, "PPS Cable delay of %fns out of Range, ignored", f1);
1246				record_clock_stats(&(instance->peer->srcadr), Msg);
1247			} else
1248				instance->delay = f1;		/* delay in ns */
1249		} else if (!strncmp(cc, "OFFSET", (size_t) 6)) {
1250			f1 = 0;
1251			units[0] = '\0';
1252			sscanf(ca, "%lf %1s", &f1, units);
1253			if (units[0] == 'N')
1254				;
1255			else if (units[0] == 'U')
1256				f1 = 1000 * f1;
1257			else if (units[0] == 'M')
1258				f1 = 1000000 * f1;
1259			else
1260				f1 = 1000000000 * f1;
1261			if (f1 < 0 || f1 > 1.e9)
1262				f1 = 0;
1263			if (f1 < 0 || f1 > 999999999.) {
1264				sprintf(Msg, "PPS Offset of %fns out of Range, ignored", f1);
1265				record_clock_stats(&(instance->peer->srcadr), Msg);
1266			} else
1267				instance->offset = f1;		/* offset in ns */
1268		} else if (!strncmp(cc, "MODE", (size_t) 4)) {
1269			sscanf(ca, "%d", &mode);
1270			if (mode < 0 || mode > 4)
1271				mode = 4;
1272		} else if (!strncmp(cc, "ASSERT", (size_t) 6)) {
1273			instance->assert = 1;
1274		} else if (!strncmp(cc, "CLEAR", (size_t) 5)) {
1275			instance->assert = 0;
1276		} else if (!strncmp(cc, "HARDPPS", (size_t) 7)) {
1277			instance->hardpps = 1;
1278		} else if (!strncmp(cc, "POSN2D", (size_t) 6)) {
1279			instance->shmem_Posn = 2;
1280		} else if (!strncmp(cc, "POSN3D", (size_t) 6)) {
1281			instance->shmem_Posn = 3;
1282		} else if (!strncmp(cc, "CHAN", (size_t) 4)) {
1283			sscanf(ca, "%d", &i);
1284			if ((i == 6) || (i == 8) || (i == 12))
1285				instance->chan_in = i;
1286		} else if (!strncmp(cc, "TRAIM", (size_t) 5)) {
1287			instance->traim_in = 1; 	/* so TRAIM alone is YES */
1288			if (!strcmp(ca, "NO") || !strcmp(ca, "OFF"))    /* Yes/No, On/Off */
1289				instance->traim_in = 0;
1290		} else if (!strncmp(cc, "MASK", (size_t) 4)) {
1291			sscanf(ca, "%d", &mask);
1292			if (mask > -1 && mask < 90)
1293				instance->Ag = mask;			/* Satellite mask angle */
1294		}
1295	}
1296	fclose(fd);
1297
1298	/*
1299	 *    OK, have read all of data file, and extracted the good stuff.
1300	 *    If lat/long/ht specified they ALL must be specified for mode = (1,3).
1301	 */
1302
1303	instance->posn_set = 1;
1304	if (!( lat_flg && long_flg && ht_flg )) {
1305		printf("ONCORE: incomplete data on %s\n", device);
1306		instance->posn_set = 0;
1307		if (mode == 1 || mode == 3) {
1308			sprintf(Msg, "Input Mode = %d, but no/incomplete position, mode set to %d", mode, mode+1);
1309			record_clock_stats(&(instance->peer->srcadr), Msg);
1310			mode++;
1311		}
1312	}
1313	instance->init_type = mode;
1314
1315	sprintf(Msg, "Input mode = %d", mode);
1316	record_clock_stats(&(instance->peer->srcadr), Msg);
1317}
1318
1319
1320
1321/*
1322 * move data from NTP to buffer (toss the extra in the unlikely case it won't fit)
1323 */
1324
1325static void
1326oncore_receive(
1327	struct recvbuf *rbufp
1328	)
1329{
1330	size_t i;
1331	u_char *p;
1332	struct peer *peer;
1333	struct instance *instance;
1334
1335	peer = (struct peer *)rbufp->recv_srcclock;
1336	instance = (struct instance *) peer->procptr->unitptr;
1337	p = (u_char *) &rbufp->recv_space;
1338
1339#if 0
1340	if (debug > 4) {
1341		int i;
1342		printf("ONCORE: >>>");
1343		for(i=0; i<rbufp->recv_length; i++)
1344			printf("%02x ", p[i]);
1345		printf("\n");
1346		printf("ONCORE: >>>");
1347		for(i=0; i<rbufp->recv_length; i++)
1348			printf("%03o ", p[i]);
1349		printf("\n");
1350	}
1351#endif
1352
1353	i = rbufp->recv_length;
1354	if (rcvbuf+rcvptr+i > &rcvbuf[sizeof rcvbuf])
1355		i = sizeof(rcvbuf) - rcvptr;	/* and some char will be lost */
1356	memcpy(rcvbuf+rcvptr, p, i);
1357	rcvptr += i;
1358	oncore_consume(instance);
1359}
1360
1361
1362
1363/*
1364 * Deal with any complete messages
1365 */
1366
1367static void
1368oncore_consume(
1369	struct instance *instance
1370	)
1371{
1372	int i, m;
1373	unsigned l;
1374
1375	while (rcvptr >= 7) {
1376		if (rcvbuf[0] != '@' || rcvbuf[1] != '@') {
1377			/* We're not in sync, lets try to get there */
1378			for (i=1; i < rcvptr-1; i++)
1379				if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@')
1380					break;
1381#ifdef DEBUG
1382			if (debug > 4)
1383				printf("ONCORE[%d]: >>> skipping %d chars\n", instance->unit, i);
1384#endif
1385			if (i != rcvptr)
1386				memcpy(rcvbuf, rcvbuf+i, (size_t)(rcvptr-i));
1387			rcvptr -= i;
1388			continue;
1389		}
1390
1391		/* Ok, we have a header now */
1392		l = sizeof(oncore_messages)/sizeof(oncore_messages[0]) -1;
1393		for(m=0; m<l; m++)
1394			if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), (size_t) 2))
1395				break;
1396		if (m == l) {
1397#ifdef DEBUG
1398			if (debug > 4)
1399				printf("ONCORE[%d]: >>> Unknown MSG, skipping 4 (%c%c)\n", instance->unit, rcvbuf[2], rcvbuf[3]);
1400#endif
1401			memcpy(rcvbuf, rcvbuf+4, (size_t) 4);
1402			rcvptr -= 4;
1403			continue;
1404		}
1405
1406		l = oncore_messages[m].len;
1407#if 0
1408		if (debug > 3)
1409			printf("ONCORE[%d]: GOT: %c%c  %d of %d entry %d\n", instance->unit, rcvbuf[2], rcvbuf[3], rcvptr, l, m);
1410#endif
1411		/* Got the entire message ? */
1412
1413		if (rcvptr < l)
1414			return;
1415
1416		/* are we at the end of message? should be <Cksum><CR><LF> */
1417
1418		if (rcvbuf[l-2] != '\r' || rcvbuf[l-1] != '\n') {
1419#ifdef DEBUG
1420			if (debug)
1421				printf("ONCORE[%d]: NO <CR><LF> at end of message\n", instance->unit);
1422#endif
1423		} else {	/* check the CheckSum */
1424			if (oncore_checksum_ok(rcvbuf, l)) {
1425				if (instance->shmem != NULL) {
1426					instance->shmem[oncore_messages[m].shmem + 2]++;
1427					memcpy(instance->shmem + oncore_messages[m].shmem + 3,
1428					    rcvbuf, (size_t) l);
1429				}
1430				oncore_msg_any(instance, rcvbuf, (size_t) (l-3), m);
1431				if (oncore_messages[m].handler)
1432					oncore_messages[m].handler(instance, rcvbuf, (size_t) (l-3));
1433			}
1434#ifdef DEBUG
1435			else if (debug) {
1436				printf("ONCORE[%d]: Checksum mismatch!\n", instance->unit);
1437				printf("ONCORE[%d]: @@%c%c ", instance->unit, rcvbuf[2], rcvbuf[3]);
1438				for (i=4; i<l; i++)
1439					printf("%03o ", rcvbuf[i]);
1440				printf("\n");
1441			}
1442#endif
1443		}
1444
1445		if (l != rcvptr)
1446			memcpy(rcvbuf, rcvbuf+l, (size_t) (rcvptr-l));
1447		rcvptr -= l;
1448	}
1449}
1450
1451
1452
1453static void
1454oncore_get_timestamp(
1455	struct instance *instance,
1456	long dt1,	/* tick offset THIS time step */
1457	long dt2	/* tick offset NEXT time step */
1458	)
1459{
1460	int	Rsm;
1461	u_long	j;
1462	l_fp ts, ts_tmp;
1463	double dmy;
1464#ifdef HAVE_STRUCT_TIMESPEC
1465	struct timespec *tsp = 0;
1466#else
1467	struct timeval	*tsp = 0;
1468#endif
1469	int	current_mode;
1470	u_long	i;
1471	pps_params_t current_params;
1472	struct timespec timeout;
1473	pps_info_t pps_i;
1474
1475#if 1
1476	/* If we are in SiteSurvey mode, then we are in 3D mode, and we fall thru.
1477	 * If we have Finished the SiteSurvey, then we fall thru for the 14/15
1478	 *  times we get here in 0D mode (the 1/15 is in 3D for SHMEM).
1479	 * This gives good time, which gets better when the SS is done.
1480	 */
1481
1482	if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D))
1483#else
1484	/* old check, only fall thru for SS_DONE and 0D mode, 2h45m wait for ticks */
1485
1486	if ((instance->site_survey != ONCORE_SS_DONE) || (instance->mode != MODE_0D))
1487#endif
1488		return;
1489
1490	/* Don't do anything without an almanac to define the GPS->UTC delta */
1491
1492	if (instance->rsm.bad_almanac)
1493		return;
1494
1495	/* Once the Almanac is valid, the M12+T does not produce valid UTC
1496	 * immediately.
1497	 * Wait for UTC offset decode valid, then wait one message more
1498	 * so we are not off by 13 seconds after  reset.
1499	 */
1500
1501	if (instance->count5) {
1502		instance->count5--;
1503		return;
1504	}
1505
1506	j = instance->ev_serial;
1507	timeout.tv_sec = 0;
1508	timeout.tv_ns

Large files files are truncated, but you can click here to view the full file