refclock_parse.c revision 56746
154359Sroberto/*
256746Sroberto * /src/NTP/ntp-4/ntpd/refclock_parse.c,v 4.36 1999/11/28 17:18:20 kardel RELEASE_19991128_A
354359Sroberto *
456746Sroberto * refclock_parse.c,v 4.36 1999/11/28 17:18:20 kardel RELEASE_19991128_A
554359Sroberto *
654359Sroberto * generic reference clock driver for receivers
754359Sroberto *
854359Sroberto * optionally make use of a STREAMS module for input processing where
954359Sroberto * available and configured. Currently the STREAMS module
1054359Sroberto * is only available for Suns running SunOS 4.x and SunOS5.x
1154359Sroberto *
1254359Sroberto * the STREAMS module is not required for operation and may be omitted
1354359Sroberto * at the cost of reduced accuracy. As new kernel interfaces emerger this
1454359Sroberto * restriction may be lifted in future.
1554359Sroberto *
1654359Sroberto * Copyright (c) 1995-1999 by Frank Kardel <kardel@acm.org>
1754359Sroberto * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universit�t Erlangen-N�rnberg, Germany
1854359Sroberto *
1954359Sroberto * This software may not be sold for profit without a written consent
2054359Sroberto * from the author.
2154359Sroberto *
2254359Sroberto * This program is distributed in the hope that it will be useful,
2354359Sroberto * but WITHOUT ANY WARRANTY; without even the implied warranty of
2454359Sroberto * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
2554359Sroberto *
2654359Sroberto */
2754359Sroberto
2854359Sroberto#ifdef HAVE_CONFIG_H
2954359Sroberto# include <config.h>
3054359Sroberto#endif
3154359Sroberto
3254359Sroberto#if defined(REFCLOCK) && defined(CLOCK_PARSE)
3354359Sroberto
3454359Sroberto/*
3554359Sroberto * This driver currently provides the support for
3654359Sroberto *   - Meinberg receiver DCF77 PZF 535 (TCXO version)       (DCF)
3754359Sroberto *   - Meinberg receiver DCF77 PZF 535 (OCXO version)       (DCF)
3854359Sroberto *   - Meinberg receiver DCF77 PZF 509                      (DCF)
3954359Sroberto *   - Meinberg receiver DCF77 AM receivers (e.g. C51)      (DCF)
4054359Sroberto *   - IGEL CLOCK                                           (DCF)
4154359Sroberto *   - ELV DCF7000                                          (DCF)
4254359Sroberto *   - Schmid clock                                         (DCF)
4354359Sroberto *   - Conrad DCF77 receiver module                         (DCF)
4454359Sroberto *   - FAU DCF77 NTP receiver (TimeBrick)                   (DCF)
4554359Sroberto *
4654359Sroberto *   - Meinberg GPS166/GPS167                               (GPS)
4754359Sroberto *   - Trimble (TSIP and TAIP protocol)                     (GPS)
4854359Sroberto *
4954359Sroberto *   - RCC8000 MSF Receiver                                 (MSF)
5054359Sroberto *   - WHARTON 400A Series clock			    (DCF)
5154359Sroberto *   - VARITEXT clock					    (MSF)
5254359Sroberto */
5354359Sroberto
5454359Sroberto/*
5554359Sroberto * Meinberg receivers are usually connected via a
5654359Sroberto * 9600 baud serial line
5754359Sroberto *
5854359Sroberto * The Meinberg GPS receivers also have a special NTP time stamp
5954359Sroberto * format. The firmware release is Uni-Erlangen.
6054359Sroberto *
6154359Sroberto * Meinberg generic receiver setup:
6254359Sroberto *	output time code every second
6354359Sroberto *	Baud rate 9600 7E2S
6454359Sroberto *
6554359Sroberto * Meinberg GPS16x setup:
6654359Sroberto *      output time code every second
6754359Sroberto *      Baudrate 19200 8N1
6854359Sroberto *
6954359Sroberto * This software supports the standard data formats used
7054359Sroberto * in Meinberg receivers.
7154359Sroberto *
7254359Sroberto * Special software versions are only sensible for the
7354359Sroberto * GPS 16x family of receivers.
7454359Sroberto *
7554359Sroberto * Meinberg can be reached via: http://www.meinberg.de/
7654359Sroberto */
7754359Sroberto
7854359Sroberto#include "ntpd.h"
7954359Sroberto#include "ntp_refclock.h"
8054359Sroberto#include "ntp_unixtime.h"	/* includes <sys/time.h> */
8154359Sroberto#include "ntp_control.h"
8254359Sroberto
8354359Sroberto#include <stdio.h>
8454359Sroberto#include <ctype.h>
8554359Sroberto#ifndef TM_IN_SYS_TIME
8654359Sroberto# include <time.h>
8754359Sroberto#endif
8854359Sroberto
8954359Sroberto#if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS)
9054359Sroberto# include "Bletch:  Define one of {STREAM,HAVE_SYSV_TTYS,HAVE_TERMIOS}"
9154359Sroberto#endif
9254359Sroberto
9354359Sroberto#ifdef STREAM
9454359Sroberto# include <sys/stream.h>
9554359Sroberto# include <sys/stropts.h>
9654359Sroberto#endif
9754359Sroberto
9854359Sroberto#ifdef HAVE_TERMIOS
9954359Sroberto# define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_))
10054359Sroberto# define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_))
10154359Sroberto# undef HAVE_SYSV_TTYS
10254359Sroberto#endif
10354359Sroberto
10454359Sroberto#ifdef HAVE_SYSV_TTYS
10554359Sroberto# define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_))
10654359Sroberto# define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_))
10754359Sroberto#endif
10854359Sroberto
10954359Sroberto#ifdef HAVE_BSD_TTYS
11054359Sroberto/* #error CURRENTLY NO BSD TTY SUPPORT */
11154359Sroberto# include "Bletch: BSD TTY not currently supported"
11254359Sroberto#endif
11354359Sroberto
11454359Sroberto#ifdef HAVE_SYS_IOCTL_H
11554359Sroberto# include <sys/ioctl.h>
11654359Sroberto#endif
11754359Sroberto
11854359Sroberto#ifdef PPS
11954359Sroberto#ifdef HAVE_SYS_PPSCLOCK_H
12054359Sroberto#include <sys/ppsclock.h>
12154359Sroberto#endif
12254359Sroberto#ifdef HAVE_TIO_SERIAL_STUFF
12354359Sroberto#include <linux/serial.h>
12454359Sroberto#endif
12554359Sroberto#endif
12654359Sroberto
12754359Sroberto#include "ntp_io.h"
12854359Sroberto#include "ntp_stdlib.h"
12954359Sroberto
13054359Sroberto#include "parse.h"
13154359Sroberto#include "mbg_gps166.h"
13254359Sroberto#include "trimble.h"
13354359Sroberto#include "binio.h"
13454359Sroberto#include "ascii.h"
13554359Sroberto#include "ieee754io.h"
13654359Sroberto
13756746Srobertostatic char rcsid[]="refclock_parse.c,v 4.36 1999/11/28 17:18:20 kardel RELEASE_19991128_A";
13854359Sroberto
13954359Sroberto/**===========================================================================
14054359Sroberto ** external interface to ntp mechanism
14154359Sroberto **/
14254359Sroberto
14354359Srobertostatic	void	parse_init	P((void));
14454359Srobertostatic	int	parse_start	P((int, struct peer *));
14554359Srobertostatic	void	parse_shutdown	P((int, struct peer *));
14654359Srobertostatic	void	parse_poll	P((int, struct peer *));
14754359Srobertostatic	void	parse_control	P((int, struct refclockstat *, struct refclockstat *, struct peer *));
14854359Sroberto
14954359Sroberto#define	parse_buginfo	noentry
15054359Sroberto
15154359Srobertostruct	refclock refclock_parse = {
15254359Sroberto	parse_start,
15354359Sroberto	parse_shutdown,
15454359Sroberto	parse_poll,
15554359Sroberto	parse_control,
15654359Sroberto	parse_init,
15754359Sroberto	parse_buginfo,
15854359Sroberto	NOFLAGS
15954359Sroberto};
16054359Sroberto
16154359Sroberto/*
16254359Sroberto * Definitions
16354359Sroberto */
16454359Sroberto#define	MAXUNITS	4	/* maximum number of "PARSE" units permitted */
16554359Sroberto#define PARSEDEVICE	"/dev/refclock-%d" /* device to open %d is unit number */
16654359Sroberto
16754359Sroberto#undef ABS
16854359Sroberto#define ABS(_X_) (((_X_) < 0) ? -(_X_) : (_X_))
16954359Sroberto
17054359Sroberto/**===========================================================================
17154359Sroberto ** function vector for dynamically binding io handling mechanism
17254359Sroberto **/
17354359Sroberto
17454359Srobertostruct parseunit;		/* to keep inquiring minds happy */
17554359Sroberto
17654359Srobertotypedef struct bind
17754359Sroberto{
17854359Sroberto  const char *bd_description;	                                /* name of type of binding */
17954359Sroberto  int	(*bd_init)     P((struct parseunit *));			/* initialize */
18054359Sroberto  void	(*bd_end)      P((struct parseunit *));			/* end */
18154359Sroberto  int   (*bd_setcs)    P((struct parseunit *, parsectl_t *));	/* set character size */
18254359Sroberto  int	(*bd_disable)  P((struct parseunit *));			/* disable */
18354359Sroberto  int	(*bd_enable)   P((struct parseunit *));			/* enable */
18454359Sroberto  int	(*bd_getfmt)   P((struct parseunit *, parsectl_t *));	/* get format */
18554359Sroberto  int	(*bd_setfmt)   P((struct parseunit *, parsectl_t *));	/* setfmt */
18654359Sroberto  int	(*bd_timecode) P((struct parseunit *, parsectl_t *));	/* get time code */
18754359Sroberto  void	(*bd_receive)  P((struct recvbuf *));			/* receive operation */
18854359Sroberto  int	(*bd_io_input) P((struct recvbuf *));			/* input operation */
18954359Sroberto} bind_t;
19054359Sroberto
19154359Sroberto#define PARSE_END(_X_)			(*(_X_)->binding->bd_end)(_X_)
19254359Sroberto#define PARSE_SETCS(_X_, _CS_)		(*(_X_)->binding->bd_setcs)(_X_, _CS_)
19354359Sroberto#define PARSE_ENABLE(_X_)		(*(_X_)->binding->bd_enable)(_X_)
19454359Sroberto#define PARSE_DISABLE(_X_)		(*(_X_)->binding->bd_disable)(_X_)
19554359Sroberto#define PARSE_GETFMT(_X_, _DCT_)	(*(_X_)->binding->bd_getfmt)(_X_, _DCT_)
19654359Sroberto#define PARSE_SETFMT(_X_, _DCT_)	(*(_X_)->binding->bd_setfmt)(_X_, _DCT_)
19754359Sroberto#define PARSE_GETTIMECODE(_X_, _DCT_)	(*(_X_)->binding->bd_timecode)(_X_, _DCT_)
19854359Sroberto
19954359Sroberto/*
20054359Sroberto * io modes
20154359Sroberto */
20254359Sroberto#define PARSE_F_PPSPPS		0x0001 /* use loopfilter PPS code (CIOGETEV) */
20354359Sroberto#define PARSE_F_PPSONSECOND	0x0002 /* PPS pulses are on second */
20454359Sroberto
20554359Sroberto
20654359Sroberto/**===========================================================================
20754359Sroberto ** error message regression handling
20854359Sroberto **
20954359Sroberto ** there are quite a few errors that can occur in rapid succession such as
21054359Sroberto ** noisy input data or no data at all. in order to reduce the amount of
21154359Sroberto ** syslog messages in such case, we are using a backoff algorithm. We limit
21254359Sroberto ** the number of error messages of a certain class to 1 per time unit. if a
21354359Sroberto ** configurable number of messages is displayed that way, we move on to the
21454359Sroberto ** next time unit / count for that class. a count of messages that have been
21554359Sroberto ** suppressed is held and displayed whenever a corresponding message is
21654359Sroberto ** displayed. the time units for a message class will also be displayed.
21754359Sroberto ** whenever an error condition clears we reset the error message state,
21854359Sroberto ** thus we would still generate much output on pathological conditions
21954359Sroberto ** where the system oscillates between OK and NOT OK states. coping
22054359Sroberto ** with that condition is currently considered too complicated.
22154359Sroberto **/
22254359Sroberto
22354359Sroberto#define ERR_ALL	        (unsigned)~0	/* "all" errors */
22454359Sroberto#define ERR_BADDATA	(unsigned)0	/* unusable input data/conversion errors */
22554359Sroberto#define ERR_NODATA	(unsigned)1	/* no input data */
22654359Sroberto#define ERR_BADIO	(unsigned)2	/* read/write/select errors */
22754359Sroberto#define ERR_BADSTATUS	(unsigned)3	/* unsync states */
22854359Sroberto#define ERR_BADEVENT	(unsigned)4	/* non nominal events */
22954359Sroberto#define ERR_INTERNAL	(unsigned)5	/* internal error */
23054359Sroberto#define ERR_CNT		(unsigned)(ERR_INTERNAL+1)
23154359Sroberto
23254359Sroberto#define ERR(_X_)	if (list_err(parse, (_X_)))
23354359Sroberto
23454359Srobertostruct errorregression
23554359Sroberto{
23654359Sroberto	u_long err_count;	/* number of repititions per class */
23754359Sroberto	u_long err_delay;	/* minimum delay between messages */
23854359Sroberto};
23954359Sroberto
24054359Srobertostatic struct errorregression
24154359Srobertoerr_baddata[] =			/* error messages for bad input data */
24254359Sroberto{
24354359Sroberto	{ 1,       0 },		/* output first message immediately */
24454359Sroberto	{ 5,      60 },		/* output next five messages in 60 second intervals */
24554359Sroberto	{ 3,    3600 },		/* output next 3 messages in hour intervals */
24654359Sroberto	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
24754359Sroberto};
24854359Sroberto
24954359Srobertostatic struct errorregression
25054359Srobertoerr_nodata[] =			/* error messages for missing input data */
25154359Sroberto{
25254359Sroberto	{ 1,       0 },		/* output first message immediately */
25354359Sroberto	{ 5,      60 },		/* output next five messages in 60 second intervals */
25454359Sroberto	{ 3,    3600 },		/* output next 3 messages in hour intervals */
25554359Sroberto	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
25654359Sroberto};
25754359Sroberto
25854359Srobertostatic struct errorregression
25954359Srobertoerr_badstatus[] =		/* unsynchronized state messages */
26054359Sroberto{
26154359Sroberto	{ 1,       0 },		/* output first message immediately */
26254359Sroberto	{ 5,      60 },		/* output next five messages in 60 second intervals */
26354359Sroberto	{ 3,    3600 },		/* output next 3 messages in hour intervals */
26454359Sroberto	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
26554359Sroberto};
26654359Sroberto
26754359Srobertostatic struct errorregression
26854359Srobertoerr_badio[] =			/* io failures (bad reads, selects, ...) */
26954359Sroberto{
27054359Sroberto	{ 1,       0 },		/* output first message immediately */
27154359Sroberto	{ 5,      60 },		/* output next five messages in 60 second intervals */
27254359Sroberto	{ 5,    3600 },		/* output next 3 messages in hour intervals */
27354359Sroberto	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
27454359Sroberto};
27554359Sroberto
27654359Srobertostatic struct errorregression
27754359Srobertoerr_badevent[] =		/* non nominal events */
27854359Sroberto{
27954359Sroberto	{ 20,      0 },		/* output first message immediately */
28054359Sroberto	{ 6,      60 },		/* output next five messages in 60 second intervals */
28154359Sroberto	{ 5,    3600 },		/* output next 3 messages in hour intervals */
28254359Sroberto	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
28354359Sroberto};
28454359Sroberto
28554359Srobertostatic struct errorregression
28654359Srobertoerr_internal[] =		/* really bad things - basically coding/OS errors */
28754359Sroberto{
28854359Sroberto	{ 0,       0 },		/* output all messages immediately */
28954359Sroberto};
29054359Sroberto
29154359Srobertostatic struct errorregression *
29254359Srobertoerr_tbl[] =
29354359Sroberto{
29454359Sroberto	err_baddata,
29554359Sroberto	err_nodata,
29654359Sroberto	err_badio,
29754359Sroberto	err_badstatus,
29854359Sroberto	err_badevent,
29954359Sroberto	err_internal
30054359Sroberto};
30154359Sroberto
30254359Srobertostruct errorinfo
30354359Sroberto{
30454359Sroberto	u_long err_started;	/* begin time (ntp) of error condition */
30554359Sroberto	u_long err_last;	/* last time (ntp) error occurred */
30654359Sroberto	u_long err_cnt;	/* number of error repititions */
30754359Sroberto	u_long err_suppressed;	/* number of suppressed messages */
30854359Sroberto	struct errorregression *err_stage; /* current error stage */
30954359Sroberto};
31054359Sroberto
31154359Sroberto/**===========================================================================
31254359Sroberto ** refclock instance data
31354359Sroberto **/
31454359Sroberto
31554359Srobertostruct parseunit
31654359Sroberto{
31754359Sroberto	/*
31854359Sroberto	 * NTP management
31954359Sroberto	 */
32054359Sroberto	struct peer         *peer;		/* backlink to peer structure - refclock inactive if 0  */
32154359Sroberto	struct refclockproc *generic;		/* backlink to refclockproc structure */
32254359Sroberto
32354359Sroberto	/*
32454359Sroberto	 * PARSE io
32554359Sroberto	 */
32654359Sroberto	bind_t	     *binding;	        /* io handling binding */
32754359Sroberto
32854359Sroberto	/*
32954359Sroberto	 * parse state
33054359Sroberto	 */
33154359Sroberto	parse_t	      parseio;	        /* io handling structure (user level parsing) */
33254359Sroberto
33354359Sroberto	/*
33454359Sroberto	 * type specific parameters
33554359Sroberto	 */
33654359Sroberto	struct parse_clockinfo   *parse_type;	        /* link to clock description */
33754359Sroberto
33854359Sroberto	/*
33954359Sroberto	 * clock state handling/reporting
34054359Sroberto	 */
34154359Sroberto	u_char	      flags;	        /* flags (leap_control) */
34254359Sroberto	u_long	      lastchange;       /* time (ntp) when last state change accured */
34354359Sroberto	u_long	      statetime[CEVNT_MAX+1]; /* accumulated time of clock states */
34456746Sroberto	u_long        pollneeddata; 	/* current_time(!=0) for receive sample expected in PPS mode */
34554359Sroberto	u_short	      lastformat;       /* last format used */
34654359Sroberto	u_long        lastsync;		/* time (ntp) when clock was last seen fully synchronized */
34754359Sroberto	u_long        lastmissed;       /* time (ntp) when poll didn't get data (powerup heuristic) */
34854359Sroberto	u_long        ppsserial;        /* magic cookie for ppsclock serials (avoids stale ppsclock data) */
34954359Sroberto	parsetime_t   time;		/* last (parse module) data */
35054359Sroberto	void         *localdata;        /* optional local, receiver-specific data */
35154359Sroberto        unsigned long localstate;       /* private local state */
35254359Sroberto	struct errorinfo errors[ERR_CNT];  /* error state table for suppressing excessive error messages */
35354359Sroberto	struct ctl_var *kv;	        /* additional pseudo variables */
35454359Sroberto	u_long        laststatistic;    /* time when staticstics where output */
35554359Sroberto};
35654359Sroberto
35754359Sroberto
35854359Sroberto/**===========================================================================
35954359Sroberto ** Clockinfo section all parameter for specific clock types
36054359Sroberto ** includes NTP parameters, TTY parameters and IO handling parameters
36154359Sroberto **/
36254359Sroberto
36354359Srobertostatic	void	poll_dpoll	P((struct parseunit *));
36454359Srobertostatic	void	poll_poll	P((struct peer *));
36554359Srobertostatic	int	poll_init	P((struct parseunit *));
36654359Sroberto
36754359Srobertotypedef struct poll_info
36854359Sroberto{
36954359Sroberto	u_long      rate;		/* poll rate - once every "rate" seconds - 0 off */
37054359Sroberto	const char *string;		/* string to send for polling */
37154359Sroberto	u_long      count;		/* number of characters in string */
37254359Sroberto} poll_info_t;
37354359Sroberto
37454359Sroberto#define NO_CL_FLAGS	0
37554359Sroberto#define NO_POLL		0
37654359Sroberto#define NO_INIT		0
37754359Sroberto#define NO_END		0
37854359Sroberto#define NO_EVENT	0
37954359Sroberto#define NO_DATA		0
38054359Sroberto#define NO_MESSAGE	0
38154359Sroberto#define NO_PPSDELAY     0
38254359Sroberto
38354359Sroberto#define DCF_ID		"DCF"	/* generic DCF */
38454359Sroberto#define DCF_A_ID	"DCFa"	/* AM demodulation */
38554359Sroberto#define DCF_P_ID	"DCFp"	/* psuedo random phase shift */
38654359Sroberto#define GPS_ID		"GPS"	/* GPS receiver */
38754359Sroberto
38854359Sroberto#define	NOCLOCK_ROOTDELAY	0.0
38954359Sroberto#define	NOCLOCK_BASEDELAY	0.0
39054359Sroberto#define	NOCLOCK_DESCRIPTION	0
39154359Sroberto#define NOCLOCK_MAXUNSYNC       0
39254359Sroberto#define NOCLOCK_CFLAG           0
39354359Sroberto#define NOCLOCK_IFLAG           0
39454359Sroberto#define NOCLOCK_OFLAG           0
39554359Sroberto#define NOCLOCK_LFLAG           0
39654359Sroberto#define NOCLOCK_ID		"TILT"
39754359Sroberto#define NOCLOCK_POLL		NO_POLL
39854359Sroberto#define NOCLOCK_INIT		NO_INIT
39954359Sroberto#define NOCLOCK_END		NO_END
40054359Sroberto#define NOCLOCK_DATA		NO_DATA
40154359Sroberto#define NOCLOCK_FORMAT		""
40254359Sroberto#define NOCLOCK_TYPE		CTL_SST_TS_UNSPEC
40354359Sroberto#define NOCLOCK_SAMPLES		0
40454359Sroberto#define NOCLOCK_KEEP		0
40554359Sroberto
40654359Sroberto#define DCF_TYPE		CTL_SST_TS_LF
40754359Sroberto#define GPS_TYPE		CTL_SST_TS_UHF
40854359Sroberto
40954359Sroberto/*
41054359Sroberto * receiver specific constants
41154359Sroberto */
41254359Sroberto#define MBG_SPEED		(B9600)
41354359Sroberto#define MBG_CFLAG		(CS7|PARENB|CREAD|CLOCAL|HUPCL)
41454359Sroberto#define MBG_IFLAG		(IGNBRK|IGNPAR|ISTRIP)
41554359Sroberto#define MBG_OFLAG		0
41654359Sroberto#define MBG_LFLAG		0
41754359Sroberto#define MBG_FLAGS               PARSE_F_PPSONSECOND
41854359Sroberto
41954359Sroberto/*
42054359Sroberto * Meinberg DCF77 receivers
42154359Sroberto */
42254359Sroberto#define	DCFUA31_ROOTDELAY	0.0  /* 0 */
42354359Sroberto#define	DCFUA31_BASEDELAY	0.010  /* 10.7421875ms: 10 ms (+/- 3 ms) */
42454359Sroberto#define	DCFUA31_DESCRIPTION	"Meinberg DCF77 C51 or compatible"
42554359Sroberto#define DCFUA31_MAXUNSYNC       60*30       /* only trust clock for 1/2 hour */
42654359Sroberto#define DCFUA31_SPEED		MBG_SPEED
42754359Sroberto#define DCFUA31_CFLAG           MBG_CFLAG
42854359Sroberto#define DCFUA31_IFLAG           MBG_IFLAG
42954359Sroberto#define DCFUA31_OFLAG           MBG_OFLAG
43054359Sroberto#define DCFUA31_LFLAG           MBG_LFLAG
43154359Sroberto#define DCFUA31_SAMPLES		5
43254359Sroberto#define DCFUA31_KEEP		3
43354359Sroberto#define DCFUA31_FORMAT		"Meinberg Standard"
43454359Sroberto
43554359Sroberto/*
43654359Sroberto * Meinberg DCF PZF535/TCXO (FM/PZF) receiver
43754359Sroberto */
43854359Sroberto#define	DCFPZF535_ROOTDELAY	0.0
43954359Sroberto#define	DCFPZF535_BASEDELAY	0.001968  /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
44054359Sroberto#define	DCFPZF535_DESCRIPTION	"Meinberg DCF PZF 535/509 / TCXO"
44154359Sroberto#define DCFPZF535_MAXUNSYNC     60*60*12           /* only trust clock for 12 hours
44254359Sroberto						    * @ 5e-8df/f we have accumulated
44354359Sroberto						    * at most 2.16 ms (thus we move to
44454359Sroberto						    * NTP synchronisation */
44554359Sroberto#define DCFPZF535_SPEED		MBG_SPEED
44654359Sroberto#define DCFPZF535_CFLAG         MBG_CFLAG
44754359Sroberto#define DCFPZF535_IFLAG         MBG_IFLAG
44854359Sroberto#define DCFPZF535_OFLAG         MBG_OFLAG
44954359Sroberto#define DCFPZF535_LFLAG         MBG_LFLAG
45054359Sroberto#define DCFPZF535_SAMPLES	       5
45154359Sroberto#define DCFPZF535_KEEP		       3
45254359Sroberto#define DCFPZF535_FORMAT	"Meinberg Standard"
45354359Sroberto
45454359Sroberto/*
45554359Sroberto * Meinberg DCF PZF535/OCXO receiver
45654359Sroberto */
45754359Sroberto#define	DCFPZF535OCXO_ROOTDELAY	0.0
45854359Sroberto#define	DCFPZF535OCXO_BASEDELAY	0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
45954359Sroberto#define	DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/509 / OCXO"
46054359Sroberto#define DCFPZF535OCXO_MAXUNSYNC     60*60*96       /* only trust clock for 4 days
46154359Sroberto						    * @ 5e-9df/f we have accumulated
46254359Sroberto						    * at most an error of 1.73 ms
46354359Sroberto						    * (thus we move to NTP synchronisation) */
46454359Sroberto#define DCFPZF535OCXO_SPEED	    MBG_SPEED
46554359Sroberto#define DCFPZF535OCXO_CFLAG         MBG_CFLAG
46654359Sroberto#define DCFPZF535OCXO_IFLAG         MBG_IFLAG
46754359Sroberto#define DCFPZF535OCXO_OFLAG         MBG_OFLAG
46854359Sroberto#define DCFPZF535OCXO_LFLAG         MBG_LFLAG
46954359Sroberto#define DCFPZF535OCXO_SAMPLES		   5
47054359Sroberto#define DCFPZF535OCXO_KEEP	           3
47154359Sroberto#define DCFPZF535OCXO_FORMAT	    "Meinberg Standard"
47254359Sroberto
47354359Sroberto/*
47454359Sroberto * Meinberg GPS16X receiver
47554359Sroberto */
47654359Srobertostatic	void	gps16x_message	 P((struct parseunit *, parsetime_t *));
47754359Srobertostatic  int     gps16x_poll_init P((struct parseunit *));
47854359Sroberto
47954359Sroberto#define	GPS16X_ROOTDELAY	0.0         /* nothing here */
48054359Sroberto#define	GPS16X_BASEDELAY	0.001968         /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
48154359Sroberto#define	GPS16X_DESCRIPTION      "Meinberg GPS16x receiver"
48254359Sroberto#define GPS16X_MAXUNSYNC        60*60*96       /* only trust clock for 4 days
48354359Sroberto						* @ 5e-9df/f we have accumulated
48454359Sroberto						* at most an error of 1.73 ms
48554359Sroberto						* (thus we move to NTP synchronisation) */
48654359Sroberto#define GPS16X_SPEED		B19200
48754359Sroberto#define GPS16X_CFLAG            (CS8|CREAD|CLOCAL|HUPCL)
48854359Sroberto#define GPS16X_IFLAG            (IGNBRK|IGNPAR)
48954359Sroberto#define GPS16X_OFLAG            MBG_OFLAG
49054359Sroberto#define GPS16X_LFLAG            MBG_LFLAG
49154359Sroberto#define GPS16X_POLLRATE	6
49254359Sroberto#define GPS16X_POLLCMD	""
49354359Sroberto#define GPS16X_CMDSIZE	0
49454359Sroberto
49554359Srobertostatic poll_info_t gps16x_pollinfo = { GPS16X_POLLRATE, GPS16X_POLLCMD, GPS16X_CMDSIZE };
49654359Sroberto
49754359Sroberto#define GPS16X_INIT		gps16x_poll_init
49854359Sroberto#define GPS16X_POLL	        0
49954359Sroberto#define GPS16X_END		0
50054359Sroberto#define GPS16X_DATA		((void *)(&gps16x_pollinfo))
50154359Sroberto#define GPS16X_MESSAGE		gps16x_message
50254359Sroberto#define GPS16X_ID		GPS_ID
50354359Sroberto#define GPS16X_FORMAT		"Meinberg GPS Extended"
50454359Sroberto#define GPS16X_SAMPLES		5
50554359Sroberto#define GPS16X_KEEP		3
50654359Sroberto
50754359Sroberto/*
50854359Sroberto * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit)
50954359Sroberto *
51054359Sroberto * This is really not the hottest clock - but before you have nothing ...
51154359Sroberto */
51254359Sroberto#define DCF7000_ROOTDELAY	0.0 /* 0 */
51354359Sroberto#define DCF7000_BASEDELAY	0.405 /* slow blow */
51454359Sroberto#define DCF7000_DESCRIPTION	"ELV DCF7000"
51554359Sroberto#define DCF7000_MAXUNSYNC	(60*5) /* sorry - but it just was not build as a clock */
51654359Sroberto#define DCF7000_SPEED		(B9600)
51754359Sroberto#define DCF7000_CFLAG           (CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL)
51854359Sroberto#define DCF7000_IFLAG		(IGNBRK)
51954359Sroberto#define DCF7000_OFLAG		0
52054359Sroberto#define DCF7000_LFLAG		0
52154359Sroberto#define DCF7000_SAMPLES		5
52254359Sroberto#define DCF7000_KEEP		3
52354359Sroberto#define DCF7000_FORMAT		"ELV DCF7000"
52454359Sroberto
52554359Sroberto/*
52654359Sroberto * Schmid DCF Receiver Kit
52754359Sroberto *
52854359Sroberto * When the WSDCF clock is operating optimally we want the primary clock
52954359Sroberto * distance to come out at 300 ms.  Thus, peer.distance in the WSDCF peer
53054359Sroberto * structure is set to 290 ms and we compute delays which are at least
53154359Sroberto * 10 ms long.  The following are 290 ms and 10 ms expressed in u_fp format
53254359Sroberto */
53354359Sroberto#define WS_POLLRATE	1	/* every second - watch interdependency with poll routine */
53454359Sroberto#define WS_POLLCMD	"\163"
53554359Sroberto#define WS_CMDSIZE	1
53654359Sroberto
53754359Srobertostatic poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE };
53854359Sroberto
53954359Sroberto#define WSDCF_INIT		poll_init
54054359Sroberto#define WSDCF_POLL		poll_dpoll
54154359Sroberto#define WSDCF_END		0
54254359Sroberto#define WSDCF_DATA		((void *)(&wsdcf_pollinfo))
54354359Sroberto#define	WSDCF_ROOTDELAY		0.0	/* 0 */
54454359Sroberto#define	WSDCF_BASEDELAY	 	0.010	/*  ~  10ms */
54554359Sroberto#define WSDCF_DESCRIPTION	"WS/DCF Receiver"
54654359Sroberto#define WSDCF_FORMAT		"Schmid"
54754359Sroberto#define WSDCF_MAXUNSYNC		(60*60)	/* assume this beast hold at 1 h better than 2 ms XXX-must verify */
54854359Sroberto#define WSDCF_SPEED		(B1200)
54954359Sroberto#define WSDCF_CFLAG		(CS8|CREAD|CLOCAL)
55054359Sroberto#define WSDCF_IFLAG		0
55154359Sroberto#define WSDCF_OFLAG		0
55254359Sroberto#define WSDCF_LFLAG		0
55354359Sroberto#define WSDCF_SAMPLES		5
55454359Sroberto#define WSDCF_KEEP		3
55554359Sroberto
55654359Sroberto/*
55754359Sroberto * RAW DCF77 - input of DCF marks via RS232 - many variants
55854359Sroberto */
55954359Sroberto#define RAWDCF_FLAGS		0
56054359Sroberto#define RAWDCF_ROOTDELAY	0.0 /* 0 */
56154359Sroberto#define RAWDCF_BASEDELAY	0.258
56254359Sroberto#define RAWDCF_FORMAT		"RAW DCF77 Timecode"
56354359Sroberto#define RAWDCF_MAXUNSYNC	(0) /* sorry - its a true receiver - no signal - no time */
56454359Sroberto#define RAWDCF_SPEED		(B50)
56554359Sroberto#ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined(SYS_IRIX5) */
56654359Sroberto/* somehow doesn't grok PARENB & IGNPAR (mj) */
56754359Sroberto# define RAWDCF_CFLAG            (CS8|CREAD|CLOCAL)
56854359Sroberto#else
56954359Sroberto# define RAWDCF_CFLAG            (CS8|CREAD|CLOCAL|PARENB)
57054359Sroberto#endif
57154359Sroberto#ifdef RAWDCF_NO_IGNPAR /* Was: defined(SYS_LINUX) && defined(CLOCK_RAWDCF) */
57254359Sroberto# define RAWDCF_IFLAG		0
57354359Sroberto#else
57454359Sroberto# define RAWDCF_IFLAG		(IGNPAR)
57554359Sroberto#endif
57654359Sroberto#define RAWDCF_OFLAG		0
57754359Sroberto#define RAWDCF_LFLAG		0
57854359Sroberto#define RAWDCF_SAMPLES		20
57954359Sroberto#define RAWDCF_KEEP		12
58054359Sroberto#define RAWDCF_INIT		0
58154359Sroberto
58254359Sroberto/*
58354359Sroberto * RAW DCF variants
58454359Sroberto */
58554359Sroberto/*
58654359Sroberto * Conrad receiver
58754359Sroberto *
58854359Sroberto * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad
58954359Sroberto * (~40DM - roughly $30 ) followed by a level converter for RS232
59054359Sroberto */
59154359Sroberto#define CONRAD_BASEDELAY	0.292 /* Conrad receiver @ 50 Baud on a Sun */
59254359Sroberto#define CONRAD_DESCRIPTION	"RAW DCF77 CODE (Conrad DCF77 receiver module)"
59354359Sroberto
59454359Sroberto/*
59554359Sroberto * TimeBrick receiver
59654359Sroberto */
59754359Sroberto#define TIMEBRICK_BASEDELAY	0.210 /* TimeBrick @ 50 Baud on a Sun */
59854359Sroberto#define TIMEBRICK_DESCRIPTION	"RAW DCF77 CODE (TimeBrick)"
59954359Sroberto
60054359Sroberto/*
60154359Sroberto * IGEL:clock receiver
60254359Sroberto */
60354359Sroberto#define IGELCLOCK_BASEDELAY	0.258 /* IGEL:clock receiver */
60454359Sroberto#define IGELCLOCK_DESCRIPTION	"RAW DCF77 CODE (IGEL:clock)"
60554359Sroberto#define IGELCLOCK_SPEED		(B1200)
60654359Sroberto#define IGELCLOCK_CFLAG		(CS8|CREAD|HUPCL|CLOCAL)
60754359Sroberto
60854359Sroberto/*
60954359Sroberto * RAWDCF receivers that need to be powered from DTR
61054359Sroberto * (like Expert mouse clock)
61154359Sroberto */
61256746Srobertostatic	int	rawdcf_init_1	P((struct parseunit *));
61356746Sroberto#define RAWDCFDTRSET_DESCRIPTION	"RAW DCF77 CODE (DTR SET/RTS CLR)"
61456746Sroberto#define RAWDCFDTRSET_INIT 		rawdcf_init_1
61554359Sroberto
61654359Sroberto/*
61756746Sroberto * RAWDCF receivers that need to be powered from
61856746Sroberto * DTR CLR and RTS SET
61954359Sroberto */
62056746Srobertostatic	int	rawdcf_init_2	P((struct parseunit *));
62156746Sroberto#define RAWDCFDTRCLRRTSSET_DESCRIPTION	"RAW DCF77 CODE (DTR CLR/RTS SET)"
62256746Sroberto#define RAWDCFDTRCLRRTSSET_INIT	rawdcf_init_2
62354359Sroberto
62454359Sroberto/*
62554359Sroberto * Trimble GPS receivers (TAIP and TSIP protocols)
62654359Sroberto */
62754359Sroberto#ifndef TRIM_POLLRATE
62854359Sroberto#define TRIM_POLLRATE	0	/* only true direct polling */
62954359Sroberto#endif
63054359Sroberto
63154359Sroberto#define TRIM_TAIPPOLLCMD	">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<"
63254359Sroberto#define TRIM_TAIPCMDSIZE	(sizeof(TRIM_TAIPPOLLCMD)-1)
63354359Sroberto
63454359Srobertostatic poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE };
63554359Srobertostatic	int	trimbletaip_init	P((struct parseunit *));
63654359Srobertostatic	void	trimbletaip_event	P((struct parseunit *, int));
63754359Sroberto
63854359Sroberto/* query time & UTC correction data */
63954359Srobertostatic char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX };
64054359Sroberto
64154359Srobertostatic poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) };
64254359Srobertostatic	int	trimbletsip_init	P((struct parseunit *));
64354359Srobertostatic	void	trimbletsip_end   	P((struct parseunit *));
64454359Srobertostatic	void	trimbletsip_message	P((struct parseunit *, parsetime_t *));
64554359Srobertostatic	void	trimbletsip_event	P((struct parseunit *, int));
64654359Sroberto
64754359Sroberto#define TRIMBLETSIP_IDLE_TIME	    (300) /* 5 minutes silence at most */
64854359Sroberto
64954359Sroberto#define TRIMBLETAIP_SPEED	    (B4800)
65054359Sroberto#define TRIMBLETAIP_CFLAG           (CS8|CREAD|CLOCAL)
65154359Sroberto#define TRIMBLETAIP_IFLAG           (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON)
65254359Sroberto#define TRIMBLETAIP_OFLAG           (OPOST|ONLCR)
65354359Sroberto#define TRIMBLETAIP_LFLAG           (0)
65454359Sroberto
65554359Sroberto#define TRIMBLETSIP_SPEED	    (B9600)
65654359Sroberto#define TRIMBLETSIP_CFLAG           (CS8|CLOCAL|CREAD|PARENB|PARODD)
65754359Sroberto#define TRIMBLETSIP_IFLAG           (IGNBRK)
65854359Sroberto#define TRIMBLETSIP_OFLAG           (0)
65954359Sroberto#define TRIMBLETSIP_LFLAG           (ICANON)
66054359Sroberto
66154359Sroberto#define TRIMBLETSIP_SAMPLES	    5
66254359Sroberto#define TRIMBLETSIP_KEEP	    3
66354359Sroberto#define TRIMBLETAIP_SAMPLES	    5
66454359Sroberto#define TRIMBLETAIP_KEEP	    3
66554359Sroberto
66654359Sroberto#define TRIMBLETAIP_FLAGS	    (PARSE_F_PPSONSECOND)
66754359Sroberto#define TRIMBLETSIP_FLAGS	    (TRIMBLETAIP_FLAGS)
66854359Sroberto
66954359Sroberto#define TRIMBLETAIP_POLL	    poll_dpoll
67054359Sroberto#define TRIMBLETSIP_POLL	    poll_dpoll
67154359Sroberto
67254359Sroberto#define TRIMBLETAIP_INIT	    trimbletaip_init
67354359Sroberto#define TRIMBLETSIP_INIT	    trimbletsip_init
67454359Sroberto
67554359Sroberto#define TRIMBLETAIP_EVENT	    trimbletaip_event
67654359Sroberto
67754359Sroberto#define TRIMBLETSIP_EVENT	    trimbletsip_event
67854359Sroberto#define TRIMBLETSIP_MESSAGE	    trimbletsip_message
67954359Sroberto
68054359Sroberto#define TRIMBLETAIP_END		    0
68154359Sroberto#define TRIMBLETSIP_END		    trimbletsip_end
68254359Sroberto
68354359Sroberto#define TRIMBLETAIP_DATA	    ((void *)(&trimbletaip_pollinfo))
68454359Sroberto#define TRIMBLETSIP_DATA	    ((void *)(&trimbletsip_pollinfo))
68554359Sroberto
68654359Sroberto#define TRIMBLETAIP_ID		    GPS_ID
68754359Sroberto#define TRIMBLETSIP_ID		    GPS_ID
68854359Sroberto
68954359Sroberto#define TRIMBLETAIP_FORMAT	    "Trimble TAIP"
69054359Sroberto#define TRIMBLETSIP_FORMAT	    "Trimble TSIP"
69154359Sroberto
69254359Sroberto#define TRIMBLETAIP_ROOTDELAY        0x0
69354359Sroberto#define TRIMBLETSIP_ROOTDELAY        0x0
69454359Sroberto
69554359Sroberto#define TRIMBLETAIP_BASEDELAY        0.0
69654359Sroberto#define TRIMBLETSIP_BASEDELAY        0.020	/* GPS time message latency */
69754359Sroberto
69854359Sroberto#define TRIMBLETAIP_DESCRIPTION      "Trimble GPS (TAIP) receiver"
69954359Sroberto#define TRIMBLETSIP_DESCRIPTION      "Trimble GPS (TSIP) receiver"
70054359Sroberto
70154359Sroberto#define TRIMBLETAIP_MAXUNSYNC        0
70254359Sroberto#define TRIMBLETSIP_MAXUNSYNC        0
70354359Sroberto
70454359Sroberto#define TRIMBLETAIP_EOL		    '<'
70554359Sroberto
70654359Sroberto/*
70754359Sroberto * RadioCode Clocks RCC 800 receiver
70854359Sroberto */
70954359Sroberto#define RCC_POLLRATE   0       /* only true direct polling */
71054359Sroberto#define RCC_POLLCMD    "\r"
71154359Sroberto#define RCC_CMDSIZE    1
71254359Sroberto
71354359Srobertostatic poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE };
71454359Sroberto#define RCC8000_FLAGS		0
71554359Sroberto#define RCC8000_POLL            poll_dpoll
71654359Sroberto#define RCC8000_INIT            poll_init
71754359Sroberto#define RCC8000_END             0
71854359Sroberto#define RCC8000_DATA            ((void *)(&rcc8000_pollinfo))
71954359Sroberto#define RCC8000_ROOTDELAY       0.0
72054359Sroberto#define RCC8000_BASEDELAY       0.0
72154359Sroberto#define RCC8000_ID              "MSF"
72254359Sroberto#define RCC8000_DESCRIPTION     "RCC 8000 MSF Receiver"
72354359Sroberto#define RCC8000_FORMAT          "Radiocode RCC8000"
72454359Sroberto#define RCC8000_MAXUNSYNC       (60*60) /* should be ok for an hour */
72554359Sroberto#define RCC8000_SPEED		(B2400)
72654359Sroberto#define RCC8000_CFLAG           (CS8|CREAD|CLOCAL)
72754359Sroberto#define RCC8000_IFLAG           (IGNBRK|IGNPAR)
72854359Sroberto#define RCC8000_OFLAG           0
72954359Sroberto#define RCC8000_LFLAG           0
73054359Sroberto#define RCC8000_SAMPLES         5
73154359Sroberto#define RCC8000_KEEP	        3
73254359Sroberto
73354359Sroberto/*
73454359Sroberto * Hopf Radio clock 6021 Format
73554359Sroberto *
73654359Sroberto */
73754359Sroberto#define HOPF6021_ROOTDELAY	0.0
73854359Sroberto#define HOPF6021_BASEDELAY	0.0
73954359Sroberto#define HOPF6021_DESCRIPTION	"HOPF 6021"
74054359Sroberto#define HOPF6021_FORMAT         "hopf Funkuhr 6021"
74154359Sroberto#define HOPF6021_MAXUNSYNC	(60*60)  /* should be ok for an hour */
74254359Sroberto#define HOPF6021_SPEED         (B9600)
74354359Sroberto#define HOPF6021_CFLAG          (CS8|CREAD|CLOCAL)
74454359Sroberto#define HOPF6021_IFLAG		(IGNBRK|ISTRIP)
74554359Sroberto#define HOPF6021_OFLAG		0
74654359Sroberto#define HOPF6021_LFLAG		0
74754359Sroberto#define HOPF6021_FLAGS          0
74854359Sroberto#define HOPF6021_SAMPLES        5
74954359Sroberto#define HOPF6021_KEEP	        3
75054359Sroberto
75154359Sroberto/*
75254359Sroberto * Diem's Computime Radio Clock Receiver
75354359Sroberto */
75454359Sroberto#define COMPUTIME_FLAGS       0
75554359Sroberto#define COMPUTIME_ROOTDELAY   0.0
75654359Sroberto#define COMPUTIME_BASEDELAY   0.0
75754359Sroberto#define COMPUTIME_ID          DCF_ID
75854359Sroberto#define COMPUTIME_DESCRIPTION "Diem's Computime receiver"
75954359Sroberto#define COMPUTIME_FORMAT      "Diem's Computime Radio Clock"
76054359Sroberto#define COMPUTIME_TYPE        DCF_TYPE
76154359Sroberto#define COMPUTIME_MAXUNSYNC   (60*60)       /* only trust clock for 1 hour */
76254359Sroberto#define COMPUTIME_SPEED       (B9600)
76354359Sroberto#define COMPUTIME_CFLAG       (CSTOPB|CS7|CREAD|CLOCAL)
76454359Sroberto#define COMPUTIME_IFLAG       (IGNBRK|IGNPAR|ISTRIP)
76554359Sroberto#define COMPUTIME_OFLAG       0
76654359Sroberto#define COMPUTIME_LFLAG       0
76754359Sroberto#define COMPUTIME_SAMPLES     5
76854359Sroberto#define COMPUTIME_KEEP        3
76954359Sroberto
77056746Srobertostatic poll_info_t we400a_pollinfo = { 60, "T", 1 };
77156746Sroberto
77254359Sroberto/*
77354359Sroberto * Varitext Radio Clock Receiver
77454359Sroberto */
77554359Sroberto#define VARITEXT_FLAGS       0
77654359Sroberto#define VARITEXT_ROOTDELAY   0.0
77754359Sroberto#define VARITEXT_BASEDELAY   0.0
77854359Sroberto#define VARITEXT_ID          "MSF"
77954359Sroberto#define VARITEXT_DESCRIPTION "Varitext receiver"
78054359Sroberto#define VARITEXT_FORMAT      "Varitext Radio Clock"
78154359Sroberto#define VARITEXT_TYPE        DCF_TYPE
78254359Sroberto#define VARITEXT_MAXUNSYNC   (60*60)       /* only trust clock for 1 hour */
78354359Sroberto#define VARITEXT_SPEED       (B9600)
78454359Sroberto#define VARITEXT_CFLAG       (CS7|CREAD|CLOCAL|PARENB|PARODD)
78554359Sroberto#define VARITEXT_IFLAG       (IGNPAR|IGNBRK|INPCK) /*|ISTRIP)*/
78654359Sroberto#define VARITEXT_OFLAG       0
78754359Sroberto#define VARITEXT_LFLAG       0
78854359Sroberto#define VARITEXT_SAMPLES     32
78954359Sroberto#define VARITEXT_KEEP        20
79054359Sroberto
79154359Srobertostatic struct parse_clockinfo
79254359Sroberto{
79354359Sroberto	u_long  cl_flags;		/* operation flags (io modes) */
79454359Sroberto  void  (*cl_poll)    P((struct parseunit *));			/* active poll routine */
79554359Sroberto  int   (*cl_init)    P((struct parseunit *));			/* active poll init routine */
79654359Sroberto  void  (*cl_event)   P((struct parseunit *, int));		/* special event handling (e.g. reset clock) */
79754359Sroberto  void  (*cl_end)     P((struct parseunit *));			/* active poll end routine */
79854359Sroberto  void  (*cl_message) P((struct parseunit *, parsetime_t *));	/* process a lower layer message */
79954359Sroberto	void   *cl_data;		/* local data area for "poll" mechanism */
80054359Sroberto	double    cl_rootdelay;		/* rootdelay */
80154359Sroberto	double    cl_basedelay;		/* current offset by which the RS232
80254359Sroberto				time code is delayed from the actual time */
80354359Sroberto	const char *cl_id;		/* ID code */
80454359Sroberto	const char *cl_description;		/* device name */
80554359Sroberto	const char *cl_format;		/* fixed format */
80654359Sroberto	u_char  cl_type;		/* clock type (ntp control) */
80754359Sroberto	u_long  cl_maxunsync;		/* time to trust oscillator after loosing synch */
80854359Sroberto	u_long  cl_speed;		/* terminal input & output baudrate */
80954359Sroberto	u_long  cl_cflag;             /* terminal control flags */
81054359Sroberto	u_long  cl_iflag;             /* terminal input flags */
81154359Sroberto	u_long  cl_oflag;             /* terminal output flags */
81254359Sroberto	u_long  cl_lflag;             /* terminal local flags */
81354359Sroberto	u_long  cl_samples;	      /* samples for median filter */
81454359Sroberto	u_long  cl_keep;              /* samples for median filter to keep */
81554359Sroberto} parse_clockinfo[] =
81654359Sroberto{
81754359Sroberto	{				/* mode 0 */
81854359Sroberto		MBG_FLAGS,
81954359Sroberto		NO_POLL,
82054359Sroberto		NO_INIT,
82154359Sroberto		NO_EVENT,
82254359Sroberto		NO_END,
82354359Sroberto		NO_MESSAGE,
82454359Sroberto		NO_DATA,
82554359Sroberto		DCFPZF535_ROOTDELAY,
82654359Sroberto		DCFPZF535_BASEDELAY,
82754359Sroberto		DCF_P_ID,
82854359Sroberto		DCFPZF535_DESCRIPTION,
82954359Sroberto		DCFPZF535_FORMAT,
83054359Sroberto		DCF_TYPE,
83154359Sroberto		DCFPZF535_MAXUNSYNC,
83254359Sroberto		DCFPZF535_SPEED,
83354359Sroberto		DCFPZF535_CFLAG,
83454359Sroberto		DCFPZF535_IFLAG,
83554359Sroberto		DCFPZF535_OFLAG,
83654359Sroberto		DCFPZF535_LFLAG,
83754359Sroberto		DCFPZF535_SAMPLES,
83854359Sroberto		DCFPZF535_KEEP
83954359Sroberto	},
84054359Sroberto	{				/* mode 1 */
84154359Sroberto		MBG_FLAGS,
84254359Sroberto		NO_POLL,
84354359Sroberto		NO_INIT,
84454359Sroberto		NO_EVENT,
84554359Sroberto		NO_END,
84654359Sroberto		NO_MESSAGE,
84754359Sroberto		NO_DATA,
84854359Sroberto		DCFPZF535OCXO_ROOTDELAY,
84954359Sroberto		DCFPZF535OCXO_BASEDELAY,
85054359Sroberto		DCF_P_ID,
85154359Sroberto		DCFPZF535OCXO_DESCRIPTION,
85254359Sroberto		DCFPZF535OCXO_FORMAT,
85354359Sroberto		DCF_TYPE,
85454359Sroberto		DCFPZF535OCXO_MAXUNSYNC,
85554359Sroberto		DCFPZF535OCXO_SPEED,
85654359Sroberto		DCFPZF535OCXO_CFLAG,
85754359Sroberto		DCFPZF535OCXO_IFLAG,
85854359Sroberto		DCFPZF535OCXO_OFLAG,
85954359Sroberto		DCFPZF535OCXO_LFLAG,
86054359Sroberto		DCFPZF535OCXO_SAMPLES,
86154359Sroberto		DCFPZF535OCXO_KEEP
86254359Sroberto	},
86354359Sroberto	{				/* mode 2 */
86454359Sroberto		MBG_FLAGS,
86554359Sroberto		NO_POLL,
86654359Sroberto		NO_INIT,
86754359Sroberto		NO_EVENT,
86854359Sroberto		NO_END,
86954359Sroberto		NO_MESSAGE,
87054359Sroberto		NO_DATA,
87154359Sroberto		DCFUA31_ROOTDELAY,
87254359Sroberto		DCFUA31_BASEDELAY,
87354359Sroberto		DCF_A_ID,
87454359Sroberto		DCFUA31_DESCRIPTION,
87554359Sroberto		DCFUA31_FORMAT,
87654359Sroberto		DCF_TYPE,
87754359Sroberto		DCFUA31_MAXUNSYNC,
87854359Sroberto		DCFUA31_SPEED,
87954359Sroberto		DCFUA31_CFLAG,
88054359Sroberto		DCFUA31_IFLAG,
88154359Sroberto		DCFUA31_OFLAG,
88254359Sroberto		DCFUA31_LFLAG,
88354359Sroberto		DCFUA31_SAMPLES,
88454359Sroberto		DCFUA31_KEEP
88554359Sroberto	},
88654359Sroberto	{				/* mode 3 */
88754359Sroberto		MBG_FLAGS,
88854359Sroberto		NO_POLL,
88954359Sroberto		NO_INIT,
89054359Sroberto		NO_EVENT,
89154359Sroberto		NO_END,
89254359Sroberto		NO_MESSAGE,
89354359Sroberto		NO_DATA,
89454359Sroberto		DCF7000_ROOTDELAY,
89554359Sroberto		DCF7000_BASEDELAY,
89654359Sroberto		DCF_A_ID,
89754359Sroberto		DCF7000_DESCRIPTION,
89854359Sroberto		DCF7000_FORMAT,
89954359Sroberto		DCF_TYPE,
90054359Sroberto		DCF7000_MAXUNSYNC,
90154359Sroberto		DCF7000_SPEED,
90254359Sroberto		DCF7000_CFLAG,
90354359Sroberto		DCF7000_IFLAG,
90454359Sroberto		DCF7000_OFLAG,
90554359Sroberto		DCF7000_LFLAG,
90654359Sroberto		DCF7000_SAMPLES,
90754359Sroberto		DCF7000_KEEP
90854359Sroberto	},
90954359Sroberto	{				/* mode 4 */
91054359Sroberto		NO_CL_FLAGS,
91154359Sroberto		WSDCF_POLL,
91254359Sroberto		WSDCF_INIT,
91354359Sroberto		NO_EVENT,
91454359Sroberto		WSDCF_END,
91554359Sroberto		NO_MESSAGE,
91654359Sroberto		WSDCF_DATA,
91754359Sroberto		WSDCF_ROOTDELAY,
91854359Sroberto		WSDCF_BASEDELAY,
91954359Sroberto		DCF_A_ID,
92054359Sroberto		WSDCF_DESCRIPTION,
92154359Sroberto		WSDCF_FORMAT,
92254359Sroberto		DCF_TYPE,
92354359Sroberto		WSDCF_MAXUNSYNC,
92454359Sroberto		WSDCF_SPEED,
92554359Sroberto		WSDCF_CFLAG,
92654359Sroberto		WSDCF_IFLAG,
92754359Sroberto		WSDCF_OFLAG,
92854359Sroberto		WSDCF_LFLAG,
92954359Sroberto		WSDCF_SAMPLES,
93054359Sroberto		WSDCF_KEEP
93154359Sroberto	},
93254359Sroberto	{				/* mode 5 */
93354359Sroberto		RAWDCF_FLAGS,
93454359Sroberto		NO_POLL,
93554359Sroberto		RAWDCF_INIT,
93654359Sroberto		NO_EVENT,
93754359Sroberto		NO_END,
93854359Sroberto		NO_MESSAGE,
93954359Sroberto		NO_DATA,
94054359Sroberto		RAWDCF_ROOTDELAY,
94154359Sroberto		CONRAD_BASEDELAY,
94254359Sroberto		DCF_A_ID,
94354359Sroberto		CONRAD_DESCRIPTION,
94454359Sroberto		RAWDCF_FORMAT,
94554359Sroberto		DCF_TYPE,
94654359Sroberto		RAWDCF_MAXUNSYNC,
94754359Sroberto		RAWDCF_SPEED,
94854359Sroberto		RAWDCF_CFLAG,
94954359Sroberto		RAWDCF_IFLAG,
95054359Sroberto		RAWDCF_OFLAG,
95154359Sroberto		RAWDCF_LFLAG,
95254359Sroberto		RAWDCF_SAMPLES,
95354359Sroberto		RAWDCF_KEEP
95454359Sroberto	},
95554359Sroberto	{				/* mode 6 */
95654359Sroberto		RAWDCF_FLAGS,
95754359Sroberto		NO_POLL,
95854359Sroberto		RAWDCF_INIT,
95954359Sroberto		NO_EVENT,
96054359Sroberto		NO_END,
96154359Sroberto		NO_MESSAGE,
96254359Sroberto		NO_DATA,
96354359Sroberto		RAWDCF_ROOTDELAY,
96454359Sroberto		TIMEBRICK_BASEDELAY,
96554359Sroberto		DCF_A_ID,
96654359Sroberto		TIMEBRICK_DESCRIPTION,
96754359Sroberto		RAWDCF_FORMAT,
96854359Sroberto		DCF_TYPE,
96954359Sroberto		RAWDCF_MAXUNSYNC,
97054359Sroberto		RAWDCF_SPEED,
97154359Sroberto		RAWDCF_CFLAG,
97254359Sroberto		RAWDCF_IFLAG,
97354359Sroberto		RAWDCF_OFLAG,
97454359Sroberto		RAWDCF_LFLAG,
97554359Sroberto		RAWDCF_SAMPLES,
97654359Sroberto		RAWDCF_KEEP
97754359Sroberto	},
97854359Sroberto	{				/* mode 7 */
97954359Sroberto		MBG_FLAGS,
98054359Sroberto		GPS16X_POLL,
98154359Sroberto		GPS16X_INIT,
98254359Sroberto		NO_EVENT,
98354359Sroberto		GPS16X_END,
98454359Sroberto		GPS16X_MESSAGE,
98554359Sroberto		GPS16X_DATA,
98654359Sroberto		GPS16X_ROOTDELAY,
98754359Sroberto		GPS16X_BASEDELAY,
98854359Sroberto		GPS16X_ID,
98954359Sroberto		GPS16X_DESCRIPTION,
99054359Sroberto		GPS16X_FORMAT,
99154359Sroberto		GPS_TYPE,
99254359Sroberto		GPS16X_MAXUNSYNC,
99354359Sroberto		GPS16X_SPEED,
99454359Sroberto		GPS16X_CFLAG,
99554359Sroberto		GPS16X_IFLAG,
99654359Sroberto		GPS16X_OFLAG,
99754359Sroberto		GPS16X_LFLAG,
99854359Sroberto		GPS16X_SAMPLES,
99954359Sroberto		GPS16X_KEEP
100054359Sroberto	},
100154359Sroberto	{				/* mode 8 */
100254359Sroberto		RAWDCF_FLAGS,
100354359Sroberto		NO_POLL,
100454359Sroberto		NO_INIT,
100554359Sroberto		NO_EVENT,
100654359Sroberto		NO_END,
100754359Sroberto		NO_MESSAGE,
100854359Sroberto		NO_DATA,
100954359Sroberto		RAWDCF_ROOTDELAY,
101054359Sroberto		IGELCLOCK_BASEDELAY,
101154359Sroberto		DCF_A_ID,
101254359Sroberto		IGELCLOCK_DESCRIPTION,
101354359Sroberto		RAWDCF_FORMAT,
101454359Sroberto		DCF_TYPE,
101554359Sroberto		RAWDCF_MAXUNSYNC,
101654359Sroberto		IGELCLOCK_SPEED,
101754359Sroberto		IGELCLOCK_CFLAG,
101854359Sroberto		RAWDCF_IFLAG,
101954359Sroberto		RAWDCF_OFLAG,
102054359Sroberto		RAWDCF_LFLAG,
102154359Sroberto		RAWDCF_SAMPLES,
102254359Sroberto		RAWDCF_KEEP
102354359Sroberto	},
102454359Sroberto	{				/* mode 9 */
102554359Sroberto		TRIMBLETAIP_FLAGS,
102654359Sroberto#if TRIM_POLLRATE		/* DHD940515: Allow user config */
102754359Sroberto		NO_POLL,
102854359Sroberto#else
102954359Sroberto		TRIMBLETAIP_POLL,
103054359Sroberto#endif
103154359Sroberto		TRIMBLETAIP_INIT,
103254359Sroberto		TRIMBLETAIP_EVENT,
103354359Sroberto		TRIMBLETAIP_END,
103454359Sroberto		NO_MESSAGE,
103554359Sroberto		TRIMBLETAIP_DATA,
103654359Sroberto		TRIMBLETAIP_ROOTDELAY,
103754359Sroberto		TRIMBLETAIP_BASEDELAY,
103854359Sroberto		TRIMBLETAIP_ID,
103954359Sroberto		TRIMBLETAIP_DESCRIPTION,
104054359Sroberto		TRIMBLETAIP_FORMAT,
104154359Sroberto		GPS_TYPE,
104254359Sroberto		TRIMBLETAIP_MAXUNSYNC,
104354359Sroberto		TRIMBLETAIP_SPEED,
104454359Sroberto		TRIMBLETAIP_CFLAG,
104554359Sroberto		TRIMBLETAIP_IFLAG,
104654359Sroberto		TRIMBLETAIP_OFLAG,
104754359Sroberto		TRIMBLETAIP_LFLAG,
104854359Sroberto		TRIMBLETAIP_SAMPLES,
104954359Sroberto		TRIMBLETAIP_KEEP
105054359Sroberto	},
105154359Sroberto	{				/* mode 10 */
105254359Sroberto		TRIMBLETSIP_FLAGS,
105354359Sroberto#if TRIM_POLLRATE		/* DHD940515: Allow user config */
105454359Sroberto		NO_POLL,
105554359Sroberto#else
105654359Sroberto		TRIMBLETSIP_POLL,
105754359Sroberto#endif
105854359Sroberto		TRIMBLETSIP_INIT,
105954359Sroberto		TRIMBLETSIP_EVENT,
106054359Sroberto		TRIMBLETSIP_END,
106154359Sroberto		TRIMBLETSIP_MESSAGE,
106254359Sroberto		TRIMBLETSIP_DATA,
106354359Sroberto		TRIMBLETSIP_ROOTDELAY,
106454359Sroberto		TRIMBLETSIP_BASEDELAY,
106554359Sroberto		TRIMBLETSIP_ID,
106654359Sroberto		TRIMBLETSIP_DESCRIPTION,
106754359Sroberto		TRIMBLETSIP_FORMAT,
106854359Sroberto		GPS_TYPE,
106954359Sroberto		TRIMBLETSIP_MAXUNSYNC,
107054359Sroberto		TRIMBLETSIP_SPEED,
107154359Sroberto		TRIMBLETSIP_CFLAG,
107254359Sroberto		TRIMBLETSIP_IFLAG,
107354359Sroberto		TRIMBLETSIP_OFLAG,
107454359Sroberto		TRIMBLETSIP_LFLAG,
107554359Sroberto		TRIMBLETSIP_SAMPLES,
107654359Sroberto		TRIMBLETSIP_KEEP
107754359Sroberto	},
107854359Sroberto	{                             /* mode 11 */
107954359Sroberto		NO_CL_FLAGS,
108054359Sroberto		RCC8000_POLL,
108154359Sroberto		RCC8000_INIT,
108254359Sroberto		NO_EVENT,
108354359Sroberto		RCC8000_END,
108454359Sroberto		NO_MESSAGE,
108554359Sroberto		RCC8000_DATA,
108654359Sroberto		RCC8000_ROOTDELAY,
108754359Sroberto		RCC8000_BASEDELAY,
108854359Sroberto		RCC8000_ID,
108954359Sroberto		RCC8000_DESCRIPTION,
109054359Sroberto		RCC8000_FORMAT,
109154359Sroberto		DCF_TYPE,
109254359Sroberto		RCC8000_MAXUNSYNC,
109354359Sroberto		RCC8000_SPEED,
109454359Sroberto		RCC8000_CFLAG,
109554359Sroberto		RCC8000_IFLAG,
109654359Sroberto		RCC8000_OFLAG,
109754359Sroberto		RCC8000_LFLAG,
109854359Sroberto		RCC8000_SAMPLES,
109954359Sroberto		RCC8000_KEEP
110054359Sroberto	},
110154359Sroberto	{                             /* mode 12 */
110254359Sroberto		HOPF6021_FLAGS,
110354359Sroberto		NO_POLL,
110454359Sroberto		NO_INIT,
110554359Sroberto		NO_EVENT,
110654359Sroberto		NO_END,
110754359Sroberto		NO_MESSAGE,
110854359Sroberto		NO_DATA,
110954359Sroberto		HOPF6021_ROOTDELAY,
111054359Sroberto		HOPF6021_BASEDELAY,
111154359Sroberto		DCF_ID,
111254359Sroberto		HOPF6021_DESCRIPTION,
111354359Sroberto		HOPF6021_FORMAT,
111454359Sroberto		DCF_TYPE,
111554359Sroberto		HOPF6021_MAXUNSYNC,
111654359Sroberto		HOPF6021_SPEED,
111754359Sroberto		HOPF6021_CFLAG,
111854359Sroberto		HOPF6021_IFLAG,
111954359Sroberto		HOPF6021_OFLAG,
112054359Sroberto		HOPF6021_LFLAG,
112154359Sroberto		HOPF6021_SAMPLES,
112254359Sroberto		HOPF6021_KEEP
112354359Sroberto	},
112454359Sroberto	{                            /* mode 13 */
112554359Sroberto		COMPUTIME_FLAGS,
112654359Sroberto		NO_POLL,
112754359Sroberto		NO_INIT,
112854359Sroberto		NO_EVENT,
112954359Sroberto		NO_END,
113054359Sroberto		NO_MESSAGE,
113154359Sroberto		NO_DATA,
113254359Sroberto		COMPUTIME_ROOTDELAY,
113354359Sroberto		COMPUTIME_BASEDELAY,
113454359Sroberto		COMPUTIME_ID,
113554359Sroberto		COMPUTIME_DESCRIPTION,
113654359Sroberto		COMPUTIME_FORMAT,
113754359Sroberto		COMPUTIME_TYPE,
113854359Sroberto		COMPUTIME_MAXUNSYNC,
113954359Sroberto		COMPUTIME_SPEED,
114054359Sroberto		COMPUTIME_CFLAG,
114154359Sroberto		COMPUTIME_IFLAG,
114254359Sroberto		COMPUTIME_OFLAG,
114354359Sroberto		COMPUTIME_LFLAG,
114454359Sroberto		COMPUTIME_SAMPLES,
114554359Sroberto		COMPUTIME_KEEP
114654359Sroberto	},
114754359Sroberto	{				/* mode 14 */
114854359Sroberto		RAWDCF_FLAGS,
114954359Sroberto		NO_POLL,
115056746Sroberto		RAWDCFDTRSET_INIT,
115154359Sroberto		NO_EVENT,
115254359Sroberto		NO_END,
115354359Sroberto		NO_MESSAGE,
115454359Sroberto		NO_DATA,
115554359Sroberto		RAWDCF_ROOTDELAY,
115654359Sroberto		RAWDCF_BASEDELAY,
115754359Sroberto		DCF_A_ID,
115856746Sroberto		RAWDCFDTRSET_DESCRIPTION,
115954359Sroberto		RAWDCF_FORMAT,
116054359Sroberto		DCF_TYPE,
116154359Sroberto		RAWDCF_MAXUNSYNC,
116254359Sroberto		RAWDCF_SPEED,
116354359Sroberto		RAWDCF_CFLAG,
116454359Sroberto		RAWDCF_IFLAG,
116554359Sroberto		RAWDCF_OFLAG,
116654359Sroberto		RAWDCF_LFLAG,
116754359Sroberto		RAWDCF_SAMPLES,
116854359Sroberto		RAWDCF_KEEP
116954359Sroberto	},
117054359Sroberto	{				/* mode 15 */
117156746Sroberto		0,				/* operation flags (io modes) */
117256746Sroberto  		poll_dpoll,			/* active poll routine */
117356746Sroberto		poll_init,			/* active poll init routine */
117456746Sroberto  		NO_EVENT,		        /* special event handling (e.g. reset clock) */
117556746Sroberto  		NO_END,				/* active poll end routine */
117656746Sroberto  		NO_MESSAGE,			/* process a lower layer message */
117756746Sroberto		((void *)(&we400a_pollinfo)),   /* local data area for "poll" mechanism */
117856746Sroberto		0,				/* rootdelay */
117956746Sroberto		1.0 / 960,			/* current offset by which the RS232
118056746Sroberto				           	time code is delayed from the actual time */
118156746Sroberto		DCF_ID,				/* ID code */
118256746Sroberto		"WHARTON 400A Series clock",	/* device name */
118356746Sroberto		"WHARTON 400A Series clock Output Format 5",	/* fixed format */
118456746Sroberto			/* Must match a format-name in a libparse/clk_xxx.c file */
118556746Sroberto		DCF_TYPE,			/* clock type (ntp control) */
118656746Sroberto		(1*60*60),		        /* time to trust oscillator after loosing synch */
118756746Sroberto		B9600,				/* terminal input & output baudrate */
118856746Sroberto		(CS8|CREAD|PARENB|CLOCAL|HUPCL),/* terminal control flags */
118956746Sroberto		0,				/* terminal input flags */
119056746Sroberto		0,				/* terminal output flags */
119156746Sroberto		0,				/* terminal local flags */
119256746Sroberto		5,				/* samples for median filter */
119356746Sroberto		3,				/* samples for median filter to keep */
119454359Sroberto	},
119556746Sroberto	{				/* mode 16 - RAWDCF RTS set, DTR clr */
119656746Sroberto		RAWDCF_FLAGS,
119756746Sroberto		NO_POLL,
119856746Sroberto		RAWDCFDTRCLRRTSSET_INIT,
119956746Sroberto		NO_EVENT,
120056746Sroberto		NO_END,
120156746Sroberto		NO_MESSAGE,
120256746Sroberto		NO_DATA,
120356746Sroberto		RAWDCF_ROOTDELAY,
120456746Sroberto		RAWDCF_BASEDELAY,
120556746Sroberto		DCF_A_ID,
120656746Sroberto		RAWDCFDTRCLRRTSSET_DESCRIPTION,
120756746Sroberto		RAWDCF_FORMAT,
120856746Sroberto		DCF_TYPE,
120956746Sroberto		RAWDCF_MAXUNSYNC,
121056746Sroberto		RAWDCF_SPEED,
121156746Sroberto		RAWDCF_CFLAG,
121256746Sroberto		RAWDCF_IFLAG,
121356746Sroberto		RAWDCF_OFLAG,
121456746Sroberto		RAWDCF_LFLAG,
121556746Sroberto		RAWDCF_SAMPLES,
121656746Sroberto		RAWDCF_KEEP
121756746Sroberto	},
121856746Sroberto        {                            /* mode 17 */
121954359Sroberto                VARITEXT_FLAGS,
122054359Sroberto                NO_POLL,
122154359Sroberto                NO_INIT,
122254359Sroberto                NO_EVENT,
122354359Sroberto                NO_END,
122454359Sroberto                NO_MESSAGE,
122554359Sroberto                NO_DATA,
122654359Sroberto                VARITEXT_ROOTDELAY,
122754359Sroberto                VARITEXT_BASEDELAY,
122854359Sroberto                VARITEXT_ID,
122954359Sroberto                VARITEXT_DESCRIPTION,
123054359Sroberto                VARITEXT_FORMAT,
123154359Sroberto                VARITEXT_TYPE,
123254359Sroberto                VARITEXT_MAXUNSYNC,
123354359Sroberto                VARITEXT_SPEED,
123454359Sroberto                VARITEXT_CFLAG,
123554359Sroberto                VARITEXT_IFLAG,
123654359Sroberto                VARITEXT_OFLAG,
123754359Sroberto                VARITEXT_LFLAG,
123854359Sroberto                VARITEXT_SAMPLES,
123954359Sroberto                VARITEXT_KEEP
124056746Sroberto        }
124154359Sroberto};
124254359Sroberto
124354359Srobertostatic int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo);
124454359Sroberto
124554359Sroberto#define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F))
124654359Sroberto#define CLK_TYPE(x)	((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x))
124754359Sroberto#define CLK_UNIT(x)	((int)REFCLOCKUNIT(&(x)->srcadr))
124854359Sroberto#define CLK_PPS(x)	(((x)->ttl) & 0x80)
124954359Sroberto
125054359Sroberto/*
125154359Sroberto * Other constant stuff
125254359Sroberto */
125354359Sroberto#define	PARSEHSREFID	0x7f7f08ff	/* 127.127.8.255 refid for hi strata */
125454359Sroberto
125554359Sroberto#define PARSESTATISTICS   (60*60)	        /* output state statistics every hour */
125654359Sroberto
125754359Srobertostatic struct parseunit *parseunits[MAXUNITS];
125854359Sroberto
125954359Srobertostatic int notice = 0;
126054359Sroberto
126154359Sroberto#define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i])
126254359Sroberto
126354359Srobertostatic void parse_event   P((struct parseunit *, int));
126454359Srobertostatic void parse_process P((struct parseunit *, parsetime_t *));
126554359Srobertostatic void clear_err     P((struct parseunit *, u_long));
126654359Srobertostatic int  list_err      P((struct parseunit *, u_long));
126754359Srobertostatic char * l_mktime    P((u_long));
126854359Sroberto
126954359Sroberto/**===========================================================================
127054359Sroberto ** implementation error message regression module
127154359Sroberto **/
127254359Srobertostatic void
127354359Srobertoclear_err(
127454359Sroberto	struct parseunit *parse,
127554359Sroberto	u_long            lstate
127654359Sroberto	)
127754359Sroberto{
127854359Sroberto	if (lstate == ERR_ALL)
127954359Sroberto	{
128054359Sroberto		int i;
128154359Sroberto
128254359Sroberto		for (i = 0; i < ERR_CNT; i++)
128354359Sroberto		{
128454359Sroberto			parse->errors[i].err_stage   = err_tbl[i];
128554359Sroberto			parse->errors[i].err_cnt     = 0;
128654359Sroberto			parse->errors[i].err_last    = 0;
128754359Sroberto			parse->errors[i].err_started = 0;
128854359Sroberto			parse->errors[i].err_suppressed = 0;
128954359Sroberto		}
129054359Sroberto	}
129154359Sroberto	else
129254359Sroberto	{
129354359Sroberto		parse->errors[lstate].err_stage   = err_tbl[lstate];
129454359Sroberto		parse->errors[lstate].err_cnt     = 0;
129554359Sroberto		parse->errors[lstate].err_last    = 0;
129654359Sroberto		parse->errors[lstate].err_started = 0;
129754359Sroberto		parse->errors[lstate].err_suppressed = 0;
129854359Sroberto	}
129954359Sroberto}
130054359Sroberto
130154359Srobertostatic int
130254359Srobertolist_err(
130354359Sroberto	struct parseunit *parse,
130454359Sroberto	u_long            lstate
130554359Sroberto	)
130654359Sroberto{
130754359Sroberto	int do_it;
130854359Sroberto	struct errorinfo *err = &parse->errors[lstate];
130954359Sroberto
131054359Sroberto	if (err->err_started == 0)
131154359Sroberto	{
131254359Sroberto		err->err_started = current_time;
131354359Sroberto	}
131454359Sroberto
131554359Sroberto	do_it = (current_time - err->err_last) >= err->err_stage->err_delay;
131654359Sroberto
131754359Sroberto	if (do_it)
131854359Sroberto	    err->err_cnt++;
131954359Sroberto
132054359Sroberto	if (err->err_stage->err_count &&
132154359Sroberto	    (err->err_cnt >= err->err_stage->err_count))
132254359Sroberto	{
132354359Sroberto		err->err_stage++;
132454359Sroberto		err->err_cnt = 0;
132554359Sroberto	}
132654359Sroberto
132754359Sroberto	if (!err->err_cnt && do_it)
132854359Sroberto	    msyslog(LOG_INFO, "PARSE receiver #%d: interval for following error message class is at least %s",
132954359Sroberto		    CLK_UNIT(parse->peer), l_mktime(err->err_stage->err_delay));
133054359Sroberto
133154359Sroberto	if (!do_it)
133254359Sroberto	    err->err_suppressed++;
133354359Sroberto	else
133454359Sroberto	    err->err_last = current_time;
133554359Sroberto
133654359Sroberto	if (do_it && err->err_suppressed)
133754359Sroberto	{
133854359Sroberto		msyslog(LOG_INFO, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s",
133954359Sroberto			CLK_UNIT(parse->peer), err->err_suppressed, (err->err_suppressed == 1) ? " was" : "s where",
134054359Sroberto			l_mktime(current_time - err->err_started));
134154359Sroberto		err->err_suppressed = 0;
134254359Sroberto	}
134354359Sroberto
134454359Sroberto	return do_it;
134554359Sroberto}
134654359Sroberto
134754359Sroberto/*--------------------------------------------------
134854359Sroberto * mkreadable - make a printable ascii string (without
134954359Sroberto * embedded quotes so that the ntpq protocol isn't
135054359Sroberto * fooled
135154359Sroberto */
135254359Sroberto#ifndef isprint
135354359Sroberto#define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F))
135454359Sroberto#endif
135554359Sroberto
135654359Srobertostatic char *
135754359Srobertomkreadable(
135854359Sroberto	char  *buffer,
135954359Sroberto	long  blen,
136054359Sroberto	const char  *src,
136154359Sroberto	u_long  srclen,
136254359Sroberto	int hex
136354359Sroberto	)
136454359Sroberto{
136554359Sroberto	char *b    = buffer;
136654359Sroberto	char *endb = (char *)0;
136754359Sroberto
136854359Sroberto	if (blen < 4)
136954359Sroberto		return (char *)0;		/* don't bother with mini buffers */
137054359Sroberto
137154359Sroberto	endb = buffer + blen - 4;
137254359Sroberto
137354359Sroberto	blen--;			/* account for '\0' */
137454359Sroberto
137554359Sroberto	while (blen && srclen--)
137654359Sroberto	{
137754359Sroberto		if (!hex &&             /* no binary only */
137854359Sroberto		    (*src != '\\') &&   /* no plain \ */
137954359Sroberto		    (*src != '"') &&    /* no " */
138054359Sroberto		    isprint((int)*src))	/* only printables */
138154359Sroberto		{			/* they are easy... */
138254359Sroberto			*buffer++ = *src++;
138354359Sroberto			blen--;
138454359Sroberto		}
138554359Sroberto		else
138654359Sroberto		{
138754359Sroberto			if (blen < 4)
138854359Sroberto			{
138954359Sroberto				while (blen--)
139054359Sroberto				{
139154359Sroberto					*buffer++ = '.';
139254359Sroberto				}
139354359Sroberto				*buffer = '\0';
139454359Sroberto				return b;
139554359Sroberto			}
139654359Sroberto			else
139754359Sroberto			{
139854359Sroberto				if (*src == '\\')
139954359Sroberto				{
140054359Sroberto					strcpy(buffer,"\\\\");
140154359Sroberto					buffer += 2;
140254359Sroberto					blen   -= 2;
140354359Sroberto					src++;
140454359Sroberto				}
140554359Sroberto				else
140654359Sroberto				{
140754359Sroberto					sprintf(buffer, "\\x%02x", *src++);
140854359Sroberto					blen   -= 4;
140954359Sroberto					buffer += 4;
141054359Sroberto				}
141154359Sroberto			}
141254359Sroberto		}
141354359Sroberto		if (srclen && !blen && endb) /* overflow - set last chars to ... */
141454359Sroberto			strcpy(endb, "...");
141554359Sroberto	}
141654359Sroberto
141754359Sroberto	*buffer = '\0';
141854359Sroberto	return b;
141954359Sroberto}
142054359Sroberto
142154359Sroberto
142254359Sroberto/*--------------------------------------------------
142354359Sroberto * mkascii - make a printable ascii string
142454359Sroberto * assumes (unless defined better) 7-bit ASCII
142554359Sroberto */
142654359Srobertostatic char *
142754359Srobertomkascii(
142854359Sroberto	char  *buffer,
142954359Sroberto	long  blen,
143054359Sroberto	const char  *src,
143154359Sroberto	u_long  srclen
143254359Sroberto	)
143354359Sroberto{
143454359Sroberto	return mkreadable(buffer, blen, src, srclen, 0);
143554359Sroberto}
143654359Sroberto
143754359Sroberto/**===========================================================================
143854359Sroberto ** implementation of i/o handling methods
143954359Sroberto ** (all STREAM, partial STREAM, user level)
144054359Sroberto **/
144154359Sroberto
144254359Sroberto/*
144354359Sroberto * define possible io handling methods
144454359Sroberto */
144554359Sroberto#ifdef STREAM
144654359Srobertostatic int  ppsclock_init   P((struct parseunit *));
144754359Srobertostatic int  stream_init     P((struct parseunit *));
144854359Srobertostatic void stream_end      P((struct parseunit *));
144954359Srobertostatic int  stream_enable   P((struct parseunit *));
145054359Srobertostatic int  stream_disable  P((struct parseunit *));
145154359Srobertostatic int  stream_setcs    P((struct parseunit *, parsectl_t *));
145254359Srobertostatic int  stream_getfmt   P((struct parseunit *, parsectl_t *));
145354359Srobertostatic int  stream_setfmt   P((struct parseunit *, parsectl_t *));
145454359Srobertostatic int  stream_timecode P((struct parseunit *, parsectl_t *));
145554359Srobertostatic void stream_receive  P((struct recvbuf *));
145654359Sroberto#endif
145754359Sroberto
145854359Srobertostatic int  local_init     P((struct parseunit *));
145954359Srobertostatic void local_end      P((struct parseunit *));
146054359Srobertostatic int  local_nop      P((struct parseunit *));
146154359Srobertostatic int  local_setcs    P((struct parseunit *, parsectl_t *));
146254359Srobertostatic int  local_getfmt   P((struct parseunit *, parsectl_t *));
146354359Srobertostatic int  local_setfmt   P((struct parseunit *, parsectl_t *));
146454359Srobertostatic int  local_timecode P((struct parseunit *, parsectl_t *));
146554359Srobertostatic void local_receive  P((struct recvbuf *));
146654359Srobertostatic int  local_input    P((struct recvbuf *));
146754359Sroberto
146854359Srobertostatic bind_t io_bindings[] =
146954359Sroberto{
147054359Sroberto#ifdef STREAM
147154359Sroberto	{
147254359Sroberto		"parse STREAM",
147354359Sroberto		stream_init,
147454359Sroberto		stream_end,
147554359Sroberto		stream_setcs,
147654359Sroberto		stream_disable,
147754359Sroberto		stream_enable,
147854359Sroberto		stream_getfmt,
147954359Sroberto		stream_setfmt,
148054359Sroberto		stream_timecode,
148154359Sroberto		stream_receive,
148254359Sroberto		0,
148354359Sroberto	},
148454359Sroberto	{
148554359Sroberto		"ppsclock STREAM",
148654359Sroberto		ppsclock_init,
148754359Sroberto		local_end,
148854359Sroberto		local_setcs,
148954359Sroberto		local_nop,
149054359Sroberto		local_nop,
149154359Sroberto		local_getfmt,
149254359Sroberto		local_setfmt,
149354359Sroberto		local_timecode,
149454359Sroberto		local_receive,
149554359Sroberto		local_input,
149654359Sroberto	},
149754359Sroberto#endif
149854359Sroberto	{
149954359Sroberto		"normal",
150054359Sroberto		local_init,
150154359Sroberto		local_end,
150254359Sroberto		local_setcs,
150354359Sroberto		local_nop,
150454359Sroberto		local_nop,
150554359Sroberto		local_getfmt,
150654359Sroberto		local_setfmt,
150754359Sroberto		local_timecode,
150854359Sroberto		local_receive,
150954359Sroberto		local_input,
151054359Sroberto	},
151154359Sroberto	{
151254359Sroberto		(char *)0,
151354359Sroberto	}
151454359Sroberto};
151554359Sroberto
151654359Sroberto#ifdef STREAM
151754359Sroberto
151854359Sroberto#define fix_ts(_X_) \
151954359Sroberto                        if ((&(_X_))->tv.tv_usec >= 1000000)                \
152054359Sroberto                          {                                                 \
152154359Sroberto			    (&(_X_))->tv.tv_usec -= 1000000;                \
152254359Sroberto			    (&(_X_))->tv.tv_sec  += 1;                      \
152354359Sroberto			  }
152454359Sroberto
152554359Sroberto#define cvt_ts(_X_, _Y_) \
152654359Sroberto                        {                                                   \
152754359Sroberto			  l_fp ts;				            \
152854359Sroberto			  fix_ts((_X_));                                    \
152954359Sroberto			  if (!buftvtots((const char *)&(&(_X_))->tv, &ts)) \
153054359Sroberto			    {                                               \
153154359Sroberto                              ERR(ERR_BADDATA)	 		            \
153254359Sroberto                                msyslog(LOG_ERR,"parse: stream_receive: timestamp conversion error (buftvtots) (%s) (%ld.%06ld) ", (_Y_), (long)(&(_X_))->tv.tv_sec, (long)(&(_X_))->tv.tv_usec);\
153354359Sroberto			      return;                                       \
153454359Sroberto			    }                                               \
153554359Sroberto			  else                                              \
153654359Sroberto			    {                                               \
153754359Sroberto			      (&(_X_))->fp = ts;                            \
153854359Sroberto			    }                                               \
153954359Sroberto		        }
154054359Sroberto
154154359Sroberto/*--------------------------------------------------
154254359Sroberto * ppsclock STREAM init
154354359Sroberto */
154454359Srobertostatic int
154554359Srobertoppsclock_init(
154654359Sroberto	struct parseunit *parse
154754359Sroberto	)
154854359Sroberto{
154954359Sroberto        static char m1[] = "ppsclocd";
155054359Sroberto	static char m2[] = "ppsclock";
155154359Sroberto
155254359Sroberto	/*
155354359Sroberto	 * now push the parse streams module
155454359Sroberto	 * it will ensure exclusive access to the device
155554359Sroberto	 */
155654359Sroberto	if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1 &&
155754359Sroberto	    ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m2) == -1)
155854359Sroberto	{
155954359Sroberto		if (errno != EINVAL)
156056746Sroberto		{
156156746Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m",
156256746Sroberto				CLK_UNIT(parse->peer));
156354359Sroberto		}
156454359Sroberto		return 0;
156554359Sroberto	}
156654359Sroberto	if (!local_init(parse))
156754359Sroberto	{
156854359Sroberto		(void)ioctl(parse->generic->io.fd, I_POP, (caddr_t)0);
156954359Sroberto		return 0;
157054359Sroberto	}
157154359Sroberto
157254359Sroberto	parse->flags |= PARSE_PPSCLOCK;
157354359Sroberto	return 1;
157454359Sroberto}
157554359Sroberto
157654359Sroberto/*--------------------------------------------------
157754359Sroberto * parse STREAM init
157854359Sroberto */
157954359Srobertostatic int
158054359Srobertostream_init(
158154359Sroberto	struct parseunit *parse
158254359Sroberto	)
158354359Sroberto{
158454359Sroberto	static char m1[] = "parse";
158554359Sroberto	/*
158654359Sroberto	 * now push the parse streams module
158754359Sroberto	 * to test whether it is there (neat interface 8-( )
158854359Sroberto	 */
158954359Sroberto	if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
159054359Sroberto	{
159154359Sroberto		if (errno != EINVAL) /* accept non-existence */
159256746Sroberto		{
159356746Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
159454359Sroberto		}
159554359Sroberto		return 0;
159654359Sroberto	}
159754359Sroberto	else
159854359Sroberto	{
159954359Sroberto		while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
160054359Sroberto		    /* empty loop */;
160154359Sroberto
160254359Sroberto		/*
160354359Sroberto		 * now push it a second time after we have removed all
160454359Sroberto		 * module garbage
160554359Sroberto		 */
160654359Sroberto		if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
160754359Sroberto		{
160854359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
160954359Sroberto			return 0;
161054359Sroberto		}
161154359Sroberto		else
161254359Sroberto		{
161354359Sroberto			return 1;
161454359Sroberto		}
161554359Sroberto	}
161654359Sroberto}
161754359Sroberto
161854359Sroberto/*--------------------------------------------------
161954359Sroberto * parse STREAM end
162054359Sroberto */
162154359Srobertostatic void
162254359Srobertostream_end(
162354359Sroberto	struct parseunit *parse
162454359Sroberto	)
162554359Sroberto{
162654359Sroberto	while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
162754359Sroberto	    /* empty loop */;
162854359Sroberto}
162954359Sroberto
163054359Sroberto/*--------------------------------------------------
163154359Sroberto * STREAM setcs
163254359Sroberto */
163354359Srobertostatic int
163454359Srobertostream_setcs(
163554359Sroberto	struct parseunit *parse,
163654359Sroberto	parsectl_t  *tcl
163754359Sroberto	)
163854359Sroberto{
163954359Sroberto	struct strioctl strioc;
164054359Sroberto
164154359Sroberto	strioc.ic_cmd     = PARSEIOC_SETCS;
164254359Sroberto	strioc.ic_timout  = 0;
164354359Sroberto	strioc.ic_dp      = (char *)tcl;
164454359Sroberto	strioc.ic_len     = sizeof (*tcl);
164554359Sroberto
164654359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
164754359Sroberto	{
164854359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer));
164954359Sroberto		return 0;
165054359Sroberto	}
165154359Sroberto	return 1;
165254359Sroberto}
165354359Sroberto
165454359Sroberto/*--------------------------------------------------
165554359Sroberto * STREAM enable
165654359Sroberto */
165754359Srobertostatic int
165854359Srobertostream_enable(
165954359Sroberto	struct parseunit *parse
166054359Sroberto	)
166154359Sroberto{
166254359Sroberto	struct strioctl strioc;
166354359Sroberto
166454359Sroberto	strioc.ic_cmd     = PARSEIOC_ENABLE;
166554359Sroberto	strioc.ic_timout  = 0;
166654359Sroberto	strioc.ic_dp      = (char *)0;
166754359Sroberto	strioc.ic_len     = 0;
166854359Sroberto
166954359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
167054359Sroberto	{
167154359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer));
167254359Sroberto		return 0;
167354359Sroberto	}
167454359Sroberto	parse->generic->io.clock_recv = stream_receive; /* ok - parse input in kernel */
167554359Sroberto	return 1;
167654359Sroberto}
167754359Sroberto
167854359Sroberto/*--------------------------------------------------
167954359Sroberto * STREAM disable
168054359Sroberto */
168154359Srobertostatic int
168254359Srobertostream_disable(
168354359Sroberto	struct parseunit *parse
168454359Sroberto	)
168554359Sroberto{
168654359Sroberto	struct strioctl strioc;
168754359Sroberto
168854359Sroberto	strioc.ic_cmd     = PARSEIOC_DISABLE;
168954359Sroberto	strioc.ic_timout  = 0;
169054359Sroberto	strioc.ic_dp      = (char *)0;
169154359Sroberto	strioc.ic_len     = 0;
169254359Sroberto
169354359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
169454359Sroberto	{
169554359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer));
169654359Sroberto		return 0;
169754359Sroberto	}
169854359Sroberto	parse->generic->io.clock_recv = local_receive; /* ok - parse input in daemon */
169954359Sroberto	return 1;
170054359Sroberto}
170154359Sroberto
170254359Sroberto/*--------------------------------------------------
170354359Sroberto * STREAM getfmt
170454359Sroberto */
170554359Srobertostatic int
170654359Srobertostream_getfmt(
170754359Sroberto	struct parseunit *parse,
170854359Sroberto	parsectl_t  *tcl
170954359Sroberto	)
171054359Sroberto{
171154359Sroberto	struct strioctl strioc;
171254359Sroberto
171354359Sroberto	strioc.ic_cmd     = PARSEIOC_GETFMT;
171454359Sroberto	strioc.ic_timout  = 0;
171554359Sroberto	strioc.ic_dp      = (char *)tcl;
171654359Sroberto	strioc.ic_len     = sizeof (*tcl);
171754359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
171854359Sroberto	{
171954359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer));
172054359Sroberto		return 0;
172154359Sroberto	}
172254359Sroberto	return 1;
172354359Sroberto}
172454359Sroberto
172554359Sroberto/*--------------------------------------------------
172654359Sroberto * STREAM setfmt
172754359Sroberto */
172854359Srobertostatic int
172954359Srobertostream_setfmt(
173054359Sroberto	struct parseunit *parse,
173154359Sroberto	parsectl_t  *tcl
173254359Sroberto	)
173354359Sroberto{
173454359Sroberto	struct strioctl strioc;
173554359Sroberto
173654359Sroberto	strioc.ic_cmd     = PARSEIOC_SETFMT;
173754359Sroberto	strioc.ic_timout  = 0;
173854359Sroberto	strioc.ic_dp      = (char *)tcl;
173954359Sroberto	strioc.ic_len     = sizeof (*tcl);
174054359Sroberto
174154359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
174254359Sroberto	{
174354359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer));
174454359Sroberto		return 0;
174554359Sroberto	}
174654359Sroberto	return 1;
174754359Sroberto}
174854359Sroberto
174954359Sroberto
175054359Sroberto/*--------------------------------------------------
175154359Sroberto * STREAM timecode
175254359Sroberto */
175354359Srobertostatic int
175454359Srobertostream_timecode(
175554359Sroberto	struct parseunit *parse,
175654359Sroberto	parsectl_t  *tcl
175754359Sroberto	)
175854359Sroberto{
175954359Sroberto	struct strioctl strioc;
176054359Sroberto
176154359Sroberto	strioc.ic_cmd     = PARSEIOC_TIMECODE;
176254359Sroberto	strioc.ic_timout  = 0;
176354359Sroberto	strioc.ic_dp      = (char *)tcl;
176454359Sroberto	strioc.ic_len     = sizeof (*tcl);
176554359Sroberto
176654359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
176754359Sroberto	{
176854359Sroberto		ERR(ERR_INTERNAL)
176954359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer));
177054359Sroberto		return 0;
177154359Sroberto	}
177254359Sroberto	clear_err(parse, ERR_INTERNAL);
177354359Sroberto	return 1;
177454359Sroberto}
177554359Sroberto
177654359Sroberto/*--------------------------------------------------
177754359Sroberto * STREAM receive
177854359Sroberto */
177954359Srobertostatic void
178054359Srobertostream_receive(
178154359Sroberto	struct recvbuf *rbufp
178254359Sroberto	)
178354359Sroberto{
178454359Sroberto	struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
178554359Sroberto	parsetime_t parsetime;
178654359Sroberto
178754359Sroberto	if (!parse->peer)
178854359Sroberto	    return;
178954359Sroberto
179054359Sroberto	if (rbufp->recv_length != sizeof(parsetime_t))
179154359Sroberto	{
179254359Sroberto		ERR(ERR_BADIO)
179354359Sroberto			msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)",
179454359Sroberto				CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
179554359Sroberto		parse->generic->baddata++;
179654359Sroberto		parse_event(parse, CEVNT_BADREPLY);
179754359Sroberto		return;
179854359Sroberto	}
179954359Sroberto	clear_err(parse, ERR_BADIO);
180054359Sroberto
180154359Sroberto	memmove((caddr_t)&parsetime,
180254359Sroberto		(caddr_t)rbufp->recv_buffer,
180354359Sroberto		sizeof(parsetime_t));
180454359Sroberto
180554359Sroberto#ifdef DEBUG
180654359Sroberto	if (debug > 3)
180754359Sroberto	  {
180854359Sroberto	    printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n",
180954359Sroberto		   CLK_UNIT(parse->peer),
181054359Sroberto		   (unsigned int)parsetime.parse_status,
181154359Sroberto		   (unsigned int)parsetime.parse_state,
181254359Sroberto		   (long)parsetime.parse_time.tv.tv_sec,
181354359Sroberto		   (long)parsetime.parse_time.tv.tv_usec,
181454359Sroberto		   (long)parsetime.parse_stime.tv.tv_sec,
181554359Sroberto		   (long)parsetime.parse_stime.tv.tv_usec,
181654359Sroberto		   (long)parsetime.parse_ptime.tv.tv_sec,
181754359Sroberto		   (long)parsetime.parse_ptime.tv.tv_usec);
181854359Sroberto	  }
181954359Sroberto#endif
182054359Sroberto
182154359Sroberto	/*
182254359Sroberto	 * switch time stamp world - be sure to normalize small usec field
182354359Sroberto	 * errors.
182454359Sroberto	 */
182554359Sroberto
182654359Sroberto	cvt_ts(parsetime.parse_stime, "parse_stime");
182754359Sroberto
182854359Sroberto	if (PARSE_TIMECODE(parsetime.parse_state))
182954359Sroberto	{
183054359Sroberto	    cvt_ts(parsetime.parse_time, "parse_time");
183154359Sroberto	}
183254359Sroberto
183354359Sroberto	if (PARSE_PPS(parsetime.parse_state))
183454359Sroberto	    cvt_ts(parsetime.parse_ptime, "parse_ptime");
183554359Sroberto
183654359Sroberto	parse_process(parse, &parsetime);
183754359Sroberto}
183854359Sroberto#endif
183954359Sroberto
184054359Sroberto/*--------------------------------------------------
184154359Sroberto * local init
184254359Sroberto */
184354359Srobertostatic int
184454359Srobertolocal_init(
184554359Sroberto	struct parseunit *parse
184654359Sroberto	)
184754359Sroberto{
184854359Sroberto	return parse_ioinit(&parse->parseio);
184954359Sroberto}
185054359Sroberto
185154359Sroberto/*--------------------------------------------------
185254359Sroberto * local end
185354359Sroberto */
185454359Srobertostatic void
185554359Srobertolocal_end(
185654359Sroberto	struct parseunit *parse
185754359Sroberto	)
185854359Sroberto{
185954359Sroberto	parse_ioend(&parse->parseio);
186054359Sroberto}
186154359Sroberto
186254359Sroberto
186354359Sroberto/*--------------------------------------------------
186454359Sroberto * local nop
186554359Sroberto */
186654359Srobertostatic int
186754359Srobertolocal_nop(
186854359Sroberto	struct parseunit *parse
186954359Sroberto	)
187054359Sroberto{
187154359Sroberto	return 1;
187254359Sroberto}
187354359Sroberto
187454359Sroberto/*--------------------------------------------------
187554359Sroberto * local setcs
187654359Sroberto */
187754359Srobertostatic int
187854359Srobertolocal_setcs(
187954359Sroberto	struct parseunit *parse,
188054359Sroberto	parsectl_t  *tcl
188154359Sroberto	)
188254359Sroberto{
188354359Sroberto	return parse_setcs(tcl, &parse->parseio);
188454359Sroberto}
188554359Sroberto
188654359Sroberto/*--------------------------------------------------
188754359Sroberto * local getfmt
188854359Sroberto */
188954359Srobertostatic int
189054359Srobertolocal_getfmt(
189154359Sroberto	struct parseunit *parse,
189254359Sroberto	parsectl_t  *tcl
189354359Sroberto	)
189454359Sroberto{
189554359Sroberto	return parse_getfmt(tcl, &parse->parseio);
189654359Sroberto}
189754359Sroberto
189854359Sroberto/*--------------------------------------------------
189954359Sroberto * local setfmt
190054359Sroberto */
190154359Srobertostatic int
190254359Srobertolocal_setfmt(
190354359Sroberto	struct parseunit *parse,
190454359Sroberto	parsectl_t  *tcl
190554359Sroberto	)
190654359Sroberto{
190754359Sroberto	return parse_setfmt(tcl, &parse->parseio);
190854359Sroberto}
190954359Sroberto
191054359Sroberto/*--------------------------------------------------
191154359Sroberto * local timecode
191254359Sroberto */
191354359Srobertostatic int
191454359Srobertolocal_timecode(
191554359Sroberto	struct parseunit *parse,
191654359Sroberto	parsectl_t  *tcl
191754359Sroberto	)
191854359Sroberto{
191954359Sroberto	return parse_timecode(tcl, &parse->parseio);
192054359Sroberto}
192154359Sroberto
192254359Sroberto
192354359Sroberto/*--------------------------------------------------
192454359Sroberto * local input
192554359Sroberto */
192654359Srobertostatic int
192754359Srobertolocal_input(
192854359Sroberto	struct recvbuf *rbufp
192954359Sroberto	)
193054359Sroberto{
193154359Sroberto	struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
193254359Sroberto	int count;
193354359Sroberto	unsigned char *s;
193454359Sroberto	timestamp_t ts;
193554359Sroberto
193654359Sroberto	if (!parse->peer)
193754359Sroberto		return 0;
193854359Sroberto
193954359Sroberto	/*
194054359Sroberto	 * eat all characters, parsing then and feeding complete samples
194154359Sroberto	 */
194254359Sroberto	count = rbufp->recv_length;
194354359Sroberto	s = (unsigned char *)rbufp->recv_buffer;
194454359Sroberto	ts.fp = rbufp->recv_time;
194554359Sroberto
194654359Sroberto	while (count--)
194754359Sroberto	{
194854359Sroberto		if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts))
194954359Sroberto		{
195054359Sroberto			struct recvbuf buf;
195154359Sroberto
195254359Sroberto			/*
195354359Sroberto			 * got something good to eat
195454359Sroberto			 */
195554359Sroberto			if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state))
195654359Sroberto			{
195754359Sroberto#ifdef TIOCDCDTIMESTAMP
195854359Sroberto				struct timeval dcd_time;
195954359Sroberto
196054359Sroberto				if (ioctl(rbufp->fd, TIOCDCDTIMESTAMP, &dcd_time) != -1)
196154359Sroberto				{
196254359Sroberto					l_fp tstmp;
196354359Sroberto
196454359Sroberto					TVTOTS(&dcd_time, &tstmp);
196554359Sroberto					tstmp.l_ui += JAN_1970;
196654359Sroberto					L_SUB(&ts.fp, &tstmp);
196754359Sroberto					if (ts.fp.l_ui == 0)
196854359Sroberto					{
196954359Sroberto#ifdef DEBUG
197054359Sroberto						if (debug)
197154359Sroberto						{
197254359Sroberto							printf(
197354359Sroberto							       "parse: local_receive: fd %d DCDTIMESTAMP %s\n",
197454359Sroberto							       rbufp->fd,
197554359Sroberto							       lfptoa(&tstmp, 6));
197654359Sroberto							printf(" sigio %s\n",
197754359Sroberto							       lfptoa(&ts.fp, 6));
197854359Sroberto						}
197954359Sroberto#endif
198054359Sroberto						parse->parseio.parse_dtime.parse_ptime.fp = tstmp;
198154359Sroberto						parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
198254359Sroberto					}
198354359Sroberto				}
198454359Sroberto#else /* TIOCDCDTIMESTAMP */
198554359Sroberto#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
198654359Sroberto				if (parse->flags & PARSE_PPSCLOCK)
198754359Sroberto				{
198854359Sroberto					l_fp tts;
198954359Sroberto					struct ppsclockev ev;
199054359Sroberto
199154359Sroberto#ifdef HAVE_CIOGETEV
199254359Sroberto					if (ioctl(parse->generic->io.fd, CIOGETEV, (caddr_t)&ev) == 0)
199354359Sroberto#endif
199454359Sroberto#ifdef HAVE_TIOCGPPSEV
199554359Sroberto					if (ioctl(parse->generic->io.fd, TIOCGPPSEV, (caddr_t)&ev) == 0)
199654359Sroberto#endif
199754359Sroberto					{
199854359Sroberto						if (ev.serial != parse->ppsserial)
199954359Sroberto						{
200054359Sroberto							/*
200154359Sroberto							 * add PPS time stamp if available via ppsclock module
200254359Sroberto							 * and not supplied already.
200354359Sroberto							 */
200454359Sroberto							if (!buftvtots((const char *)&ev.tv, &tts))
200554359Sroberto							{
200654359Sroberto								ERR(ERR_BADDATA)
200754359Sroberto									msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)");
200854359Sroberto							}
200954359Sroberto							else
201054359Sroberto							{
201154359Sroberto								parse->parseio.parse_dtime.parse_ptime.fp = tts;
201254359Sroberto								parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
201354359Sroberto							}
201454359Sroberto						}
201554359Sroberto						parse->ppsserial = ev.serial;
201654359Sroberto					}
201754359Sroberto				}
201854359Sroberto#endif
201954359Sroberto#endif /* TIOCDCDTIMESTAMP */
202054359Sroberto			}
202154359Sroberto			if (count)
202254359Sroberto			{	/* simulate receive */
202354359Sroberto				memmove((caddr_t)buf.recv_buffer,
202454359Sroberto					(caddr_t)&parse->parseio.parse_dtime,
202554359Sroberto					sizeof(parsetime_t));
202654359Sroberto				parse_iodone(&parse->parseio);
202754359Sroberto				buf.recv_length = sizeof(parsetime_t);
202854359Sroberto				buf.recv_time = rbufp->recv_time;
202954359Sroberto				buf.srcadr = rbufp->srcadr;
203054359Sroberto				buf.dstadr = rbufp->dstadr;
203154359Sroberto				buf.fd     = rbufp->fd;
203254359Sroberto				buf.next = 0;
203354359Sroberto				buf.X_from_where = rbufp->X_from_where;
203454359Sroberto				rbufp->receiver(&buf);
203554359Sroberto			}
203654359Sroberto			else
203754359Sroberto			{
203856746Sroberto				memmove((caddr_t)rbufp->recv_buffer,
203956746Sroberto					(caddr_t)&parse->parseio.parse_dtime,
204056746Sroberto					sizeof(parsetime_t));
204156746Sroberto				parse_iodone(&parse->parseio);
204254359Sroberto				rbufp->recv_length = sizeof(parsetime_t);
204354359Sroberto				return 1; /* got something & in place return */
204454359Sroberto			}
204554359Sroberto		}
204654359Sroberto	}
204754359Sroberto	return 0;		/* nothing to pass up */
204854359Sroberto}
204954359Sroberto
205054359Sroberto/*--------------------------------------------------
205154359Sroberto * local receive
205254359Sroberto */
205354359Srobertostatic void
205454359Srobertolocal_receive(
205554359Sroberto	struct recvbuf *rbufp
205654359Sroberto	)
205754359Sroberto{
205854359Sroberto	struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
205954359Sroberto	parsetime_t parsetime;
206054359Sroberto
206154359Sroberto	if (!parse->peer)
206254359Sroberto	    return;
206354359Sroberto
206454359Sroberto	if (rbufp->recv_length != sizeof(parsetime_t))
206554359Sroberto	{
206654359Sroberto		ERR(ERR_BADIO)
206754359Sroberto			msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)",
206854359Sroberto				CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
206954359Sroberto		parse->generic->baddata++;
207054359Sroberto		parse_event(parse, CEVNT_BADREPLY);
207154359Sroberto		return;
207254359Sroberto	}
207354359Sroberto	clear_err(parse, ERR_BADIO);
207454359Sroberto
207554359Sroberto	memmove((caddr_t)&parsetime,
207654359Sroberto		(caddr_t)rbufp->recv_buffer,
207754359Sroberto		sizeof(parsetime_t));
207854359Sroberto
207954359Sroberto#ifdef DEBUG
208054359Sroberto	if (debug > 3)
208154359Sroberto	  {
208254359Sroberto	    printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n",
208354359Sroberto		   CLK_UNIT(parse->peer),
208454359Sroberto		   (unsigned int)parsetime.parse_status,
208554359Sroberto		   (unsigned int)parsetime.parse_state,
208654359Sroberto		   (long)parsetime.parse_time.tv.tv_sec,
208754359Sroberto		   (long)parsetime.parse_time.tv.tv_usec,
208854359Sroberto		   (long)parsetime.parse_stime.tv.tv_sec,
208954359Sroberto		   (long)parsetime.parse_stime.tv.tv_usec,
209054359Sroberto		   (long)parsetime.parse_ptime.tv.tv_sec,
209154359Sroberto		   (long)parsetime.parse_ptime.tv.tv_usec);
209254359Sroberto	  }
209354359Sroberto#endif
209454359Sroberto
209554359Sroberto	parse_process(parse, &parsetime);
209654359Sroberto}
209754359Sroberto
209854359Sroberto/*--------------------------------------------------
209954359Sroberto * init_iobinding - find and initialize lower layers
210054359Sroberto */
210154359Srobertostatic bind_t *
210254359Srobertoinit_iobinding(
210354359Sroberto	struct parseunit *parse
210454359Sroberto	)
210554359Sroberto{
210654359Sroberto  bind_t *b = io_bindings;
210754359Sroberto
210854359Sroberto	while (b->bd_description != (char *)0)
210954359Sroberto	{
211054359Sroberto		if ((*b->bd_init)(parse))
211154359Sroberto		{
211254359Sroberto			return b;
211354359Sroberto		}
211454359Sroberto		b++;
211554359Sroberto	}
211654359Sroberto	return (bind_t *)0;
211754359Sroberto}
211854359Sroberto
211954359Sroberto/**===========================================================================
212054359Sroberto ** support routines
212154359Sroberto **/
212254359Sroberto
212354359Sroberto/*--------------------------------------------------
212454359Sroberto * convert a flag field to a string
212554359Sroberto */
212654359Srobertostatic char *
212754359Srobertoparsestate(
212854359Sroberto	u_long lstate,
212954359Sroberto	char *buffer
213054359Sroberto	)
213154359Sroberto{
213254359Sroberto	static struct bits
213354359Sroberto	{
213454359Sroberto		u_long      bit;
213554359Sroberto		const char *name;
213654359Sroberto	} flagstrings[] =
213754359Sroberto	  {
213856746Sroberto		  { PARSEB_ANNOUNCE,   "DST SWITCH WARNING" },
213956746Sroberto		  { PARSEB_POWERUP,    "NOT SYNCHRONIZED" },
214056746Sroberto		  { PARSEB_NOSYNC,     "TIME CODE NOT CONFIRMED" },
214156746Sroberto		  { PARSEB_DST,        "DST" },
214256746Sroberto		  { PARSEB_UTC,        "UTC DISPLAY" },
214356746Sroberto		  { PARSEB_LEAPADD,    "LEAP ADD WARNING" },
214456746Sroberto		  { PARSEB_LEAPDEL,    "LEAP DELETE WARNING" },
214554359Sroberto		  { PARSEB_LEAPSECOND, "LEAP SECOND" },
214656746Sroberto		  { PARSEB_ALTERNATE,  "ALTERNATE ANTENNA" },
214756746Sroberto		  { PARSEB_TIMECODE,   "TIME CODE" },
214856746Sroberto		  { PARSEB_PPS,        "PPS" },
214956746Sroberto		  { PARSEB_POSITION,   "POSITION" },
215054359Sroberto		  { 0 }
215154359Sroberto	  };
215254359Sroberto
215354359Sroberto	static struct sbits
215454359Sroberto	{
215554359Sroberto		u_long      bit;
215654359Sroberto		const char *name;
215754359Sroberto	} sflagstrings[] =
215854359Sroberto	  {
215954359Sroberto		  { PARSEB_S_LEAP,     "LEAP INDICATION" },
216054359Sroberto		  { PARSEB_S_PPS,      "PPS SIGNAL" },
216154359Sroberto		  { PARSEB_S_ANTENNA,  "ANTENNA" },
216254359Sroberto		  { PARSEB_S_POSITION, "POSITION" },
216354359Sroberto		  { 0 }
216454359Sroberto	  };
216554359Sroberto	int i;
216654359Sroberto
216754359Sroberto	*buffer = '\0';
216854359Sroberto
216954359Sroberto	i = 0;
217054359Sroberto	while (flagstrings[i].bit)
217154359Sroberto	{
217254359Sroberto		if (flagstrings[i].bit & lstate)
217354359Sroberto		{
217454359Sroberto			if (buffer[0])
217554359Sroberto			    strcat(buffer, "; ");
217654359Sroberto			strcat(buffer, flagstrings[i].name);
217754359Sroberto		}
217854359Sroberto		i++;
217954359Sroberto	}
218054359Sroberto
218154359Sroberto	if (lstate & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION))
218254359Sroberto	{
218354359Sroberto      char *s, *t;
218454359Sroberto
218554359Sroberto		if (buffer[0])
218654359Sroberto		    strcat(buffer, "; ");
218754359Sroberto
218854359Sroberto		strcat(buffer, "(");
218954359Sroberto
219054359Sroberto		t = s = buffer + strlen(buffer);
219154359Sroberto
219254359Sroberto		i = 0;
219354359Sroberto		while (sflagstrings[i].bit)
219454359Sroberto		{
219554359Sroberto			if (sflagstrings[i].bit & lstate)
219654359Sroberto			{
219754359Sroberto				if (t != s)
219854359Sroberto				{
219954359Sroberto					strcpy(t, "; ");
220054359Sroberto					t += 2;
220154359Sroberto				}
220254359Sroberto
220354359Sroberto				strcpy(t, sflagstrings[i].name);
220454359Sroberto				t += strlen(t);
220554359Sroberto			}
220654359Sroberto			i++;
220754359Sroberto		}
220854359Sroberto		strcpy(t, ")");
220954359Sroberto	}
221054359Sroberto	return buffer;
221154359Sroberto}
221254359Sroberto
221354359Sroberto/*--------------------------------------------------
221454359Sroberto * convert a status flag field to a string
221554359Sroberto */
221654359Srobertostatic char *
221754359Srobertoparsestatus(
221854359Sroberto	u_long lstate,
221954359Sroberto	char *buffer
222054359Sroberto	)
222154359Sroberto{
222254359Sroberto	static struct bits
222354359Sroberto	{
222454359Sroberto		u_long      bit;
222554359Sroberto		const char *name;
222654359Sroberto	} flagstrings[] =
222754359Sroberto	  {
222854359Sroberto		  { CVT_OK,      "CONVERSION SUCCESSFUL" },
222954359Sroberto		  { CVT_NONE,    "NO CONVERSION" },
223054359Sroberto		  { CVT_FAIL,    "CONVERSION FAILED" },
223154359Sroberto		  { CVT_BADFMT,  "ILLEGAL FORMAT" },
223254359Sroberto		  { CVT_BADDATE, "DATE ILLEGAL" },
223354359Sroberto		  { CVT_BADTIME, "TIME ILLEGAL" },
223454359Sroberto		  { CVT_ADDITIONAL, "ADDITIONAL DATA" },
223554359Sroberto		  { 0 }
223654359Sroberto	  };
223754359Sroberto	int i;
223854359Sroberto
223954359Sroberto	*buffer = '\0';
224054359Sroberto
224154359Sroberto	i = 0;
224254359Sroberto	while (flagstrings[i].bit)
224354359Sroberto	{
224454359Sroberto		if (flagstrings[i].bit & lstate)
224554359Sroberto		{
224654359Sroberto			if (buffer[0])
224754359Sroberto			    strcat(buffer, "; ");
224854359Sroberto			strcat(buffer, flagstrings[i].name);
224954359Sroberto		}
225054359Sroberto		i++;
225154359Sroberto	}
225254359Sroberto
225354359Sroberto	return buffer;
225454359Sroberto}
225554359Sroberto
225654359Sroberto/*--------------------------------------------------
225754359Sroberto * convert a clock status flag field to a string
225854359Sroberto */
225954359Srobertostatic const char *
226054359Srobertoclockstatus(
226154359Sroberto	u_long lstate
226254359Sroberto	)
226354359Sroberto{
226454359Sroberto	static char buffer[20];
226554359Sroberto	static struct status
226654359Sroberto	{
226754359Sroberto		u_long      value;
226854359Sroberto		const char *name;
226954359Sroberto	} flagstrings[] =
227054359Sroberto	  {
227154359Sroberto		  { CEVNT_NOMINAL, "NOMINAL" },
227254359Sroberto		  { CEVNT_TIMEOUT, "NO RESPONSE" },
227354359Sroberto		  { CEVNT_BADREPLY,"BAD FORMAT" },
227454359Sroberto		  { CEVNT_FAULT,   "FAULT" },
227554359Sroberto		  { CEVNT_PROP,    "PROPAGATION DELAY" },
227654359Sroberto		  { CEVNT_BADDATE, "ILLEGAL DATE" },
227754359Sroberto		  { CEVNT_BADTIME, "ILLEGAL TIME" },
227854359Sroberto		  { (unsigned)~0L }
227954359Sroberto	  };
228054359Sroberto	int i;
228154359Sroberto
228254359Sroberto	i = 0;
228354359Sroberto	while (flagstrings[i].value != ~0)
228454359Sroberto	{
228554359Sroberto		if (flagstrings[i].value == lstate)
228654359Sroberto		{
228754359Sroberto			return flagstrings[i].name;
228854359Sroberto		}
228954359Sroberto		i++;
229054359Sroberto	}
229154359Sroberto
229254359Sroberto	sprintf(buffer, "unknown #%ld", (u_long)lstate);
229354359Sroberto
229454359Sroberto	return buffer;
229554359Sroberto}
229654359Sroberto
229754359Sroberto
229854359Sroberto/*--------------------------------------------------
229954359Sroberto * l_mktime - make representation of a relative time
230054359Sroberto */
230154359Srobertostatic char *
230254359Srobertol_mktime(
230354359Sroberto	u_long delta
230454359Sroberto	)
230554359Sroberto{
230654359Sroberto	u_long tmp, m, s;
230754359Sroberto	static char buffer[40];
230854359Sroberto
230954359Sroberto	buffer[0] = '\0';
231054359Sroberto
231154359Sroberto	if ((tmp = delta / (60*60*24)) != 0)
231254359Sroberto	{
231354359Sroberto		sprintf(buffer, "%ldd+", (u_long)tmp);
231454359Sroberto		delta -= tmp * 60*60*24;
231554359Sroberto	}
231654359Sroberto
231754359Sroberto	s = delta % 60;
231854359Sroberto	delta /= 60;
231954359Sroberto	m = delta % 60;
232054359Sroberto	delta /= 60;
232154359Sroberto
232254359Sroberto	sprintf(buffer+strlen(buffer), "%02d:%02d:%02d",
232354359Sroberto		(int)delta, (int)m, (int)s);
232454359Sroberto
232554359Sroberto	return buffer;
232654359Sroberto}
232754359Sroberto
232854359Sroberto
232954359Sroberto/*--------------------------------------------------
233054359Sroberto * parse_statistics - list summary of clock states
233154359Sroberto */
233254359Srobertostatic void
233354359Srobertoparse_statistics(
233454359Sroberto	struct parseunit *parse
233554359Sroberto	)
233654359Sroberto{
233754359Sroberto	int i;
233854359Sroberto
233954359Sroberto	NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */
234054359Sroberto		{
234154359Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s",
234254359Sroberto				CLK_UNIT(parse->peer),
234354359Sroberto				l_mktime(current_time - parse->generic->timestarted));
234454359Sroberto
234554359Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s",
234654359Sroberto				CLK_UNIT(parse->peer),
234754359Sroberto				clockstatus(parse->generic->currentstatus));
234854359Sroberto
234954359Sroberto			for (i = 0; i <= CEVNT_MAX; i++)
235054359Sroberto			{
235154359Sroberto				u_long s_time;
235254359Sroberto				u_long percent, d = current_time - parse->generic->timestarted;
235354359Sroberto
235454359Sroberto				percent = s_time = PARSE_STATETIME(parse, i);
235554359Sroberto
235654359Sroberto				while (((u_long)(~0) / 10000) < percent)
235754359Sroberto				{
235854359Sroberto					percent /= 10;
235954359Sroberto					d       /= 10;
236054359Sroberto				}
236154359Sroberto
236254359Sroberto				if (d)
236354359Sroberto				    percent = (percent * 10000) / d;
236454359Sroberto				else
236554359Sroberto				    percent = 10000;
236654359Sroberto
236754359Sroberto				if (s_time)
236854359Sroberto				    msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)",
236954359Sroberto					    CLK_UNIT(parse->peer),
237054359Sroberto					    clockstatus((unsigned int)i),
237154359Sroberto					    l_mktime(s_time),
237254359Sroberto					    percent / 100, percent % 100);
237354359Sroberto			}
237454359Sroberto		}
237554359Sroberto}
237654359Sroberto
237754359Sroberto/*--------------------------------------------------
237854359Sroberto * cparse_statistics - wrapper for statistics call
237954359Sroberto */
238054359Srobertostatic void
238154359Srobertocparse_statistics(
238254359Sroberto	register struct parseunit *parse
238354359Sroberto	)
238454359Sroberto{
238554359Sroberto	if (parse->laststatistic + PARSESTATISTICS < current_time)
238654359Sroberto		parse_statistics(parse);
238754359Sroberto	parse->laststatistic = current_time;
238854359Sroberto}
238954359Sroberto
239054359Sroberto/**===========================================================================
239154359Sroberto ** ntp interface routines
239254359Sroberto **/
239354359Sroberto
239454359Sroberto/*--------------------------------------------------
239554359Sroberto * parse_init - initialize internal parse driver data
239654359Sroberto */
239754359Srobertostatic void
239854359Srobertoparse_init(void)
239954359Sroberto{
240054359Sroberto	memset((caddr_t)parseunits, 0, sizeof parseunits);
240154359Sroberto}
240254359Sroberto
240354359Sroberto
240454359Sroberto/*--------------------------------------------------
240554359Sroberto * parse_shutdown - shut down a PARSE clock
240654359Sroberto */
240754359Srobertostatic void
240854359Srobertoparse_shutdown(
240954359Sroberto	int unit,
241054359Sroberto	struct peer *peer
241154359Sroberto	)
241254359Sroberto{
241354359Sroberto	struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
241454359Sroberto
241554359Sroberto	if (parse && !parse->peer)
241654359Sroberto	{
241754359Sroberto		msyslog(LOG_ERR,
241854359Sroberto			"PARSE receiver #%d: parse_shutdown: INTERNAL ERROR, unit not in use", unit);
241954359Sroberto		return;
242054359Sroberto	}
242154359Sroberto
242254359Sroberto	/*
242354359Sroberto	 * print statistics a last time and
242454359Sroberto	 * stop statistics machine
242554359Sroberto	 */
242654359Sroberto	parse_statistics(parse);
242754359Sroberto
242854359Sroberto	if (parse->parse_type->cl_end)
242954359Sroberto	{
243054359Sroberto		parse->parse_type->cl_end(parse);
243154359Sroberto	}
243254359Sroberto
243354359Sroberto	if (parse->binding)
243454359Sroberto	    PARSE_END(parse);
243554359Sroberto
243654359Sroberto	/*
243754359Sroberto	 * Tell the I/O module to turn us off.  We're history.
243854359Sroberto	 */
243954359Sroberto	io_closeclock(&parse->generic->io);
244054359Sroberto
244154359Sroberto	free_varlist(parse->kv);
244254359Sroberto
244354359Sroberto	NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
244454359Sroberto		msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed",
244554359Sroberto			CLK_UNIT(parse->peer), parse->parse_type->cl_description);
244654359Sroberto
244754359Sroberto	parse->peer = (struct peer *)0; /* unused now */
244854359Sroberto	free(parse);
244954359Sroberto}
245054359Sroberto
245154359Sroberto/*--------------------------------------------------
245254359Sroberto * parse_start - open the PARSE devices and initialize data for processing
245354359Sroberto */
245454359Srobertostatic int
245554359Srobertoparse_start(
245654359Sroberto	int sysunit,
245754359Sroberto	struct peer *peer
245854359Sroberto	)
245954359Sroberto{
246054359Sroberto	u_int unit;
246154359Sroberto	int fd232;
246254359Sroberto#ifdef HAVE_TERMIOS
246354359Sroberto	struct termios tio;		/* NEEDED FOR A LONG TIME ! */
246454359Sroberto#endif
246554359Sroberto#ifdef HAVE_SYSV_TTYS
246654359Sroberto	struct termio tio;		/* NEEDED FOR A LONG TIME ! */
246754359Sroberto#endif
246854359Sroberto	struct parseunit * parse;
246954359Sroberto	char parsedev[sizeof(PARSEDEVICE)+20];
247054359Sroberto	parsectl_t tmp_ctl;
247154359Sroberto	u_int type;
247254359Sroberto
247354359Sroberto	type = CLK_TYPE(peer);
247454359Sroberto	unit = CLK_UNIT(peer);
247554359Sroberto
247654359Sroberto	if ((type == ~0) || (parse_clockinfo[type].cl_description == (char *)0))
247754359Sroberto	{
247854359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)",
247954359Sroberto			unit, CLK_REALTYPE(peer), ncltypes-1);
248054359Sroberto		return 0;
248154359Sroberto	}
248254359Sroberto
248354359Sroberto	/*
248454359Sroberto	 * Unit okay, attempt to open the device.
248554359Sroberto	 */
248654359Sroberto	(void) sprintf(parsedev, PARSEDEVICE, unit);
248754359Sroberto
248854359Sroberto#ifndef O_NOCTTY
248954359Sroberto#define O_NOCTTY 0
249054359Sroberto#endif
249154359Sroberto
249254359Sroberto	fd232 = open(parsedev, O_RDWR | O_NOCTTY
249354359Sroberto#ifdef O_NONBLOCK
249454359Sroberto		     | O_NONBLOCK
249554359Sroberto#endif
249654359Sroberto		     , 0777);
249754359Sroberto
249854359Sroberto	if (fd232 == -1)
249954359Sroberto	{
250054359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev);
250154359Sroberto		return 0;
250254359Sroberto	}
250354359Sroberto
250454359Sroberto	parse = (struct parseunit *)emalloc(sizeof(struct parseunit));
250554359Sroberto
250654359Sroberto	memset((char *)parse, 0, sizeof(struct parseunit));
250754359Sroberto
250854359Sroberto	parse->generic = peer->procptr;	 /* link up */
250954359Sroberto	parse->generic->unitptr = (caddr_t)parse; /* link down */
251054359Sroberto
251154359Sroberto	/*
251254359Sroberto	 * Set up the structures
251354359Sroberto	 */
251454359Sroberto	parse->generic->timestarted    = current_time;
251554359Sroberto	parse->lastchange     = current_time;
251654359Sroberto
251754359Sroberto	parse->generic->currentstatus	        = CEVNT_TIMEOUT; /* expect the worst */
251854359Sroberto
251954359Sroberto	parse->flags          = 0;
252054359Sroberto	parse->pollneeddata   = 0;
252154359Sroberto	parse->laststatistic  = current_time;
252254359Sroberto	parse->lastformat     = (unsigned short)~0;	/* assume no format known */
252354359Sroberto	parse->time.parse_status = (unsigned short)~0;	/* be sure to mark initial status change */
252454359Sroberto	parse->lastmissed     = 0;	/* assume got everything */
252554359Sroberto	parse->ppsserial      = 0;
252654359Sroberto	parse->localdata      = (void *)0;
252754359Sroberto	parse->localstate     = 0;
252854359Sroberto	parse->kv             = (struct ctl_var *)0;
252954359Sroberto
253054359Sroberto	clear_err(parse, ERR_ALL);
253154359Sroberto
253254359Sroberto	parse->parse_type     = &parse_clockinfo[type];
253354359Sroberto
253454359Sroberto	parse->generic->fudgetime1 = parse->parse_type->cl_basedelay;
253554359Sroberto
253654359Sroberto	parse->generic->fudgetime2 = 0.0;
253754359Sroberto
253854359Sroberto	parse->generic->clockdesc = parse->parse_type->cl_description;
253954359Sroberto
254054359Sroberto	peer->rootdelay       = parse->parse_type->cl_rootdelay;
254154359Sroberto	peer->sstclktype      = parse->parse_type->cl_type;
254254359Sroberto	peer->precision       = sys_precision;
254354359Sroberto
254454359Sroberto	peer->stratum         = STRATUM_REFCLOCK;
254554359Sroberto	if (peer->stratum <= 1)
254654359Sroberto	    memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4);
254754359Sroberto	else
254854359Sroberto	    parse->generic->refid = htonl(PARSEHSREFID);
254954359Sroberto
255054359Sroberto	parse->generic->io.fd = fd232;
255154359Sroberto
255254359Sroberto	parse->peer = peer;		/* marks it also as busy */
255354359Sroberto
255454359Sroberto	/*
255554359Sroberto	 * configure terminal line
255654359Sroberto	 */
255754359Sroberto	if (TTY_GETATTR(fd232, &tio) == -1)
255854359Sroberto	{
255954359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232);
256054359Sroberto		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
256154359Sroberto		return 0;
256254359Sroberto	}
256354359Sroberto	else
256454359Sroberto	{
256554359Sroberto#ifndef _PC_VDISABLE
256654359Sroberto		memset((char *)tio.c_cc, 0, sizeof(tio.c_cc));
256754359Sroberto#else
256854359Sroberto		int disablec;
256954359Sroberto		errno = 0;		/* pathconf can deliver -1 without changing errno ! */
257054359Sroberto
257154359Sroberto		disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE);
257254359Sroberto		if (disablec == -1 && errno)
257354359Sroberto		{
257454359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer));
257554359Sroberto			memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */
257654359Sroberto		}
257754359Sroberto		else
257854359Sroberto		    if (disablec != -1)
257954359Sroberto			memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc));
258054359Sroberto#endif
258154359Sroberto
258254359Sroberto#if defined (VMIN) || defined(VTIME)
258354359Sroberto		if ((parse_clockinfo[type].cl_lflag & ICANON) == 0)
258454359Sroberto		{
258554359Sroberto#ifdef VMIN
258654359Sroberto			tio.c_cc[VMIN]   = 1;
258754359Sroberto#endif
258854359Sroberto#ifdef VTIME
258954359Sroberto			tio.c_cc[VTIME]  = 0;
259054359Sroberto#endif
259154359Sroberto		}
259254359Sroberto#endif
259354359Sroberto
259454359Sroberto		tio.c_cflag = parse_clockinfo[type].cl_cflag;
259554359Sroberto		tio.c_iflag = parse_clockinfo[type].cl_iflag;
259654359Sroberto		tio.c_oflag = parse_clockinfo[type].cl_oflag;
259754359Sroberto		tio.c_lflag = parse_clockinfo[type].cl_lflag;
259854359Sroberto
259954359Sroberto
260054359Sroberto#ifdef HAVE_TERMIOS
260154359Sroberto		if ((cfsetospeed(&tio, parse_clockinfo[type].cl_speed) == -1) ||
260254359Sroberto		    (cfsetispeed(&tio, parse_clockinfo[type].cl_speed) == -1))
260354359Sroberto		{
260454359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit);
260554359Sroberto			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
260654359Sroberto			return 0;
260754359Sroberto		}
260854359Sroberto#else
260954359Sroberto		tio.c_cflag     |= parse_clockinfo[type].cl_speed;
261054359Sroberto#endif
261154359Sroberto
261254359Sroberto#if defined(HAVE_TIO_SERIAL_STUFF)		/* Linux hack: define PPS interface */
261354359Sroberto		{
261454359Sroberto		  struct serial_struct	ss;
261554359Sroberto		  if (ioctl(fd232, TIOCGSERIAL, &ss) < 0 ||
261654359Sroberto		      (
261754359Sroberto#ifdef ASYNC_LOW_LATENCY
261854359Sroberto		       ss.flags |= ASYNC_LOW_LATENCY,
261954359Sroberto#endif
262054359Sroberto#ifdef ASYNC_PPS_CD_NEG
262154359Sroberto		       ss.flags |= ASYNC_PPS_CD_NEG,
262254359Sroberto#endif
262354359Sroberto		       ioctl(fd232, TIOCSSERIAL, &ss)) < 0) {
262454359Sroberto		    msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", fd232);
262554359Sroberto		    msyslog(LOG_NOTICE,
262654359Sroberto			    "refclock_parse: optional PPS processing not available");
262754359Sroberto		  } else {
262854359Sroberto		    parse->flags    |= PARSE_PPSCLOCK;
262954359Sroberto		    msyslog(LOG_INFO,
263054359Sroberto			    "refclock_parse: PPS detection on");
263154359Sroberto		  }
263254359Sroberto		}
263354359Sroberto#endif
263454359Sroberto#ifdef HAVE_TIOCSPPS			/* SUN PPS support */
263554359Sroberto		if (CLK_PPS(parse->peer))
263654359Sroberto		  {
263754359Sroberto		    int i = 1;
263854359Sroberto
263954359Sroberto		    if (ioctl(fd232, TIOCSPPS, (caddr_t)&i) == 0)
264054359Sroberto		      {
264154359Sroberto			parse->flags |= PARSE_PPSCLOCK;
264254359Sroberto		      }
264354359Sroberto		  }
264454359Sroberto#endif
264554359Sroberto
264654359Sroberto		if (TTY_SETATTR(fd232, &tio) == -1)
264754359Sroberto		{
264854359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232);
264954359Sroberto			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
265054359Sroberto			return 0;
265154359Sroberto		}
265254359Sroberto	}
265354359Sroberto
265454359Sroberto	/*
265554359Sroberto	 * Insert in async io device list.
265654359Sroberto	 */
265754359Sroberto	parse->generic->io.srcclock = (caddr_t)parse;
265854359Sroberto	parse->generic->io.datalen = 0;
265954359Sroberto
266054359Sroberto	if (!io_addclock(&parse->generic->io))
266154359Sroberto        {
266254359Sroberto		msyslog(LOG_ERR,
266354359Sroberto			"PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev);
266454359Sroberto		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
266554359Sroberto		return 0;
266654359Sroberto	}
266754359Sroberto
266854359Sroberto	parse->binding = init_iobinding(parse);
266954359Sroberto	parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */
267054359Sroberto	parse->generic->io.io_input   = parse->binding->bd_io_input; /* pick correct input routine */
267154359Sroberto
267254359Sroberto	if (parse->binding == (bind_t *)0)
267354359Sroberto		{
267454359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer));
267554359Sroberto			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
267654359Sroberto			return 0;			/* well, ok - special initialisation broke */
267754359Sroberto		}
267854359Sroberto
267954359Sroberto	/*
268054359Sroberto	 * as we always(?) get 8 bit chars we want to be
268154359Sroberto	 * sure, that the upper bits are zero for less
268254359Sroberto	 * than 8 bit I/O - so we pass that information on.
268354359Sroberto	 * note that there can be only one bit count format
268454359Sroberto	 * per file descriptor
268554359Sroberto	 */
268654359Sroberto
268754359Sroberto	switch (tio.c_cflag & CSIZE)
268854359Sroberto	{
268954359Sroberto	    case CS5:
269054359Sroberto		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5;
269154359Sroberto		break;
269254359Sroberto
269354359Sroberto	    case CS6:
269454359Sroberto		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6;
269554359Sroberto		break;
269654359Sroberto
269754359Sroberto	    case CS7:
269854359Sroberto		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7;
269954359Sroberto		break;
270054359Sroberto
270154359Sroberto	    case CS8:
270254359Sroberto		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8;
270354359Sroberto		break;
270454359Sroberto	}
270554359Sroberto
270654359Sroberto	if (!PARSE_SETCS(parse, &tmp_ctl))
270754359Sroberto	{
270854359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit);
270954359Sroberto		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
271054359Sroberto		return 0;			/* well, ok - special initialisation broke */
271154359Sroberto	}
271254359Sroberto
271354359Sroberto	strcpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format);
271454359Sroberto	tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer);
271554359Sroberto
271654359Sroberto	if (!PARSE_SETFMT(parse, &tmp_ctl))
271754359Sroberto	{
271854359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit);
271954359Sroberto		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
272054359Sroberto		return 0;			/* well, ok - special initialisation broke */
272154359Sroberto	}
272254359Sroberto
272354359Sroberto	/*
272454359Sroberto	 * get rid of all IO accumulated so far
272554359Sroberto	 */
272654359Sroberto#ifdef HAVE_TERMIOS
272754359Sroberto	(void) tcflush(parse->generic->io.fd, TCIOFLUSH);
272854359Sroberto#else
272954359Sroberto#ifdef TCFLSH
273054359Sroberto	{
273154359Sroberto#ifndef TCIOFLUSH
273254359Sroberto#define TCIOFLUSH 2
273354359Sroberto#endif
273454359Sroberto		int flshcmd = TCIOFLUSH;
273554359Sroberto
273654359Sroberto		(void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd);
273754359Sroberto	}
273854359Sroberto#endif
273954359Sroberto#endif
274056746Sroberto
274154359Sroberto	/*
274254359Sroberto	 * try to do any special initializations
274354359Sroberto	 */
274454359Sroberto	if (parse->parse_type->cl_init)
274554359Sroberto		{
274654359Sroberto			if (parse->parse_type->cl_init(parse))
274754359Sroberto				{
274854359Sroberto					parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
274954359Sroberto					return 0;		/* well, ok - special initialisation broke */
275054359Sroberto				}
275154359Sroberto		}
275254359Sroberto
275354359Sroberto	/*
275454359Sroberto	 * get out Copyright information once
275554359Sroberto	 */
275654359Sroberto	if (!notice)
275754359Sroberto        {
275854359Sroberto		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
275954359Sroberto			msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-1999, Frank Kardel");
276054359Sroberto		notice = 1;
276154359Sroberto	}
276254359Sroberto
276354359Sroberto	/*
276454359Sroberto	 * print out configuration
276554359Sroberto	 */
276654359Sroberto	NLOG(NLOG_CLOCKINFO)
276754359Sroberto		{
276854359Sroberto			/* conditional if clause for conditional syslog */
276954359Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (device %s) added",
277054359Sroberto				CLK_UNIT(parse->peer),
277154359Sroberto				parse->parse_type->cl_description, parsedev);
277254359Sroberto
277354359Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d:  Stratum %d, %sPPS support, trust time %s, precision %d",
277454359Sroberto				CLK_UNIT(parse->peer),
277554359Sroberto				parse->peer->stratum, CLK_PPS(parse->peer) ? "" : "no ",
277654359Sroberto				l_mktime(parse->parse_type->cl_maxunsync), parse->peer->precision);
277754359Sroberto
277854359Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d:  rootdelay %.6f s, phaseadjust %.6f s, %s IO handling",
277954359Sroberto				CLK_UNIT(parse->peer),
278054359Sroberto				parse->parse_type->cl_rootdelay,
278154359Sroberto				parse->generic->fudgetime1,
278254359Sroberto				parse->binding->bd_description);
278354359Sroberto
278454359Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d:  Format recognition: %s", CLK_UNIT(parse->peer),
278554359Sroberto				parse->parse_type->cl_format);
278654359Sroberto#ifdef PPS
278754359Sroberto                        msyslog(LOG_INFO, "PARSE receiver #%d:  %sPPS ioctl support", CLK_UNIT(parse->peer),
278854359Sroberto				(parse->flags & PARSE_PPSCLOCK) ? "" : "NO ");
278954359Sroberto#endif
279054359Sroberto		}
279154359Sroberto
279254359Sroberto	return 1;
279354359Sroberto}
279454359Sroberto
279554359Sroberto/*--------------------------------------------------
279654359Sroberto * parse_poll - called by the transmit procedure
279754359Sroberto */
279854359Srobertostatic void
279954359Srobertoparse_poll(
280054359Sroberto	int unit,
280154359Sroberto	struct peer *peer
280254359Sroberto	)
280354359Sroberto{
280454359Sroberto	struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
280554359Sroberto
280654359Sroberto	if (peer != parse->peer)
280754359Sroberto	{
280854359Sroberto		msyslog(LOG_ERR,
280954359Sroberto			"PARSE receiver #%d: poll: INTERNAL: peer incorrect",
281054359Sroberto			unit);
281154359Sroberto		return;
281254359Sroberto	}
281354359Sroberto
281454359Sroberto	/*
281554359Sroberto	 * Update clock stat counters
281654359Sroberto	 */
281754359Sroberto	parse->generic->polls++;
281854359Sroberto
281956746Sroberto	if (parse->pollneeddata &&
282056746Sroberto	    ((current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll)))))
282154359Sroberto	{
282254359Sroberto		/*
282356746Sroberto		 * start worrying when exceeding a poll inteval
282454359Sroberto		 * bad news - didn't get a response last time
282554359Sroberto		 */
282654359Sroberto		parse->generic->noreply++;
282754359Sroberto		parse->lastmissed = current_time;
282854359Sroberto		parse_event(parse, CEVNT_TIMEOUT);
282954359Sroberto
283054359Sroberto		ERR(ERR_NODATA)
283154359Sroberto			msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / cableling)", CLK_UNIT(parse->peer));
283254359Sroberto	}
283354359Sroberto
283454359Sroberto	/*
283554359Sroberto	 * we just mark that we want the next sample for the clock filter
283654359Sroberto	 */
283756746Sroberto	parse->pollneeddata = current_time;
283854359Sroberto
283954359Sroberto	if (parse->parse_type->cl_poll)
284054359Sroberto	{
284154359Sroberto		parse->parse_type->cl_poll(parse);
284254359Sroberto	}
284354359Sroberto
284454359Sroberto	cparse_statistics(parse);
284554359Sroberto
284654359Sroberto	return;
284754359Sroberto}
284854359Sroberto
284954359Sroberto#define LEN_STATES 300		/* length of state string */
285054359Sroberto
285154359Sroberto/*--------------------------------------------------
285254359Sroberto * parse_control - set fudge factors, return statistics
285354359Sroberto */
285454359Srobertostatic void
285554359Srobertoparse_control(
285654359Sroberto	int unit,
285754359Sroberto	struct refclockstat *in,
285854359Sroberto	struct refclockstat *out,
285954359Sroberto	struct peer *peer
286054359Sroberto	)
286154359Sroberto{
286254359Sroberto	register struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
286354359Sroberto	parsectl_t tmpctl;
286454359Sroberto
286554359Sroberto	static char outstatus[400];	/* status output buffer */
286654359Sroberto
286754359Sroberto	if (out)
286854359Sroberto	{
286954359Sroberto		out->lencode       = 0;
287054359Sroberto		out->p_lastcode    = 0;
287154359Sroberto		out->kv_list       = (struct ctl_var *)0;
287254359Sroberto	}
287354359Sroberto
287454359Sroberto	if (!parse || !parse->peer)
287554359Sroberto	{
287654359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)",
287754359Sroberto			unit);
287854359Sroberto		return;
287954359Sroberto	}
288054359Sroberto
288154359Sroberto	unit = CLK_UNIT(parse->peer);
288254359Sroberto
288354359Sroberto	if (in)
288454359Sroberto	{
288554359Sroberto		if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4))
288654359Sroberto		{
288754359Sroberto			parse->flags = in->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4);
288854359Sroberto		}
288954359Sroberto	}
289054359Sroberto
289154359Sroberto	if (out)
289254359Sroberto	{
289354359Sroberto		u_long sum = 0;
289454359Sroberto		char *t, *tt, *start;
289554359Sroberto		int i;
289654359Sroberto
289754359Sroberto		outstatus[0] = '\0';
289854359Sroberto
289954359Sroberto		out->type       = REFCLK_PARSE;
290054359Sroberto		out->haveflags |= CLK_HAVETIME2;
290154359Sroberto
290254359Sroberto		/*
290354359Sroberto		 * figure out skew between PPS and RS232 - just for informational
290454359Sroberto		 * purposes - returned in time2 value
290554359Sroberto		 */
290654359Sroberto		if (PARSE_SYNC(parse->time.parse_state))
290754359Sroberto		{
290854359Sroberto			if (PARSE_PPS(parse->time.parse_state) && PARSE_TIMECODE(parse->time.parse_state))
290954359Sroberto			{
291054359Sroberto				l_fp off;
291154359Sroberto
291254359Sroberto				/*
291354359Sroberto				 * we have a PPS and RS232 signal - calculate the skew
291454359Sroberto				 * WARNING: assumes on TIMECODE == PULSE (timecode after pulse)
291554359Sroberto				 */
291654359Sroberto				off = parse->time.parse_stime.fp;
291754359Sroberto				L_SUB(&off, &parse->time.parse_ptime.fp); /* true offset */
291854359Sroberto				tt = add_var(&out->kv_list, 80, RO);
291954359Sroberto				sprintf(tt, "refclock_ppsskew=%s", lfptoms(&off, 6));
292054359Sroberto			}
292154359Sroberto		}
292254359Sroberto
292354359Sroberto		if (PARSE_PPS(parse->time.parse_state))
292454359Sroberto		{
292554359Sroberto			tt = add_var(&out->kv_list, 80, RO|DEF);
292654359Sroberto			sprintf(tt, "refclock_ppstime=\"%s\"", gmprettydate(&parse->time.parse_ptime.fp));
292754359Sroberto		}
292854359Sroberto
292954359Sroberto		tt = add_var(&out->kv_list, 128, RO|DEF);
293054359Sroberto		sprintf(tt, "refclock_time=\"");
293154359Sroberto		tt += strlen(tt);
293254359Sroberto
293354359Sroberto		if (parse->time.parse_time.fp.l_ui == 0)
293454359Sroberto		{
293554359Sroberto			strcpy(tt, "<UNDEFINED>\"");
293654359Sroberto		}
293754359Sroberto		else
293854359Sroberto		{
293954359Sroberto			sprintf(tt, "%s\"", gmprettydate(&parse->time.parse_time.fp));
294054359Sroberto			t = tt + strlen(tt);
294154359Sroberto		}
294254359Sroberto
294354359Sroberto		if (!PARSE_GETTIMECODE(parse, &tmpctl))
294454359Sroberto		{
294554359Sroberto			ERR(ERR_INTERNAL)
294654359Sroberto				msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit);
294754359Sroberto		}
294854359Sroberto		else
294954359Sroberto		{
295054359Sroberto			tt = add_var(&out->kv_list, 512, RO|DEF);
295154359Sroberto			sprintf(tt, "refclock_status=\"");
295254359Sroberto			tt += strlen(tt);
295354359Sroberto
295454359Sroberto			/*
295554359Sroberto			 * copy PPS flags from last read transaction (informational only)
295654359Sroberto			 */
295754359Sroberto			tmpctl.parsegettc.parse_state |= parse->time.parse_state &
295854359Sroberto				(PARSEB_PPS|PARSEB_S_PPS);
295954359Sroberto
296054359Sroberto			(void) parsestate(tmpctl.parsegettc.parse_state, tt);
296154359Sroberto
296254359Sroberto			strcat(tt, "\"");
296354359Sroberto
296454359Sroberto			if (tmpctl.parsegettc.parse_count)
296554359Sroberto			    mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1),
296654359Sroberto				    tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1));
296754359Sroberto
296854359Sroberto			parse->generic->badformat += tmpctl.parsegettc.parse_badformat;
296954359Sroberto		}
297054359Sroberto
297154359Sroberto		tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format;
297254359Sroberto
297354359Sroberto		if (!PARSE_GETFMT(parse, &tmpctl))
297454359Sroberto		{
297554359Sroberto			ERR(ERR_INTERNAL)
297654359Sroberto				msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit);
297754359Sroberto		}
297854359Sroberto		else
297954359Sroberto		{
298054359Sroberto			tt = add_var(&out->kv_list, 80, RO|DEF);
298154359Sroberto			sprintf(tt, "refclock_format=\"");
298254359Sroberto
298354359Sroberto			strncat(tt, tmpctl.parseformat.parse_buffer, tmpctl.parseformat.parse_count);
298454359Sroberto			strcat(tt,"\"");
298554359Sroberto		}
298654359Sroberto
298754359Sroberto		/*
298854359Sroberto		 * gather state statistics
298954359Sroberto		 */
299054359Sroberto
299154359Sroberto		start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF);
299254359Sroberto		strcpy(tt, "refclock_states=\"");
299354359Sroberto		tt += strlen(tt);
299454359Sroberto
299554359Sroberto		for (i = 0; i <= CEVNT_MAX; i++)
299654359Sroberto		{
299754359Sroberto			u_long s_time;
299854359Sroberto			u_long d = current_time - parse->generic->timestarted;
299954359Sroberto			u_long percent;
300054359Sroberto
300154359Sroberto			percent = s_time = PARSE_STATETIME(parse, i);
300254359Sroberto
300354359Sroberto			while (((u_long)(~0) / 10000) < percent)
300454359Sroberto			{
300554359Sroberto				percent /= 10;
300654359Sroberto				d       /= 10;
300754359Sroberto			}
300854359Sroberto
300954359Sroberto			if (d)
301054359Sroberto			    percent = (percent * 10000) / d;
301154359Sroberto			else
301254359Sroberto			    percent = 10000;
301354359Sroberto
301454359Sroberto			if (s_time)
301554359Sroberto			{
301654359Sroberto				char item[80];
301754359Sroberto				int count;
301854359Sroberto
301954359Sroberto				sprintf(item, "%s%s%s: %s (%d.%02d%%)",
302054359Sroberto					sum ? "; " : "",
302154359Sroberto					(parse->generic->currentstatus == i) ? "*" : "",
302254359Sroberto					clockstatus((unsigned int)i),
302354359Sroberto					l_mktime(s_time),
302454359Sroberto					(int)(percent / 100), (int)(percent % 100));
302554359Sroberto				if ((count = strlen(item)) < (LEN_STATES - 40 - (tt - start)))
302654359Sroberto					{
302754359Sroberto						strcpy(tt, item);
302854359Sroberto						tt  += count;
302954359Sroberto					}
303054359Sroberto				sum += s_time;
303154359Sroberto			}
303254359Sroberto		}
303354359Sroberto
303454359Sroberto		sprintf(tt, "; running time: %s\"", l_mktime(sum));
303554359Sroberto
303654359Sroberto		tt = add_var(&out->kv_list, 32, RO);
303754359Sroberto		sprintf(tt, "refclock_id=\"%s\"", parse->parse_type->cl_id);
303854359Sroberto
303954359Sroberto		tt = add_var(&out->kv_list, 80, RO);
304054359Sroberto		sprintf(tt, "refclock_iomode=\"%s\"", parse->binding->bd_description);
304154359Sroberto
304254359Sroberto		tt = add_var(&out->kv_list, 128, RO);
304354359Sroberto		sprintf(tt, "refclock_driver_version=\"%s\"", rcsid);
304454359Sroberto
304554359Sroberto		{
304654359Sroberto			struct ctl_var *k;
304754359Sroberto
304854359Sroberto			k = parse->kv;
304954359Sroberto			while (k && !(k->flags & EOV))
305054359Sroberto			{
305154359Sroberto				set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags);
305254359Sroberto				k++;
305354359Sroberto			}
305454359Sroberto		}
305554359Sroberto
305654359Sroberto		out->lencode       = strlen(outstatus);
305754359Sroberto		out->p_lastcode    = outstatus;
305854359Sroberto	}
305954359Sroberto}
306054359Sroberto
306154359Sroberto/**===========================================================================
306254359Sroberto ** processing routines
306354359Sroberto **/
306454359Sroberto
306554359Sroberto/*--------------------------------------------------
306654359Sroberto * event handling - note that nominal events will also be posted
306754359Sroberto */
306854359Srobertostatic void
306954359Srobertoparse_event(
307054359Sroberto	struct parseunit *parse,
307154359Sroberto	int event
307254359Sroberto	)
307354359Sroberto{
307454359Sroberto	if (parse->generic->currentstatus != (u_char) event)
307554359Sroberto	{
307654359Sroberto		parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange;
307754359Sroberto		parse->lastchange              = current_time;
307854359Sroberto
307954359Sroberto		parse->generic->currentstatus    = (u_char)event;
308054359Sroberto
308154359Sroberto		if (parse->parse_type->cl_event)
308254359Sroberto		    parse->parse_type->cl_event(parse, event);
308354359Sroberto
308454359Sroberto		if (event != CEVNT_NOMINAL)
308554359Sroberto		{
308654359Sroberto	  parse->generic->lastevent = parse->generic->currentstatus;
308754359Sroberto		}
308854359Sroberto		else
308954359Sroberto		{
309054359Sroberto			NLOG(NLOG_CLOCKSTATUS)
309154359Sroberto				msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED",
309254359Sroberto					CLK_UNIT(parse->peer));
309354359Sroberto		}
309454359Sroberto
309554359Sroberto		if (event == CEVNT_FAULT)
309654359Sroberto		{
309754359Sroberto			NLOG(NLOG_CLOCKEVENT) /* conditional if clause for conditional syslog */
309854359Sroberto				ERR(ERR_BADEVENT)
309954359Sroberto				msyslog(LOG_ERR,
310054359Sroberto					"clock %s fault '%s' (0x%02x)", refnumtoa(parse->peer->srcadr.sin_addr.s_addr), ceventstr(event),
310154359Sroberto					(u_int)event);
310254359Sroberto		}
310354359Sroberto		else
310454359Sroberto		{
310554359Sroberto			NLOG(NLOG_CLOCKEVENT) /* conditional if clause for conditional syslog */
310654359Sroberto				if (event == CEVNT_NOMINAL || list_err(parse, ERR_BADEVENT))
310754359Sroberto				    msyslog(LOG_INFO,
310854359Sroberto					    "clock %s event '%s' (0x%02x)", refnumtoa(parse->peer->srcadr.sin_addr.s_addr), ceventstr(event),
310954359Sroberto					    (u_int)event);
311054359Sroberto		}
311154359Sroberto
311254359Sroberto		report_event(EVNT_PEERCLOCK, parse->peer);
311354359Sroberto		report_event(EVNT_CLOCKEXCPT, parse->peer);
311454359Sroberto	}
311554359Sroberto}
311654359Sroberto
311754359Sroberto/*--------------------------------------------------
311854359Sroberto * process a PARSE time sample
311954359Sroberto */
312054359Srobertostatic void
312154359Srobertoparse_process(
312254359Sroberto	struct parseunit *parse,
312354359Sroberto	parsetime_t      *parsetime
312454359Sroberto	)
312554359Sroberto{
312654359Sroberto	l_fp off, rectime, reftime;
312754359Sroberto	double fudge;
312854359Sroberto
312954359Sroberto	/*
313054359Sroberto	 * check for changes in conversion status
313154359Sroberto	 * (only one for each new status !)
313254359Sroberto	 */
313354359Sroberto	if (((parsetime->parse_status & CVT_MASK) != CVT_OK) &&
313454359Sroberto	    ((parsetime->parse_status & CVT_MASK) != CVT_NONE) &&
313554359Sroberto	    (parse->time.parse_status != parsetime->parse_status))
313654359Sroberto	{
313754359Sroberto		char buffer[400];
313854359Sroberto
313954359Sroberto		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
314054359Sroberto			msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"",
314154359Sroberto				CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer));
314254359Sroberto
314354359Sroberto		if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL)
314454359Sroberto		{
314554359Sroberto			/*
314654359Sroberto			 * tell more about the story - list time code
314754359Sroberto			 * there is a slight change for a race condition and
314854359Sroberto			 * the time code might be overwritten by the next packet
314954359Sroberto			 */
315054359Sroberto			parsectl_t tmpctl;
315154359Sroberto
315254359Sroberto			if (!PARSE_GETTIMECODE(parse, &tmpctl))
315354359Sroberto			{
315454359Sroberto				ERR(ERR_INTERNAL)
315554359Sroberto					msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer));
315654359Sroberto			}
315754359Sroberto			else
315854359Sroberto			{
315954359Sroberto				ERR(ERR_BADDATA)
316054359Sroberto					msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / cableling)",
316154359Sroberto						CLK_UNIT(parse->peer), mkascii(buffer, sizeof buffer, tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1)));
316254359Sroberto				parse->generic->badformat += tmpctl.parsegettc.parse_badformat;
316354359Sroberto			}
316454359Sroberto		}
316554359Sroberto	}
316654359Sroberto
316754359Sroberto	/*
316854359Sroberto	 * examine status and post appropriate events
316954359Sroberto	 */
317054359Sroberto	if ((parsetime->parse_status & CVT_MASK) != CVT_OK)
317154359Sroberto	{
317254359Sroberto		/*
317354359Sroberto		 * got bad data - tell the rest of the system
317454359Sroberto		 */
317554359Sroberto		switch (parsetime->parse_status & CVT_MASK)
317654359Sroberto		{
317754359Sroberto		case CVT_NONE:
317854359Sroberto			if ((parsetime->parse_status & CVT_ADDITIONAL) &&
317954359Sroberto			    parse->parse_type->cl_message)
318054359Sroberto				parse->parse_type->cl_message(parse, parsetime);
318154359Sroberto			break; 		/* well, still waiting - timeout is handled at higher levels */
318254359Sroberto
318354359Sroberto		case CVT_FAIL:
318454359Sroberto			parse->generic->badformat++;
318554359Sroberto			if (parsetime->parse_status & CVT_BADFMT)
318654359Sroberto			{
318754359Sroberto				parse_event(parse, CEVNT_BADREPLY);
318854359Sroberto			}
318954359Sroberto			else
319054359Sroberto				if (parsetime->parse_status & CVT_BADDATE)
319154359Sroberto				{
319254359Sroberto					parse_event(parse, CEVNT_BADDATE);
319354359Sroberto				}
319454359Sroberto				else
319554359Sroberto					if (parsetime->parse_status & CVT_BADTIME)
319654359Sroberto					{
319754359Sroberto						parse_event(parse, CEVNT_BADTIME);
319854359Sroberto					}
319954359Sroberto					else
320054359Sroberto					{
320154359Sroberto						parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */
320254359Sroberto					}
320354359Sroberto		}
320454359Sroberto		return;			/* skip the rest - useless */
320554359Sroberto	}
320654359Sroberto
320754359Sroberto	/*
320854359Sroberto	 * check for format changes
320954359Sroberto	 * (in case somebody has swapped clocks 8-)
321054359Sroberto	 */
321154359Sroberto	if (parse->lastformat != parsetime->parse_format)
321254359Sroberto	{
321354359Sroberto		parsectl_t tmpctl;
321454359Sroberto
321554359Sroberto		tmpctl.parseformat.parse_format = parsetime->parse_format;
321654359Sroberto
321754359Sroberto		if (!PARSE_GETFMT(parse, &tmpctl))
321854359Sroberto		{
321954359Sroberto			ERR(ERR_INTERNAL)
322054359Sroberto				msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer));
322154359Sroberto		}
322254359Sroberto		else
322354359Sroberto		{
322454359Sroberto			NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
322554359Sroberto				msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"",
322654359Sroberto					CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer);
322754359Sroberto		}
322854359Sroberto		parse->lastformat = parsetime->parse_format;
322954359Sroberto	}
323054359Sroberto
323154359Sroberto	/*
323254359Sroberto	 * now, any changes ?
323354359Sroberto	 */
323454359Sroberto	if (parse->time.parse_state != parsetime->parse_state)
323554359Sroberto	{
323654359Sroberto		char tmp1[200];
323754359Sroberto		char tmp2[200];
323854359Sroberto		/*
323954359Sroberto		 * something happend
324054359Sroberto		 */
324154359Sroberto
324254359Sroberto		(void) parsestate(parsetime->parse_state, tmp1);
324354359Sroberto		(void) parsestate(parse->time.parse_state, tmp2);
324454359Sroberto
324554359Sroberto		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
324654359Sroberto			msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s",
324754359Sroberto				CLK_UNIT(parse->peer), tmp2, tmp1);
324854359Sroberto	}
324954359Sroberto
325054359Sroberto	/*
325154359Sroberto	 * remember for future
325254359Sroberto	 */
325354359Sroberto	parse->time = *parsetime;
325454359Sroberto
325554359Sroberto	/*
325654359Sroberto	 * check to see, whether the clock did a complete powerup or lost PZF signal
325754359Sroberto	 * and post correct events for current condition
325854359Sroberto	 */
325954359Sroberto	if (PARSE_POWERUP(parsetime->parse_state))
326054359Sroberto	{
326154359Sroberto		/*
326254359Sroberto		 * this is bad, as we have completely lost synchronisation
326354359Sroberto		 * well this is a problem with the receiver here
326454359Sroberto		 * for PARSE Meinberg DCF77 receivers the lost synchronisation
326554359Sroberto		 * is true as it is the powerup state and the time is taken
326654359Sroberto		 * from a crude real time clock chip
326754359Sroberto		 * for the PZF series this is only partly true, as
326854359Sroberto		 * PARSE_POWERUP only means that the pseudo random
326954359Sroberto		 * phase shift sequence cannot be found. this is only
327054359Sroberto		 * bad, if we have never seen the clock in the SYNC
327154359Sroberto		 * state, where the PHASE and EPOCH are correct.
327254359Sroberto		 * for reporting events the above business does not
327354359Sroberto		 * really matter, but we can use the time code
327454359Sroberto		 * even in the POWERUP state after having seen
327554359Sroberto		 * the clock in the synchronized state (PZF class
327654359Sroberto		 * receivers) unless we have had a telegram disruption
327754359Sroberto		 * after having seen the clock in the SYNC state. we
327854359Sroberto		 * thus require having seen the clock in SYNC state
327954359Sroberto		 * *after* having missed telegrams (noresponse) from
328054359Sroberto		 * the clock. one problem remains: we might use erroneously
328154359Sroberto		 * POWERUP data if the disruption is shorter than 1 polling
328254359Sroberto		 * interval. fortunately powerdowns last usually longer than 64
328354359Sroberto		 * seconds and the receiver is at least 2 minutes in the
328454359Sroberto		 * POWERUP or NOSYNC state before switching to SYNC
328554359Sroberto		 */
328654359Sroberto		parse_event(parse, CEVNT_FAULT);
328754359Sroberto		NLOG(NLOG_CLOCKSTATUS)
328854359Sroberto			ERR(ERR_BADSTATUS)
328954359Sroberto			msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED",
329054359Sroberto				CLK_UNIT(parse->peer));
329154359Sroberto	}
329254359Sroberto	else
329354359Sroberto	{
329454359Sroberto		/*
329554359Sroberto		 * we have two states left
329654359Sroberto		 *
329754359Sroberto		 * SYNC:
329854359Sroberto		 *  this state means that the EPOCH (timecode) and PHASE
329954359Sroberto		 *  information has be read correctly (at least two
330054359Sroberto		 *  successive PARSE timecodes were received correctly)
330154359Sroberto		 *  this is the best possible state - full trust
330254359Sroberto		 *
330354359Sroberto		 * NOSYNC:
330454359Sroberto		 *  The clock should be on phase with respect to the second
330554359Sroberto		 *  signal, but the timecode has not been received correctly within
330654359Sroberto		 *  at least the last two minutes. this is a sort of half baked state
330754359Sroberto		 *  for PARSE Meinberg DCF77 clocks this is bad news (clock running
330854359Sroberto		 *  without timecode confirmation)
330954359Sroberto		 *  PZF 535 has also no time confirmation, but the phase should be
331054359Sroberto		 *  very precise as the PZF signal can be decoded
331154359Sroberto		 */
331254359Sroberto
331354359Sroberto		if (PARSE_SYNC(parsetime->parse_state))
331454359Sroberto		{
331554359Sroberto			/*
331654359Sroberto			 * currently completely synchronized - best possible state
331754359Sroberto			 */
331854359Sroberto			parse->lastsync = current_time;
331954359Sroberto			clear_err(parse, ERR_BADSTATUS);
332054359Sroberto		}
332154359Sroberto		else
332254359Sroberto		{
332354359Sroberto			/*
332454359Sroberto			 * we have had some problems receiving the time code
332554359Sroberto			 */
332654359Sroberto			parse_event(parse, CEVNT_PROP);
332754359Sroberto			NLOG(NLOG_CLOCKSTATUS)
332854359Sroberto				ERR(ERR_BADSTATUS)
332954359Sroberto				msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED",
333054359Sroberto					CLK_UNIT(parse->peer));
333154359Sroberto		}
333254359Sroberto	}
333354359Sroberto
333454359Sroberto	fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */
333554359Sroberto
333654359Sroberto	if (PARSE_TIMECODE(parsetime->parse_state))
333754359Sroberto	{
333854359Sroberto		rectime = parsetime->parse_stime.fp;
333954359Sroberto		off = reftime = parsetime->parse_time.fp;
334054359Sroberto
334154359Sroberto		L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */
334254359Sroberto
334354359Sroberto#ifdef DEBUG
334454359Sroberto		if (debug > 3)
334554359Sroberto			printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n",
334654359Sroberto			       CLK_UNIT(parse->peer),
334754359Sroberto			       prettydate(&reftime),
334854359Sroberto			       prettydate(&rectime),
334954359Sroberto			       lfptoa(&off,6));
335054359Sroberto#endif
335154359Sroberto	}
335254359Sroberto
335354359Sroberto	if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
335454359Sroberto	{
335554359Sroberto		l_fp offset;
335654359Sroberto
335754359Sroberto		/*
335854359Sroberto		 * we have a PPS signal - much better than the RS232 stuff (we hope)
335954359Sroberto		 */
336054359Sroberto		offset = parsetime->parse_ptime.fp;
336154359Sroberto
336254359Sroberto#ifdef DEBUG
336354359Sroberto		if (debug > 3)
336454359Sroberto			printf("PARSE receiver #%d: PPStime %s\n",
336554359Sroberto				CLK_UNIT(parse->peer),
336654359Sroberto				prettydate(&offset));
336754359Sroberto#endif
336854359Sroberto		if (PARSE_TIMECODE(parsetime->parse_state))
336954359Sroberto		{
337054359Sroberto			if (M_ISGEQ(off.l_i, off.l_f, -1, 0x80000000) &&
337154359Sroberto			    M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_f))
337254359Sroberto			{
337354359Sroberto				fudge = parse->generic->fudgetime2; /* pick PPS fudge factor */
337454359Sroberto
337554359Sroberto				/*
337654359Sroberto				 * RS232 offsets within [-0.5..0.5[ - take PPS offsets
337754359Sroberto				 */
337854359Sroberto
337954359Sroberto				if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND)
338054359Sroberto				{
338154359Sroberto					reftime = off = offset;
338254359Sroberto					if (reftime.l_uf & (unsigned)0x80000000)
338354359Sroberto						reftime.l_ui++;
338454359Sroberto					reftime.l_uf = 0;
338556746Sroberto
338654359Sroberto
338754359Sroberto					/*
338854359Sroberto					 * implied on second offset
338954359Sroberto					 */
339054359Sroberto					off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
339154359Sroberto					off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */
339254359Sroberto				}
339354359Sroberto				else
339454359Sroberto				{
339554359Sroberto					/*
339654359Sroberto					 * time code describes pulse
339754359Sroberto					 */
339854359Sroberto					reftime = off = parsetime->parse_time.fp;
339954359Sroberto
340054359Sroberto					L_SUB(&off, &offset); /* true offset */
340154359Sroberto				}
340254359Sroberto			}
340354359Sroberto			/*
340454359Sroberto			 * take RS232 offset when PPS when out of bounds
340554359Sroberto			 */
340654359Sroberto		}
340754359Sroberto		else
340854359Sroberto		{
340954359Sroberto			fudge = parse->generic->fudgetime2; /* pick PPS fudge factor */
341054359Sroberto			/*
341154359Sroberto			 * Well, no time code to guide us - assume on second pulse
341254359Sroberto			 * and pray, that we are within [-0.5..0.5[
341354359Sroberto			 */
341454359Sroberto			off = offset;
341554359Sroberto			reftime = offset;
341654359Sroberto			if (reftime.l_uf & (unsigned)0x80000000)
341754359Sroberto				reftime.l_ui++;
341854359Sroberto			reftime.l_uf = 0;
341954359Sroberto			/*
342054359Sroberto			 * implied on second offset
342154359Sroberto			 */
342254359Sroberto			off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
342354359Sroberto			off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */
342454359Sroberto		}
342554359Sroberto	}
342654359Sroberto	else
342754359Sroberto	{
342854359Sroberto		if (!PARSE_TIMECODE(parsetime->parse_state))
342954359Sroberto		{
343054359Sroberto			/*
343154359Sroberto			 * Well, no PPS, no TIMECODE, no more work ...
343254359Sroberto			 */
343354359Sroberto			if ((parsetime->parse_status & CVT_ADDITIONAL) &&
343454359Sroberto			    parse->parse_type->cl_message)
343554359Sroberto				parse->parse_type->cl_message(parse, parsetime);
343654359Sroberto			return;
343754359Sroberto		}
343854359Sroberto	}
343954359Sroberto
344054359Sroberto#ifdef DEBUG
344154359Sroberto	if (debug > 3)
344254359Sroberto		printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n",
344354359Sroberto			CLK_UNIT(parse->peer),
344454359Sroberto			prettydate(&reftime),
344554359Sroberto			prettydate(&rectime),
344654359Sroberto			lfptoa(&off,6));
344754359Sroberto#endif
344854359Sroberto
344954359Sroberto
345054359Sroberto	rectime = reftime;
345154359Sroberto	L_SUB(&rectime, &off);	/* just to keep the ntp interface happy */
345254359Sroberto
345354359Sroberto#ifdef DEBUG
345454359Sroberto	if (debug > 3)
345554359Sroberto		printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n",
345654359Sroberto			CLK_UNIT(parse->peer),
345754359Sroberto			prettydate(&reftime),
345854359Sroberto			prettydate(&rectime));
345954359Sroberto#endif
346054359Sroberto
346154359Sroberto	if ((parsetime->parse_status & CVT_ADDITIONAL) &&
346254359Sroberto	    parse->parse_type->cl_message)
346354359Sroberto		parse->parse_type->cl_message(parse, parsetime);
346454359Sroberto
346554359Sroberto	if (PARSE_SYNC(parsetime->parse_state))
346654359Sroberto	{
346754359Sroberto		/*
346854359Sroberto		 * log OK status
346954359Sroberto		 */
347054359Sroberto		parse_event(parse, CEVNT_NOMINAL);
347154359Sroberto	}
347254359Sroberto
347354359Sroberto	clear_err(parse, ERR_BADIO);
347454359Sroberto	clear_err(parse, ERR_BADDATA);
347554359Sroberto	clear_err(parse, ERR_NODATA);
347654359Sroberto	clear_err(parse, ERR_INTERNAL);
347754359Sroberto
347854359Sroberto#ifdef DEBUG
347954359Sroberto	if (debug > 2)
348054359Sroberto		{
348154359Sroberto			printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n",
348254359Sroberto				CLK_UNIT(parse->peer),
348354359Sroberto				prettydate(&reftime),
348454359Sroberto				prettydate(&rectime),
348554359Sroberto				fudge);
348654359Sroberto		}
348754359Sroberto#endif
348854359Sroberto
348954359Sroberto	refclock_process_offset(parse->generic, reftime, rectime, fudge);
349054359Sroberto	if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
349154359Sroberto	{
349254359Sroberto		(void) pps_sample(&parse->time.parse_ptime.fp);
349354359Sroberto	}
349454359Sroberto
349554359Sroberto
349654359Sroberto	/*
349754359Sroberto	 * and now stick it into the clock machine
349854359Sroberto	 * samples are only valid iff lastsync is not too old and
349954359Sroberto	 * we have seen the clock in sync at least once
350054359Sroberto	 * after the last time we didn't see an expected data telegram
350154359Sroberto	 * see the clock states section above for more reasoning
350254359Sroberto	 */
350354359Sroberto	if (((current_time - parse->lastsync) > parse->parse_type->cl_maxunsync) ||
350454359Sroberto	    (parse->lastsync <= parse->lastmissed))
350554359Sroberto	{
350654359Sroberto		parse->generic->leap = LEAP_NOTINSYNC;
350754359Sroberto	}
350854359Sroberto	else
350954359Sroberto	{
351054359Sroberto		if (PARSE_LEAPADD(parsetime->parse_state))
351154359Sroberto		{
351254359Sroberto			/*
351354359Sroberto			 * we pick this state also for time code that pass leap warnings
351454359Sroberto			 * without direction information (as earth is currently slowing
351554359Sroberto			 * down).
351654359Sroberto			 */
351754359Sroberto			parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND;
351854359Sroberto		}
351954359Sroberto		else
352054359Sroberto		    if (PARSE_LEAPDEL(parsetime->parse_state))
352154359Sroberto		    {
352254359Sroberto			    parse->generic->leap = LEAP_DELSECOND;
352354359Sroberto		    }
352454359Sroberto		    else
352554359Sroberto		    {
352654359Sroberto			    parse->generic->leap = LEAP_NOWARNING;
352754359Sroberto		    }
352854359Sroberto	}
352954359Sroberto
353054359Sroberto	/*
353154359Sroberto	 * ready, unless the machine wants a sample
353254359Sroberto	 */
353354359Sroberto	if (!parse->pollneeddata)
353454359Sroberto	    return;
353554359Sroberto
353654359Sroberto	parse->pollneeddata = 0;
353754359Sroberto
353854359Sroberto	refclock_receive(parse->peer);
353954359Sroberto}
354056746Sroberto
354154359Sroberto/**===========================================================================
354254359Sroberto ** special code for special clocks
354354359Sroberto **/
354454359Sroberto
354554359Srobertostatic void
354654359Srobertomk_utcinfo(
354754359Sroberto	   char *t,
354854359Sroberto	   int wnt,
354954359Sroberto	   int wnlsf,
355054359Sroberto	   int dn,
355154359Sroberto	   int dtls,
355254359Sroberto	   int dtlsf
355354359Sroberto	   )
355454359Sroberto{
355554359Sroberto  l_fp leapdate;
355654359Sroberto
355754359Sroberto  sprintf(t, "current correction %d sec", dtls);
355854359Sroberto  t += strlen(t);
355954359Sroberto
356054359Sroberto  if (wnlsf < 990)
356154359Sroberto    wnlsf += 1024;
356254359Sroberto
356354359Sroberto  if (wnt < 990)
356454359Sroberto    wnt += 1024;
356554359Sroberto
356654359Sroberto  gpstolfp((unsigned short)wnlsf, (unsigned short)dn, 0, &leapdate);
356754359Sroberto
356854359Sroberto  if ((dtlsf != dtls) &&
356954359Sroberto      ((wnlsf - wnt) < 52))
357054359Sroberto    {
357154359Sroberto      sprintf(t, ", next correction %d sec on %s, new GPS-UTC offset %d",
357254359Sroberto	      dtlsf - dtls, gmprettydate(&leapdate), dtlsf);
357354359Sroberto    }
357454359Sroberto  else
357554359Sroberto    {
357654359Sroberto      sprintf(t, ", last correction on %s",
357754359Sroberto	      gmprettydate(&leapdate));
357854359Sroberto    }
357954359Sroberto}
358054359Sroberto
358154359Sroberto#ifdef CLOCK_MEINBERG
358254359Sroberto/**===========================================================================
358354359Sroberto ** Meinberg GPS166/GPS167 support
358454359Sroberto **/
358554359Sroberto
358654359Sroberto/*------------------------------------------------------------
358754359Sroberto * gps16x_message - process GPS16x messages
358854359Sroberto */
358954359Srobertostatic void
359054359Srobertogps16x_message(
359154359Sroberto	       struct parseunit *parse,
359254359Sroberto	       parsetime_t      *parsetime
359354359Sroberto	       )
359454359Sroberto{
359554359Sroberto	if (parse->time.parse_msglen && parsetime->parse_msg[0] == SOH)
359654359Sroberto	{
359754359Sroberto		GPS_MSG_HDR header;
359854359Sroberto		unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1;
359954359Sroberto
360054359Sroberto#ifdef DEBUG
360154359Sroberto		if (debug > 2)
360254359Sroberto		{
360354359Sroberto			char msgbuffer[600];
360454359Sroberto
360554359Sroberto			mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1);
360654359Sroberto			printf("PARSE receiver #%d: received message (%d bytes) >%s<\n",
360754359Sroberto				CLK_UNIT(parse->peer),
360854359Sroberto				parsetime->parse_msglen,
360954359Sroberto				msgbuffer);
361054359Sroberto		}
361154359Sroberto#endif
361254359Sroberto		get_mbg_header(&bufp, &header);
361354359Sroberto		if (header.gps_hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) &&
361454359Sroberto		    (header.gps_len == 0 ||
361554359Sroberto		     (header.gps_len < sizeof(parsetime->parse_msg) &&
361654359Sroberto		      header.gps_data_csum == mbg_csum(bufp, header.gps_len))))
361754359Sroberto		{
361854359Sroberto			/*
361954359Sroberto			 * clean message
362054359Sroberto			 */
362154359Sroberto			switch (header.gps_cmd)
362254359Sroberto			{
362354359Sroberto			case GPS_SW_REV:
362454359Sroberto				{
362554359Sroberto					char buffer[64];
362654359Sroberto					SW_REV gps_sw_rev;
362754359Sroberto
362854359Sroberto					get_mbg_sw_rev(&bufp, &gps_sw_rev);
362954359Sroberto					sprintf(buffer, "meinberg_gps_version=\"%x.%02x%s%s\"",
363054359Sroberto						(gps_sw_rev.code >> 8) & 0xFF,
363154359Sroberto						gps_sw_rev.code & 0xFF,
363254359Sroberto						gps_sw_rev.name[0] ? " " : "",
363354359Sroberto						gps_sw_rev.name);
363454359Sroberto					set_var(&parse->kv, buffer, 64, RO|DEF);
363554359Sroberto				}
363654359Sroberto			break;
363754359Sroberto
363854359Sroberto			case GPS_STAT:
363954359Sroberto				{
364054359Sroberto					static struct state
364154359Sroberto					{
364254359Sroberto						unsigned short flag; /* status flag */
364354359Sroberto						unsigned const char *string; /* bit name */
364454359Sroberto					} states[] =
364554359Sroberto					  {
364654359Sroberto						  { TM_ANT_DISCONN, (const unsigned char *)"ANTENNA FAULTY" },
364754359Sroberto						  { TM_SYN_FLAG,    (const unsigned char *)"NO SYNC SIGNAL" },
364854359Sroberto						  { TM_NO_SYNC,     (const unsigned char *)"NO SYNC POWERUP" },
364954359Sroberto						  { TM_NO_POS,      (const unsigned char *)"NO POSITION" },
365054359Sroberto						  { 0, (const unsigned char *)"" }
365154359Sroberto					  };
365254359Sroberto					unsigned short status;
365354359Sroberto					struct state *s = states;
365454359Sroberto					char buffer[512];
365554359Sroberto					char *p, *b;
365654359Sroberto
365754359Sroberto					status = get_lsb_short(&bufp);
365854359Sroberto					sprintf(buffer, "meinberg_gps_status=\"[0x%04x] ", status);
365954359Sroberto
366054359Sroberto					if (status)
366154359Sroberto					{
366254359Sroberto						p = b = buffer + strlen(buffer);
366354359Sroberto						while (s->flag)
366454359Sroberto						{
366554359Sroberto							if (status & s->flag)
366654359Sroberto							{
366754359Sroberto								if (p != b)
366854359Sroberto								{
366954359Sroberto									*p++ = ',';
367054359Sroberto									*p++ = ' ';
367154359Sroberto								}
367254359Sroberto
367354359Sroberto								strcat(p, (const char *)s->string);
367454359Sroberto							}
367554359Sroberto							s++;
367654359Sroberto						}
367754359Sroberto
367854359Sroberto						*p++ = '"';
367954359Sroberto						*p   = '\0';
368054359Sroberto					}
368154359Sroberto					else
368254359Sroberto					{
368354359Sroberto						strcat(buffer, "<OK>\"");
368454359Sroberto					}
368554359Sroberto
368654359Sroberto					set_var(&parse->kv, buffer, 64, RO|DEF);
368754359Sroberto				}
368854359Sroberto			break;
368954359Sroberto
369054359Sroberto			case GPS_POS_XYZ:
369154359Sroberto				{
369254359Sroberto					XYZ xyz;
369354359Sroberto					char buffer[256];
369454359Sroberto
369554359Sroberto					get_mbg_xyz(&bufp, xyz);
369654359Sroberto					sprintf(buffer, "gps_position(XYZ)=\"%s m, %s m, %s m\"",
369754359Sroberto						mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1),
369854359Sroberto						mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1),
369954359Sroberto						mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1));
370054359Sroberto
370154359Sroberto					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
370254359Sroberto				}
370354359Sroberto			break;
370454359Sroberto
370554359Sroberto			case GPS_POS_LLA:
370654359Sroberto				{
370754359Sroberto					LLA lla;
370854359Sroberto					char buffer[256];
370954359Sroberto
371054359Sroberto					get_mbg_lla(&bufp, lla);
371154359Sroberto
371254359Sroberto					sprintf(buffer, "gps_position(LLA)=\"%s deg, %s deg, %s m\"",
371354359Sroberto						mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4),
371454359Sroberto						mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4),
371554359Sroberto						mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1));
371654359Sroberto
371754359Sroberto					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
371854359Sroberto				}
371954359Sroberto			break;
372054359Sroberto
372154359Sroberto			case GPS_TZDL:
372254359Sroberto				break;
372354359Sroberto
372454359Sroberto			case GPS_PORT_PARM:
372554359Sroberto				break;
372654359Sroberto
372754359Sroberto			case GPS_SYNTH:
372854359Sroberto				break;
372954359Sroberto
373054359Sroberto			case GPS_ANT_INFO:
373154359Sroberto				{
373254359Sroberto					ANT_INFO antinfo;
373354359Sroberto					char buffer[512];
373454359Sroberto					char *p;
373554359Sroberto
373654359Sroberto					get_mbg_antinfo(&bufp, &antinfo);
373754359Sroberto					sprintf((char *)buffer, "meinberg_antenna_status=\"");
373854359Sroberto					p = buffer + strlen(buffer);
373954359Sroberto
374054359Sroberto					switch (antinfo.status)
374154359Sroberto					{
374254359Sroberto					case ANT_INVALID:
374354359Sroberto						strcat(p, "<OK>");
374454359Sroberto						p += strlen(p);
374554359Sroberto						break;
374654359Sroberto
374754359Sroberto					case ANT_DISCONN:
374854359Sroberto						strcat(p, "DISCONNECTED since ");
374954359Sroberto						NLOG(NLOG_CLOCKSTATUS)
375054359Sroberto							ERR(ERR_BADSTATUS)
375154359Sroberto							msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s",
375254359Sroberto								CLK_UNIT(parse->peer), p);
375354359Sroberto
375454359Sroberto						p += strlen(p);
375554359Sroberto						mbg_tm_str((unsigned char **)&p, &antinfo.tm_disconn);
375654359Sroberto						*p = '\0';
375754359Sroberto						break;
375854359Sroberto
375954359Sroberto					case ANT_RECONN:
376054359Sroberto						strcat(p, "RECONNECTED on ");
376154359Sroberto						p += strlen(p);
376254359Sroberto						mbg_tm_str((unsigned char **)&p, &antinfo.tm_reconn);
376354359Sroberto						sprintf(p, ", reconnect clockoffset %c%ld.%07ld s, disconnect time ",
376454359Sroberto							(antinfo.delta_t < 0) ? '-' : '+',
376554359Sroberto							ABS(antinfo.delta_t) / 10000,
376654359Sroberto							ABS(antinfo.delta_t) % 10000);
376754359Sroberto						p += strlen(p);
376854359Sroberto						mbg_tm_str((unsigned char **)&p, &antinfo.tm_disconn);
376954359Sroberto						*p = '\0';
377054359Sroberto						break;
377154359Sroberto
377254359Sroberto					default:
377354359Sroberto						sprintf(p, "bad status 0x%04x", antinfo.status);
377454359Sroberto						p += strlen(p);
377554359Sroberto						break;
377654359Sroberto					}
377754359Sroberto
377854359Sroberto					*p++ = '"';
377954359Sroberto					*p   = '\0';
378054359Sroberto
378154359Sroberto					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
378254359Sroberto				}
378354359Sroberto			break;
378454359Sroberto
378554359Sroberto			case GPS_UCAP:
378654359Sroberto				break;
378754359Sroberto
378854359Sroberto			case GPS_CFGH:
378954359Sroberto				{
379054359Sroberto					CFGH cfgh;
379154359Sroberto					char buffer[512];
379254359Sroberto					char *p;
379354359Sroberto
379454359Sroberto					get_mbg_cfgh(&bufp, &cfgh);
379554359Sroberto					if (cfgh.valid)
379654359Sroberto					{
379754359Sroberto						int i;
379854359Sroberto
379954359Sroberto						p = buffer;
380054359Sroberto						strcpy(buffer, "gps_tot_51=\"");
380154359Sroberto						p += strlen(p);
380254359Sroberto						mbg_tgps_str((unsigned char **)&p, &cfgh.tot_51);
380354359Sroberto						*p++ = '"';
380454359Sroberto						*p   = '\0';
380554359Sroberto						set_var(&parse->kv, buffer, sizeof(buffer), RO);
380654359Sroberto
380754359Sroberto						p = buffer;
380854359Sroberto						strcpy(buffer, "gps_tot_63=\"");
380954359Sroberto						p += strlen(p);
381054359Sroberto						mbg_tgps_str((unsigned char **)&p, &cfgh.tot_63);
381154359Sroberto						*p++ = '"';
381254359Sroberto						*p   = '\0';
381354359Sroberto						set_var(&parse->kv, buffer, sizeof(buffer), RO);
381454359Sroberto
381554359Sroberto						p = buffer;
381654359Sroberto						strcpy(buffer, "gps_t0a=\"");
381754359Sroberto						p += strlen(p);
381854359Sroberto						mbg_tgps_str((unsigned char **)&p, &cfgh.t0a);
381954359Sroberto						*p++ = '"';
382054359Sroberto						*p   = '\0';
382154359Sroberto						set_var(&parse->kv, buffer, sizeof(buffer), RO);
382254359Sroberto
382354359Sroberto						for (i = MIN_SVNO; i <= MAX_SVNO; i++)
382454359Sroberto						{
382554359Sroberto							p = buffer;
382654359Sroberto							sprintf(p, "gps_cfg[%d]=\"[0x%x] ", i, cfgh.cfg[i]);
382754359Sroberto							p += strlen(p);
382854359Sroberto							switch (cfgh.cfg[i] & 0x7)
382954359Sroberto							{
383054359Sroberto							case 0:
383154359Sroberto								strcpy(p, "BLOCK I");
383254359Sroberto								break;
383354359Sroberto							case 1:
383454359Sroberto								strcpy(p, "BLOCK II");
383554359Sroberto								break;
383654359Sroberto							default:
383754359Sroberto								sprintf(p, "bad CFG");
383854359Sroberto								break;
383954359Sroberto							}
384054359Sroberto							strcat(p, "\"");
384154359Sroberto							set_var(&parse->kv, buffer, sizeof(buffer), RO);
384254359Sroberto
384354359Sroberto							p = buffer;
384454359Sroberto							sprintf(p, "gps_health[%d]=\"[0x%x] ", i, cfgh.health[i]);
384554359Sroberto							p += strlen(p);
384654359Sroberto							switch ((cfgh.health[i] >> 5) & 0x7 )
384754359Sroberto							{
384854359Sroberto							case 0:
384954359Sroberto								strcpy(p, "OK;");
385054359Sroberto								break;
385154359Sroberto							case 1:
385254359Sroberto								strcpy(p, "PARITY;");
385354359Sroberto								break;
385454359Sroberto							case 2:
385554359Sroberto								strcpy(p, "TLM/HOW;");
385654359Sroberto								break;
385754359Sroberto							case 3:
385854359Sroberto								strcpy(p, "Z-COUNT;");
385954359Sroberto								break;
386054359Sroberto							case 4:
386154359Sroberto								strcpy(p, "SUBFRAME 1,2,3;");
386254359Sroberto								break;
386354359Sroberto							case 5:
386454359Sroberto								strcpy(p, "SUBFRAME 4,5;");
386554359Sroberto								break;
386654359Sroberto							case 6:
386754359Sroberto								strcpy(p, "UPLOAD BAD;");
386854359Sroberto								break;
386954359Sroberto							case 7:
387054359Sroberto								strcpy(p, "DATA BAD;");
387154359Sroberto								break;
387254359Sroberto							}
387354359Sroberto
387454359Sroberto							p += strlen(p);
387554359Sroberto
387654359Sroberto							switch (cfgh.health[i] & 0x1F)
387754359Sroberto							{
387854359Sroberto							case 0:
387954359Sroberto								strcpy(p, "SIGNAL OK");
388054359Sroberto								break;
388154359Sroberto							case 0x1C:
388254359Sroberto								strcpy(p, "SV TEMP OUT");
388354359Sroberto								break;
388454359Sroberto							case 0x1D:
388554359Sroberto								strcpy(p, "SV WILL BE TEMP OUT");
388654359Sroberto								break;
388754359Sroberto							case 0x1E:
388854359Sroberto								break;
388954359Sroberto							case 0x1F:
389054359Sroberto								strcpy(p, "MULTIPLE ERRS");
389154359Sroberto								break;
389254359Sroberto							default:
389354359Sroberto								strcpy(p, "TRANSMISSION PROBLEMS");
389454359Sroberto								break;
389554359Sroberto							}
389654359Sroberto
389754359Sroberto							strcat(p, "\"");
389854359Sroberto							set_var(&parse->kv, buffer, sizeof(buffer), RO);
389954359Sroberto						}
390054359Sroberto					}
390154359Sroberto				}
390254359Sroberto			break;
390354359Sroberto
390454359Sroberto			case GPS_ALM:
390554359Sroberto				break;
390654359Sroberto
390754359Sroberto			case GPS_EPH:
390854359Sroberto				break;
390954359Sroberto
391054359Sroberto			case GPS_UTC:
391154359Sroberto				{
391254359Sroberto					UTC utc;
391354359Sroberto					char buffer[512];
391454359Sroberto					char *p;
391554359Sroberto
391654359Sroberto					p = buffer;
391754359Sroberto
391854359Sroberto					get_mbg_utc(&bufp, &utc);
391954359Sroberto
392054359Sroberto					if (utc.valid)
392154359Sroberto					{
392254359Sroberto						strcpy(p, "gps_utc_correction=\"");
392354359Sroberto						p += strlen(p);
392454359Sroberto						mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf);
392554359Sroberto						strcat(p, "\"");
392654359Sroberto					}
392754359Sroberto					else
392854359Sroberto					{
392954359Sroberto						strcpy(p, "gps_utc_correction=\"<NO UTC DATA>\"");
393054359Sroberto					}
393154359Sroberto					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
393254359Sroberto				}
393354359Sroberto			break;
393454359Sroberto
393554359Sroberto			case GPS_IONO:
393654359Sroberto				break;
393754359Sroberto
393854359Sroberto			case GPS_ASCII_MSG:
393954359Sroberto				{
394054359Sroberto					ASCII_MSG gps_ascii_msg;
394154359Sroberto					char buffer[128];
394254359Sroberto
394354359Sroberto					get_mbg_ascii_msg(&bufp, &gps_ascii_msg);
394454359Sroberto
394554359Sroberto					if (gps_ascii_msg.valid)
394654359Sroberto						{
394754359Sroberto							char buffer1[128];
394854359Sroberto							mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0);
394954359Sroberto
395054359Sroberto							sprintf(buffer, "gps_message=\"%s\"", buffer1);
395154359Sroberto						}
395254359Sroberto					else
395354359Sroberto						strcpy(buffer, "gps_message=<NONE>");
395454359Sroberto
395554359Sroberto					set_var(&parse->kv, buffer, 128, RO|DEF);
395654359Sroberto				}
395754359Sroberto
395854359Sroberto			break;
395954359Sroberto
396054359Sroberto			default:
396154359Sroberto				break;
396254359Sroberto			}
396354359Sroberto		}
396454359Sroberto		else
396554359Sroberto		{
396654359Sroberto			msyslog(LOG_DEBUG, "PARSE receiver #%d: gps16x_message: message checksum error: hdr_csum = 0x%x (expected 0x%lx), data_len = %d, data_csum = 0x%x (expected 0x%lx)",
396754359Sroberto				CLK_UNIT(parse->peer),
396854359Sroberto				header.gps_hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6),
396954359Sroberto				header.gps_len,
397054359Sroberto				header.gps_data_csum, mbg_csum(bufp, (unsigned)((header.gps_len < sizeof(parsetime->parse_msg)) ? header.gps_len : 0)));
397154359Sroberto		}
397254359Sroberto	}
397354359Sroberto
397454359Sroberto	return;
397554359Sroberto}
397654359Sroberto
397754359Sroberto/*------------------------------------------------------------
397854359Sroberto * gps16x_poll - query the reciver peridically
397954359Sroberto */
398054359Srobertostatic void
398154359Srobertogps16x_poll(
398254359Sroberto	    struct peer *peer
398354359Sroberto	    )
398454359Sroberto{
398554359Sroberto	struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
398654359Sroberto
398754359Sroberto	static GPS_MSG_HDR sequence[] =
398854359Sroberto	{
398954359Sroberto		{ GPS_SW_REV,          0, 0, 0 },
399054359Sroberto		{ GPS_STAT,            0, 0, 0 },
399154359Sroberto		{ GPS_UTC,             0, 0, 0 },
399254359Sroberto		{ GPS_ASCII_MSG,       0, 0, 0 },
399354359Sroberto		{ GPS_ANT_INFO,        0, 0, 0 },
399454359Sroberto		{ GPS_CFGH,            0, 0, 0 },
399554359Sroberto		{ GPS_POS_XYZ,         0, 0, 0 },
399654359Sroberto		{ GPS_POS_LLA,         0, 0, 0 },
399754359Sroberto		{ (unsigned short)~0,  0, 0, 0 }
399854359Sroberto	};
399954359Sroberto
400054359Sroberto	int rtc;
400154359Sroberto	unsigned char cmd_buffer[64];
400254359Sroberto	unsigned char *outp = cmd_buffer;
400354359Sroberto	GPS_MSG_HDR *header;
400454359Sroberto
400554359Sroberto	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
400654359Sroberto	{
400754359Sroberto		parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
400854359Sroberto	}
400954359Sroberto
401054359Sroberto	if (sequence[parse->localstate].gps_cmd == (unsigned short)~0)
401154359Sroberto		parse->localstate = 0;
401254359Sroberto
401354359Sroberto	header = sequence + parse->localstate++;
401454359Sroberto
401554359Sroberto	*outp++ = SOH;		/* start command */
401654359Sroberto
401754359Sroberto	put_mbg_header(&outp, header);
401854359Sroberto	outp = cmd_buffer + 1;
401954359Sroberto
402054359Sroberto	header->gps_hdr_csum = (short)mbg_csum(outp, 6);
402154359Sroberto	put_mbg_header(&outp, header);
402254359Sroberto
402354359Sroberto#ifdef DEBUG
402454359Sroberto	if (debug > 2)
402554359Sroberto	{
402654359Sroberto		char buffer[128];
402754359Sroberto
402854359Sroberto		mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1);
402954359Sroberto		printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n",
403054359Sroberto		       CLK_UNIT(parse->peer),
403154359Sroberto		       parse->localstate - 1,
403254359Sroberto		       (int)(outp - cmd_buffer),
403354359Sroberto		       buffer);
403454359Sroberto	}
403554359Sroberto#endif
403654359Sroberto
403754359Sroberto	rtc = write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer));
403854359Sroberto
403954359Sroberto	if (rtc < 0)
404054359Sroberto	{
404154359Sroberto		ERR(ERR_BADIO)
404254359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
404354359Sroberto	}
404454359Sroberto	else
404554359Sroberto	if (rtc != outp - cmd_buffer)
404654359Sroberto	{
404754359Sroberto		ERR(ERR_BADIO)
404854359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, (int)(outp - cmd_buffer));
404954359Sroberto	}
405054359Sroberto
405154359Sroberto	clear_err(parse, ERR_BADIO);
405254359Sroberto	return;
405354359Sroberto}
405454359Sroberto
405554359Sroberto/*--------------------------------------------------
405654359Sroberto * init routine - setup timer
405754359Sroberto */
405854359Srobertostatic int
405954359Srobertogps16x_poll_init(
406054359Sroberto	struct parseunit *parse
406154359Sroberto	)
406254359Sroberto{
406354359Sroberto	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
406454359Sroberto	{
406554359Sroberto		parse->peer->action = gps16x_poll;
406654359Sroberto		gps16x_poll(parse->peer);
406754359Sroberto	}
406854359Sroberto
406954359Sroberto	return 0;
407054359Sroberto}
407154359Sroberto
407254359Sroberto#else
407354359Srobertostatic void
407454359Srobertogps16x_message(
407554359Sroberto	       struct parseunit *parse,
407654359Sroberto	       parsetime_t      *parsetime
407754359Sroberto	       )
407854359Sroberto{}
407954359Srobertostatic int
408054359Srobertogps16x_poll_init(
408154359Sroberto	struct parseunit *parse
408254359Sroberto	)
408354359Sroberto{
408454359Sroberto	return 1;
408554359Sroberto}
408654359Sroberto#endif /* CLOCK_MEINBERG */
408754359Sroberto
408854359Sroberto/**===========================================================================
408954359Sroberto ** clock polling support
409054359Sroberto **/
409154359Sroberto
409254359Sroberto/*--------------------------------------------------
409354359Sroberto * direct poll routine
409454359Sroberto */
409554359Srobertostatic void
409654359Srobertopoll_dpoll(
409754359Sroberto	struct parseunit *parse
409854359Sroberto	)
409954359Sroberto{
410054359Sroberto	int rtc;
410154359Sroberto	const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string;
410254359Sroberto	int   ct = ((poll_info_t *)parse->parse_type->cl_data)->count;
410354359Sroberto
410454359Sroberto	rtc = write(parse->generic->io.fd, ps, (unsigned long)ct);
410554359Sroberto	if (rtc < 0)
410654359Sroberto	{
410754359Sroberto		ERR(ERR_BADIO)
410854359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
410954359Sroberto	}
411054359Sroberto	else
411154359Sroberto	    if (rtc != ct)
411254359Sroberto	    {
411354359Sroberto		    ERR(ERR_BADIO)
411454359Sroberto			    msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, ct);
411554359Sroberto	    }
411654359Sroberto	clear_err(parse, ERR_BADIO);
411754359Sroberto}
411854359Sroberto
411954359Sroberto/*--------------------------------------------------
412054359Sroberto * periodic poll routine
412154359Sroberto */
412254359Srobertostatic void
412354359Srobertopoll_poll(
412454359Sroberto	struct peer *peer
412554359Sroberto	)
412654359Sroberto{
412754359Sroberto	struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
412854359Sroberto
412954359Sroberto	if (parse->parse_type->cl_poll)
413054359Sroberto		parse->parse_type->cl_poll(parse);
413154359Sroberto
413254359Sroberto	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
413354359Sroberto	{
413454359Sroberto		parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
413554359Sroberto	}
413654359Sroberto}
413754359Sroberto
413854359Sroberto/*--------------------------------------------------
413954359Sroberto * init routine - setup timer
414054359Sroberto */
414154359Srobertostatic int
414254359Srobertopoll_init(
414354359Sroberto	struct parseunit *parse
414454359Sroberto	)
414554359Sroberto{
414654359Sroberto	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
414754359Sroberto	{
414854359Sroberto		parse->peer->action = poll_poll;
414954359Sroberto		poll_poll(parse->peer);
415054359Sroberto	}
415154359Sroberto
415254359Sroberto	return 0;
415354359Sroberto}
415456746Sroberto
415554359Sroberto/**===========================================================================
415654359Sroberto ** Trimble support
415754359Sroberto **/
415854359Sroberto
415954359Sroberto/*-------------------------------------------------------------
416054359Sroberto * trimble TAIP init routine - setup EOL and then do poll_init.
416154359Sroberto */
416254359Srobertostatic int
416354359Srobertotrimbletaip_init(
416454359Sroberto	struct parseunit *parse
416554359Sroberto	)
416654359Sroberto{
416754359Sroberto#ifdef HAVE_TERMIOS
416854359Sroberto	struct termios tio;
416954359Sroberto#endif
417054359Sroberto#ifdef HAVE_SYSV_TTYS
417154359Sroberto	struct termio tio;
417254359Sroberto#endif
417354359Sroberto	/*
417454359Sroberto	 * configure terminal line for trimble receiver
417554359Sroberto	 */
417654359Sroberto	if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
417754359Sroberto	{
417854359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
417954359Sroberto		return 0;
418054359Sroberto	}
418154359Sroberto	else
418254359Sroberto	{
418354359Sroberto		tio.c_cc[VEOL] = TRIMBLETAIP_EOL;
418454359Sroberto
418554359Sroberto		if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
418654359Sroberto		{
418754359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
418854359Sroberto			return 0;
418954359Sroberto		}
419054359Sroberto	}
419154359Sroberto	return poll_init(parse);
419254359Sroberto}
419354359Sroberto
419454359Sroberto/*--------------------------------------------------
419554359Sroberto * trimble TAIP event routine - reset receiver upon data format trouble
419654359Sroberto */
419754359Srobertostatic const char *taipinit[] = {
419854359Sroberto	">FPV00000000<",
419954359Sroberto	">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<",
420054359Sroberto	">FTM00020001<",
420154359Sroberto	(char *)0
420254359Sroberto};
420354359Sroberto
420454359Srobertostatic void
420554359Srobertotrimbletaip_event(
420654359Sroberto	struct parseunit *parse,
420754359Sroberto	int event
420854359Sroberto	)
420954359Sroberto{
421054359Sroberto	switch (event)
421154359Sroberto	{
421254359Sroberto	    case CEVNT_BADREPLY:	/* reset on garbled input */
421354359Sroberto	    case CEVNT_TIMEOUT:		/* reset on no input */
421454359Sroberto		    {
421554359Sroberto			    const char **iv;
421654359Sroberto
421754359Sroberto			    iv = taipinit;
421854359Sroberto			    while (*iv)
421954359Sroberto			    {
422054359Sroberto				    int rtc = write(parse->generic->io.fd, *iv, strlen(*iv));
422154359Sroberto				    if (rtc < 0)
422254359Sroberto				    {
422354359Sroberto					    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
422454359Sroberto					    return;
422554359Sroberto				    }
422654359Sroberto				    else
422754359Sroberto				    {
422854359Sroberto					    if (rtc != strlen(*iv))
422954359Sroberto					    {
423054359Sroberto						    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)",
423154359Sroberto							    CLK_UNIT(parse->peer), rtc, (int)strlen(*iv));
423254359Sroberto						    return;
423354359Sroberto					    }
423454359Sroberto				    }
423554359Sroberto				    iv++;
423654359Sroberto			    }
423754359Sroberto
423854359Sroberto			    NLOG(NLOG_CLOCKINFO)
423954359Sroberto				    ERR(ERR_BADIO)
424054359Sroberto				    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED",
424154359Sroberto					    CLK_UNIT(parse->peer));
424254359Sroberto		    }
424354359Sroberto		    break;
424454359Sroberto
424554359Sroberto	    default:			/* ignore */
424654359Sroberto		break;
424754359Sroberto	}
424854359Sroberto}
424954359Sroberto
425054359Sroberto/*
425154359Sroberto * This driver supports the Trimble SVee Six Plus GPS receiver module.
425254359Sroberto * It should support other Trimble receivers which use the Trimble Standard
425354359Sroberto * Interface Protocol (see below).
425454359Sroberto *
425554359Sroberto * The module has a serial I/O port for command/data and a 1 pulse-per-second
425654359Sroberto * output, about 1 microsecond wide. The leading edge of the pulse is
425754359Sroberto * coincident with the change of the GPS second. This is the same as
425854359Sroberto * the change of the UTC second +/- ~1 microsecond. Some other clocks
425954359Sroberto * specifically use a feature in the data message as a timing reference, but
426054359Sroberto * the SVee Six Plus does not do this. In fact there is considerable jitter
426154359Sroberto * on the timing of the messages, so this driver only supports the use
426254359Sroberto * of the PPS pulse for accurate timing. Where it is determined that
426354359Sroberto * the offset is way off, when first starting up ntpd for example,
426454359Sroberto * the timing of the data stream is used until the offset becomes low enough
426556746Sroberto * (|offset| < CLOCK_MAX), at which point the pps offset is used.
426654359Sroberto *
426754359Sroberto * It can use either option for receiving PPS information - the 'ppsclock'
426854359Sroberto * stream pushed onto the serial data interface to timestamp the Carrier
426954359Sroberto * Detect interrupts, where the 1PPS connects to the CD line. This only
427054359Sroberto * works on SunOS 4.1.x currently. To select this, define PPSPPS in
427154359Sroberto * Config.local. The other option is to use a pulse-stretcher/level-converter
427254359Sroberto * to convert the PPS pulse into a RS232 start pulse & feed this into another
427354359Sroberto * tty port. To use this option, define PPSCLK in Config.local. The pps input,
427454359Sroberto * by whichever method, is handled in ntp_loopfilter.c
427554359Sroberto *
427654359Sroberto * The receiver uses a serial message protocol called Trimble Standard
427754359Sroberto * Interface Protocol (it can support others but this driver only supports
427854359Sroberto * TSIP). Messages in this protocol have the following form:
427954359Sroberto *
428054359Sroberto * <DLE><id> ... <data> ... <DLE><ETX>
428154359Sroberto *
428254359Sroberto * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled
428354359Sroberto * on transmission and compressed back to one on reception. Otherwise
428454359Sroberto * the values of data bytes can be anything. The serial interface is RS-422
428554359Sroberto * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits
428654359Sroberto * in total!), and 1 stop bit. The protocol supports byte, integer, single,
428754359Sroberto * and double datatypes. Integers are two bytes, sent most significant first.
428854359Sroberto * Singles are IEEE754 single precision floating point numbers (4 byte) sent
428954359Sroberto * sign & exponent first. Doubles are IEEE754 double precision floating point
429054359Sroberto * numbers (8 byte) sent sign & exponent first.
429154359Sroberto * The receiver supports a large set of messages, only a small subset of
429254359Sroberto * which are used here. From driver to receiver the following are used:
429354359Sroberto *
429454359Sroberto *  ID    Description
429554359Sroberto *
429654359Sroberto *  21    Request current time
429754359Sroberto *  22    Mode Select
429854359Sroberto *  2C    Set/Request operating parameters
429954359Sroberto *  2F    Request UTC info
430054359Sroberto *  35    Set/Request I/O options
430154359Sroberto
430254359Sroberto * From receiver to driver the following are recognised:
430354359Sroberto *
430454359Sroberto *  ID    Description
430554359Sroberto *
430654359Sroberto *  41    GPS Time
430754359Sroberto *  44    Satellite selection, PDOP, mode
430854359Sroberto *  46    Receiver health
430954359Sroberto *  4B    Machine code/status
431054359Sroberto *  4C    Report operating parameters (debug only)
431154359Sroberto *  4F    UTC correction data (used to get leap second warnings)
431254359Sroberto *  55    I/O options (debug only)
431354359Sroberto *
431454359Sroberto * All others are accepted but ignored.
431554359Sroberto *
431654359Sroberto */
431754359Sroberto
431854359Sroberto#define PI		3.1415926535898	/* lots of sig figs */
431954359Sroberto#define D2R		PI/180.0
432054359Sroberto
432154359Sroberto/*-------------------------------------------------------------------
432254359Sroberto * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command
432354359Sroberto * interface to the receiver.
432454359Sroberto *
432554359Sroberto * CAVEAT: the sendflt, sendint routines are byte order dependend and
432654359Sroberto * float implementation dependend - these must be converted to portable
432754359Sroberto * versions !
432854359Sroberto *
432954359Sroberto * CURRENT LIMITATION: float implementation. This runs only on systems
433054359Sroberto * with IEEE754 floats as native floats
433154359Sroberto */
433254359Sroberto
433354359Srobertotypedef struct trimble
433454359Sroberto{
433554359Sroberto	u_long last_msg;	/* last message received */
433654359Sroberto	u_char qtracking;	/* query tracking status */
433754359Sroberto	u_long ctrack;		/* current tracking set */
433854359Sroberto	u_long ltrack;		/* last tracking set */
433954359Sroberto} trimble_t;
434054359Sroberto
434154359Srobertounion uval {
434254359Sroberto	u_char  bd[8];
434354359Sroberto	int     iv;
434454359Sroberto	float   fv;
434554359Sroberto	double  dv;
434654359Sroberto};
434754359Sroberto
434854359Srobertostruct txbuf
434954359Sroberto{
435054359Sroberto	short idx;			/* index to first unused byte */
435154359Sroberto	u_char *txt;			/* pointer to actual data buffer */
435254359Sroberto};
435354359Sroberto
435456746Srobertovoid	sendcmd		P((struct txbuf *buf, int c));
435556746Srobertovoid	sendbyte	P((struct txbuf *buf, int b));
435656746Srobertovoid	sendetx		P((struct txbuf *buf, struct parseunit *parse));
435756746Srobertovoid	sendint		P((struct txbuf *buf, int a));
435856746Srobertovoid	sendflt		P((struct txbuf *buf, double a));
435956746Sroberto
436054359Srobertovoid
436154359Srobertosendcmd(
436254359Sroberto	struct txbuf *buf,
436354359Sroberto	int c
436454359Sroberto	)
436554359Sroberto{
436654359Sroberto	buf->txt[0] = DLE;
436754359Sroberto	buf->txt[1] = (u_char)c;
436854359Sroberto	buf->idx = 2;
436954359Sroberto}
437054359Sroberto
437154359Srobertovoid
437254359Srobertosendbyte(
437354359Sroberto	struct txbuf *buf,
437454359Sroberto	int b
437554359Sroberto	)
437654359Sroberto{
437754359Sroberto	if (b == DLE)
437854359Sroberto	    buf->txt[buf->idx++] = DLE;
437954359Sroberto	buf->txt[buf->idx++] = (u_char)b;
438054359Sroberto}
438154359Sroberto
438254359Srobertovoid
438354359Srobertosendetx(
438454359Sroberto	struct txbuf *buf,
438554359Sroberto	struct parseunit *parse
438654359Sroberto	)
438754359Sroberto{
438854359Sroberto	buf->txt[buf->idx++] = DLE;
438954359Sroberto	buf->txt[buf->idx++] = ETX;
439054359Sroberto
439154359Sroberto	if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx)
439254359Sroberto	{
439354359Sroberto		ERR(ERR_BADIO)
439454359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
439554359Sroberto	}
439654359Sroberto	else
439754359Sroberto	{
439854359Sroberto#ifdef DEBUG
439954359Sroberto	  if (debug > 2)
440054359Sroberto	  {
440154359Sroberto		  char buffer[256];
440254359Sroberto
440354359Sroberto		  mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1);
440454359Sroberto		  printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n",
440554359Sroberto			 CLK_UNIT(parse->peer),
440654359Sroberto			 buf->idx, buffer);
440754359Sroberto	  }
440854359Sroberto#endif
440954359Sroberto		clear_err(parse, ERR_BADIO);
441054359Sroberto	}
441154359Sroberto}
441254359Sroberto
441354359Srobertovoid
441454359Srobertosendint(
441554359Sroberto	struct txbuf *buf,
441654359Sroberto	int a
441754359Sroberto	)
441854359Sroberto{
441954359Sroberto	/* send 16bit int, msbyte first */
442054359Sroberto	sendbyte(buf, (u_char)((a>>8) & 0xff));
442154359Sroberto	sendbyte(buf, (u_char)(a & 0xff));
442254359Sroberto}
442354359Sroberto
442454359Srobertovoid
442554359Srobertosendflt(
442654359Sroberto	struct txbuf *buf,
442754359Sroberto	double a
442854359Sroberto	)
442954359Sroberto{
443054359Sroberto	int i;
443154359Sroberto	union uval uval;
443254359Sroberto
443354359Sroberto	uval.fv = a;
443454359Sroberto#ifdef WORDS_BIGENDIAN
443554359Sroberto	for (i=0; i<=3; i++)
443654359Sroberto#else
443754359Sroberto	    for (i=3; i>=0; i--)
443854359Sroberto#endif
443954359Sroberto		sendbyte(buf, uval.bd[i]);
444054359Sroberto}
444154359Sroberto
444254359Sroberto#define TRIM_POS_OPT	0x13	/* output position with high precision */
444354359Sroberto#define TRIM_TIME_OPT	0x03	/* use UTC time stamps, on second */
444454359Sroberto
444554359Sroberto/*--------------------------------------------------
444654359Sroberto * trimble TSIP setup routine
444754359Sroberto */
444854359Srobertostatic int
444954359Srobertotrimbletsip_setup(
445054359Sroberto		  struct parseunit *parse,
445154359Sroberto		  const char *reason
445256746Sroberto		  )
445354359Sroberto{
445454359Sroberto	u_char buffer[256];
445554359Sroberto	struct txbuf buf;
445654359Sroberto
445754359Sroberto	buf.txt = buffer;
445854359Sroberto
445954359Sroberto	sendcmd(&buf, CMD_CVERSION);	/* request software versions */
446056746Sroberto	sendetx(&buf, parse);
446156746Sroberto
446254359Sroberto	sendcmd(&buf, CMD_COPERPARAM);	/* set operating parameters */
446356746Sroberto	sendbyte(&buf, 4);	/* static */
446456746Sroberto	sendflt(&buf, 5.0*D2R);	/* elevation angle mask = 10 deg XXX */
446556746Sroberto	sendflt(&buf, 4.0);	/* s/n ratio mask = 6 XXX */
446656746Sroberto	sendflt(&buf, 12.0);	/* PDOP mask = 12 */
446756746Sroberto	sendflt(&buf, 8.0);	/* PDOP switch level = 8 */
446856746Sroberto	sendetx(&buf, parse);
446956746Sroberto
447054359Sroberto	sendcmd(&buf, CMD_CMODESEL);	/* fix mode select */
447156746Sroberto	sendbyte(&buf, 0);	/* automatic */
447256746Sroberto	sendetx(&buf, parse);
447356746Sroberto
447454359Sroberto	sendcmd(&buf, CMD_CMESSAGE);	/* request system message */
447556746Sroberto	sendetx(&buf, parse);
447656746Sroberto
447754359Sroberto	sendcmd(&buf, CMD_CSUPER);	/* superpacket fix */
447856746Sroberto	sendbyte(&buf, 0x2);	/* binary mode */
447956746Sroberto	sendetx(&buf, parse);
448056746Sroberto
448154359Sroberto	sendcmd(&buf, CMD_CIOOPTIONS);	/* set I/O options */
448254359Sroberto	sendbyte(&buf, TRIM_POS_OPT);	/* position output */
448354359Sroberto	sendbyte(&buf, 0x00);	/* no velocity output */
448454359Sroberto	sendbyte(&buf, TRIM_TIME_OPT);	/* UTC, compute on seconds */
448554359Sroberto	sendbyte(&buf, 0x00);	/* no raw measurements */
448656746Sroberto	sendetx(&buf, parse);
448756746Sroberto
448854359Sroberto	sendcmd(&buf, CMD_CUTCPARAM);	/* request UTC correction data */
448954359Sroberto	sendetx(&buf, parse);
449054359Sroberto
449154359Sroberto	NLOG(NLOG_CLOCKINFO)
449254359Sroberto		ERR(ERR_BADIO)
449354359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason);
449454359Sroberto
449554359Sroberto	return 0;
449654359Sroberto}
449754359Sroberto
449854359Sroberto/*--------------------------------------------------
449954359Sroberto * TRIMBLE TSIP check routine
450054359Sroberto */
450154359Srobertostatic void
450254359Srobertotrimble_check(
450354359Sroberto	      struct peer *peer
450454359Sroberto	      )
450554359Sroberto{
450654359Sroberto	struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
450754359Sroberto	trimble_t *t = parse->localdata;
450854359Sroberto	u_char buffer[256];
450954359Sroberto	struct txbuf buf;
451054359Sroberto	buf.txt = buffer;
451154359Sroberto
451254359Sroberto	if (t)
451354359Sroberto	{
451454359Sroberto		if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME)
451554359Sroberto			(void)trimbletsip_setup(parse, "message timeout");
451654359Sroberto	}
451754359Sroberto	poll_poll(parse->peer);	/* emit query string and re-arm timer */
451854359Sroberto
451954359Sroberto	if (t->qtracking)
452054359Sroberto	{
452154359Sroberto		u_long oldsats = t->ltrack & ~t->ctrack;
452254359Sroberto
452354359Sroberto		t->qtracking = 0;
452454359Sroberto		t->ltrack = t->ctrack;
452554359Sroberto
452654359Sroberto		if (oldsats)
452754359Sroberto		{
452854359Sroberto			int i;
452954359Sroberto
453054359Sroberto			for (i = 0; oldsats; i++)
453154359Sroberto				if (oldsats & (1 << i))
453254359Sroberto					{
453354359Sroberto						sendcmd(&buf, CMD_CSTATTRACK);
453454359Sroberto						sendbyte(&buf, i+1);	/* old sat */
453554359Sroberto						sendetx(&buf, parse);
453654359Sroberto					}
453754359Sroberto			oldsats &= ~(1 << i);
453854359Sroberto		}
453954359Sroberto
454054359Sroberto		sendcmd(&buf, CMD_CSTATTRACK);
454154359Sroberto		sendbyte(&buf, 0x00);	/* current tracking set */
454254359Sroberto		sendetx(&buf, parse);
454354359Sroberto	}
454454359Sroberto}
454554359Sroberto
454654359Sroberto/*--------------------------------------------------
454754359Sroberto * TRIMBLE TSIP end routine
454854359Sroberto */
454954359Srobertostatic void
455054359Srobertotrimbletsip_end(
455154359Sroberto	      struct parseunit *parse
455254359Sroberto	      )
455354359Sroberto{	trimble_t *t = parse->localdata;
455454359Sroberto
455554359Sroberto	if (t)
455654359Sroberto	{
455754359Sroberto		free(t);
455854359Sroberto		parse->localdata = (void *)0;
455954359Sroberto	}
456054359Sroberto	parse->peer->nextaction = 0;
456154359Sroberto	parse->peer->action = (void (*) P((struct peer *)))0;
456254359Sroberto}
456354359Sroberto
456454359Sroberto/*--------------------------------------------------
456554359Sroberto * TRIMBLE TSIP init routine
456654359Sroberto */
456754359Srobertostatic int
456854359Srobertotrimbletsip_init(
456954359Sroberto	struct parseunit *parse
457054359Sroberto	)
457154359Sroberto{
457254359Sroberto#if defined(VEOL) || defined(VEOL2)
457354359Sroberto#ifdef HAVE_TERMIOS
457454359Sroberto	struct termios tio;		/* NEEDED FOR A LONG TIME ! */
457554359Sroberto#endif
457654359Sroberto#ifdef HAVE_SYSV_TTYS
457754359Sroberto	struct termio tio;		/* NEEDED FOR A LONG TIME ! */
457854359Sroberto#endif
457954359Sroberto	/*
458054359Sroberto	 * allocate local data area
458154359Sroberto	 */
458254359Sroberto	if (!parse->localdata)
458354359Sroberto	{
458454359Sroberto		trimble_t *t;
458554359Sroberto
458654359Sroberto		t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t)));
458754359Sroberto
458854359Sroberto		if (t)
458954359Sroberto		{
459054359Sroberto			memset((char *)t, 0, sizeof(trimble_t));
459154359Sroberto			t->last_msg = current_time;
459254359Sroberto		}
459354359Sroberto	}
459454359Sroberto
459554359Sroberto	parse->peer->action     = trimble_check;
459654359Sroberto	parse->peer->nextaction = current_time;
459754359Sroberto
459854359Sroberto	/*
459954359Sroberto	 * configure terminal line for ICANON mode with VEOL characters
460054359Sroberto	 */
460154359Sroberto	if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
460254359Sroberto	{
460354359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
460454359Sroberto		return 0;
460554359Sroberto	}
460654359Sroberto	else
460754359Sroberto	{
460854359Sroberto		if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON))
460954359Sroberto		{
461054359Sroberto#ifdef VEOL
461154359Sroberto			tio.c_cc[VEOL]  = ETX;
461254359Sroberto#endif
461354359Sroberto#ifdef VEOL2
461454359Sroberto			tio.c_cc[VEOL2]  = DLE;
461554359Sroberto#endif
461656746Sroberto		}
461754359Sroberto
461854359Sroberto		if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
461954359Sroberto		{
462054359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
462154359Sroberto			return 0;
462254359Sroberto		}
462354359Sroberto	}
462454359Sroberto#endif
462554359Sroberto	return trimbletsip_setup(parse, "initial startup");
462654359Sroberto}
462754359Sroberto
462854359Sroberto/*------------------------------------------------------------
462954359Sroberto * trimbletsip_event - handle Trimble events
463054359Sroberto * simple evente handler - attempt to re-initialize receiver
463154359Sroberto */
463254359Srobertostatic void
463354359Srobertotrimbletsip_event(
463454359Sroberto	struct parseunit *parse,
463554359Sroberto	int event
463654359Sroberto	)
463754359Sroberto{
463854359Sroberto	switch (event)
463954359Sroberto	{
464054359Sroberto	    case CEVNT_BADREPLY:	/* reset on garbled input */
464154359Sroberto	    case CEVNT_TIMEOUT:		/* reset on no input */
464254359Sroberto		    (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT");
464354359Sroberto		    break;
464454359Sroberto
464554359Sroberto	    default:			/* ignore */
464654359Sroberto		break;
464754359Sroberto	}
464854359Sroberto}
464954359Sroberto
465054359Sroberto/*
465154359Sroberto * getflt, getint convert fields in the incoming data into the
465254359Sroberto * appropriate type of item
465354359Sroberto *
465454359Sroberto * CAVEAT: these routines are currently definitely byte order dependent
465554359Sroberto * and assume Representation(float) == IEEE754
465654359Sroberto * These functions MUST be converted to portable versions (especially
465754359Sroberto * converting the float representation into ntp_fp formats in order
465854359Sroberto * to avoid floating point operations at all!
465954359Sroberto */
466054359Sroberto
466154359Srobertostatic float
466254359Srobertogetflt(
466354359Sroberto	u_char *bp
466454359Sroberto	)
466554359Sroberto{
466654359Sroberto	union uval uval;
466754359Sroberto
466854359Sroberto#ifdef WORDS_BIGENDIAN
466954359Sroberto	uval.bd[0] = *bp++;
467054359Sroberto	uval.bd[1] = *bp++;
467154359Sroberto	uval.bd[2] = *bp++;
467254359Sroberto	uval.bd[3] = *bp;
467354359Sroberto#else  /* ! WORDS_BIGENDIAN */
467454359Sroberto	uval.bd[3] = *bp++;
467554359Sroberto	uval.bd[2] = *bp++;
467654359Sroberto	uval.bd[1] = *bp++;
467754359Sroberto	uval.bd[0] = *bp;
467854359Sroberto#endif /* ! WORDS_BIGENDIAN */
467954359Sroberto	return uval.fv;
468054359Sroberto}
468154359Sroberto
468254359Srobertostatic double
468354359Srobertogetdbl(
468454359Sroberto	u_char *bp
468554359Sroberto	)
468654359Sroberto{
468754359Sroberto	union uval uval;
468854359Sroberto
468954359Sroberto#ifdef WORDS_BIGENDIAN
469054359Sroberto	uval.bd[0] = *bp++;
469154359Sroberto	uval.bd[1] = *bp++;
469254359Sroberto	uval.bd[2] = *bp++;
469354359Sroberto	uval.bd[3] = *bp++;
469454359Sroberto	uval.bd[4] = *bp++;
469554359Sroberto	uval.bd[5] = *bp++;
469654359Sroberto	uval.bd[6] = *bp++;
469754359Sroberto	uval.bd[7] = *bp;
469854359Sroberto#else  /* ! WORDS_BIGENDIAN */
469954359Sroberto	uval.bd[7] = *bp++;
470054359Sroberto	uval.bd[6] = *bp++;
470154359Sroberto	uval.bd[5] = *bp++;
470254359Sroberto	uval.bd[4] = *bp++;
470354359Sroberto	uval.bd[3] = *bp++;
470454359Sroberto	uval.bd[2] = *bp++;
470554359Sroberto	uval.bd[1] = *bp++;
470654359Sroberto	uval.bd[0] = *bp;
470754359Sroberto#endif /* ! WORDS_BIGENDIAN */
470854359Sroberto	return uval.dv;
470954359Sroberto}
471054359Sroberto
471154359Srobertostatic int
471254359Srobertogetshort(
471354359Sroberto	 unsigned char *p
471454359Sroberto	 )
471554359Sroberto{
471654359Sroberto	return get_msb_short(&p);
471754359Sroberto}
471854359Sroberto
471954359Sroberto/*--------------------------------------------------
472054359Sroberto * trimbletsip_message - process trimble messages
472154359Sroberto */
472254359Sroberto#define RTOD (180.0 / 3.1415926535898)
472354359Sroberto#define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */
472454359Sroberto
472554359Srobertostatic void
472654359Srobertotrimbletsip_message(
472754359Sroberto		    struct parseunit *parse,
472854359Sroberto		    parsetime_t      *parsetime
472954359Sroberto		    )
473054359Sroberto{
473154359Sroberto	unsigned char *buffer = parsetime->parse_msg;
473254359Sroberto	unsigned int   size   = parsetime->parse_msglen;
473354359Sroberto
473454359Sroberto	if ((size < 4) ||
473554359Sroberto	    (buffer[0]      != DLE) ||
473654359Sroberto	    (buffer[size-1] != ETX) ||
473754359Sroberto	    (buffer[size-2] != DLE))
473854359Sroberto	{
473954359Sroberto#ifdef DEBUG
474054359Sroberto		if (debug > 2) {
474154359Sroberto			int i;
474254359Sroberto
474354359Sroberto			printf("TRIMBLE BAD packet, size %d:\n	", size);
474454359Sroberto			for (i = 0; i < size; i++) {
474554359Sroberto				printf ("%2.2x, ", buffer[i]&0xff);
474654359Sroberto				if (i%16 == 15) printf("\n\t");
474754359Sroberto			}
474854359Sroberto			printf("\n");
474954359Sroberto		}
475054359Sroberto#endif
475154359Sroberto		return;
475254359Sroberto	}
475354359Sroberto	else
475454359Sroberto	{
475554359Sroberto		int var_flag;
475654359Sroberto		trimble_t *tr = parse->localdata;
475754359Sroberto		unsigned int cmd = buffer[1];
475854359Sroberto		char pbuffer[200];
475954359Sroberto		char *t = pbuffer;
476054359Sroberto		cmd_info_t *s;
476154359Sroberto
476254359Sroberto#ifdef DEBUG
476354359Sroberto		if (debug > 3) {
476454359Sroberto			int i;
476554359Sroberto
476654359Sroberto			printf("TRIMBLE packet 0x%02x, size %d:\n	", cmd, size);
476754359Sroberto			for (i = 0; i < size; i++) {
476854359Sroberto				printf ("%2.2x, ", buffer[i]&0xff);
476954359Sroberto				if (i%16 == 15) printf("\n\t");
477054359Sroberto			}
477154359Sroberto			printf("\n");
477254359Sroberto		}
477354359Sroberto#endif
477454359Sroberto
477554359Sroberto		if (tr)
477654359Sroberto			tr->last_msg = current_time;
477754359Sroberto
477854359Sroberto		s = trimble_convert(cmd, trimble_rcmds);
477954359Sroberto
478054359Sroberto		if (s)
478154359Sroberto		{
478254359Sroberto			sprintf(t, "%s=\"", s->varname);
478354359Sroberto		}
478454359Sroberto		else
478554359Sroberto		{
478654359Sroberto			printf("TRIMBLE unknown command 0x%02x\n", cmd);
478754359Sroberto			return;
478854359Sroberto		}
478954359Sroberto
479054359Sroberto		var_flag = s->varmode;
479154359Sroberto
479254359Sroberto		t += strlen(t);
479354359Sroberto
479454359Sroberto		switch(cmd)
479554359Sroberto		{
479654359Sroberto		case CMD_RCURTIME:
479754359Sroberto			sprintf(t, "%f, %d, %f",
479854359Sroberto				getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)),
479954359Sroberto				getflt((unsigned char *)&mb(6)));
480054359Sroberto			break;
480154359Sroberto
480254359Sroberto		case CMD_RBEST4:
480354359Sroberto			strcpy(t, "mode: ");
480454359Sroberto			t += strlen(t);
480554359Sroberto			switch (mb(0) & 0xF)
480654359Sroberto			{
480754359Sroberto			default:
480854359Sroberto				sprintf(t, "0x%x", mb(0) & 0x7);
480954359Sroberto				break;
481054359Sroberto
481154359Sroberto			case 1:
481254359Sroberto				strcat(t, "0D");
481354359Sroberto				break;
481454359Sroberto
481554359Sroberto			case 3:
481654359Sroberto				strcat(t, "2D");
481754359Sroberto				break;
481854359Sroberto
481954359Sroberto			case 4:
482054359Sroberto				strcat(t, "3D");
482154359Sroberto				break;
482254359Sroberto			}
482354359Sroberto			t += strlen(t);
482454359Sroberto			if (mb(0) & 0x10)
482554359Sroberto				strcpy(t, "-MANUAL, ");
482654359Sroberto			else
482754359Sroberto				strcpy(t, "-AUTO, ");
482854359Sroberto			t += strlen(t);
482954359Sroberto
483054359Sroberto			sprintf(t, "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f",
483154359Sroberto				mb(1), mb(2), mb(3), mb(4),
483254359Sroberto				getflt((unsigned char *)&mb(5)),
483354359Sroberto				getflt((unsigned char *)&mb(9)),
483454359Sroberto				getflt((unsigned char *)&mb(13)),
483554359Sroberto				getflt((unsigned char *)&mb(17)));
483654359Sroberto
483754359Sroberto			break;
483854359Sroberto
483954359Sroberto		case CMD_RVERSION:
484054359Sroberto			sprintf(t, "%d.%d (%d/%d/%d)",
484154359Sroberto				mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff);
484254359Sroberto			break;
484354359Sroberto
484454359Sroberto		case CMD_RRECVHEALTH:
484554359Sroberto		{
484654359Sroberto			static const char *msgs[] =
484754359Sroberto			{
484854359Sroberto				"Battery backup failed",
484954359Sroberto				"Signal processor error",
485054359Sroberto				"Alignment error, channel or chip 1",
485154359Sroberto				"Alignment error, channel or chip 2",
485254359Sroberto				"Antenna feed line fault",
485354359Sroberto				"Excessive ref freq. error",
485454359Sroberto				"<BIT 6>",
485554359Sroberto				"<BIT 7>"
485654359Sroberto			};
485754359Sroberto
485854359Sroberto			int i, bits;
485954359Sroberto
486054359Sroberto			switch (mb(0) & 0xFF)
486154359Sroberto			{
486254359Sroberto			default:
486354359Sroberto				sprintf(t, "illegal value 0x%02x", mb(0) & 0xFF);
486454359Sroberto				break;
486554359Sroberto			case 0x00:
486654359Sroberto				strcpy(t, "doing position fixes");
486754359Sroberto				break;
486854359Sroberto			case 0x01:
486954359Sroberto				strcpy(t, "no GPS time yet");
487054359Sroberto				break;
487154359Sroberto			case 0x03:
487254359Sroberto				strcpy(t, "PDOP too high");
487354359Sroberto				break;
487454359Sroberto			case 0x08:
487554359Sroberto				strcpy(t, "no usable satellites");
487654359Sroberto				break;
487754359Sroberto			case 0x09:
487854359Sroberto				strcpy(t, "only ONE usable satellite");
487954359Sroberto				break;
488054359Sroberto			case 0x0A:
488154359Sroberto				strcpy(t, "only TWO usable satellites");
488254359Sroberto				break;
488354359Sroberto			case 0x0B:
488454359Sroberto				strcpy(t, "only THREE usable satellites");
488554359Sroberto				break;
488654359Sroberto			case 0x0C:
488754359Sroberto				strcpy(t, "the chosen satellite is unusable");
488854359Sroberto				break;
488954359Sroberto			}
489054359Sroberto
489154359Sroberto			t += strlen(t);
489254359Sroberto
489354359Sroberto			bits = mb(1) & 0xFF;
489454359Sroberto
489554359Sroberto			for (i = 0; i < 8; i++)
489654359Sroberto				if (bits & (0x1<<i))
489754359Sroberto				{
489854359Sroberto					sprintf(t, ", %s", msgs[i]);
489954359Sroberto					t += strlen(t);
490054359Sroberto				}
490154359Sroberto		}
490254359Sroberto		break;
490354359Sroberto
490454359Sroberto		case CMD_RMESSAGE:
490554359Sroberto			mkreadable(t, (int)(sizeof(pbuffer) - (t - pbuffer)), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0);
490654359Sroberto			break;
490754359Sroberto
490854359Sroberto		case CMD_RMACHSTAT:
490954359Sroberto		{
491054359Sroberto			static const char *msgs[] =
491154359Sroberto			{
491254359Sroberto				"Synthesizer Fault",
491354359Sroberto				"Battery Powered Time Clock Fault",
491454359Sroberto				"A-to-D Converter Fault",
491554359Sroberto				"The almanac stored in the receiver is not complete and current",
491654359Sroberto				"<BIT 4>",
491754359Sroberto				"<BIT 5",
491854359Sroberto				"<BIT 6>",
491954359Sroberto				"<BIT 7>"
492054359Sroberto			};
492154359Sroberto
492254359Sroberto			int i, bits;
492354359Sroberto
492454359Sroberto			sprintf(t, "machine id 0x%02x", mb(0) & 0xFF);
492554359Sroberto			t += strlen(t);
492654359Sroberto
492754359Sroberto			bits = mb(1) & 0xFF;
492854359Sroberto
492954359Sroberto			for (i = 0; i < 8; i++)
493054359Sroberto				if (bits & (0x1<<i))
493154359Sroberto				{
493254359Sroberto					sprintf(t, ", %s", msgs[i]);
493354359Sroberto					t += strlen(t);
493454359Sroberto				}
493554359Sroberto
493654359Sroberto			sprintf(t, ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" );
493754359Sroberto		}
493854359Sroberto		break;
493954359Sroberto
494054359Sroberto		case CMD_ROPERPARAM:
494154359Sroberto			sprintf(t, "%2x %.1f %.1f %.1f %.1f",
494254359Sroberto				mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)),
494354359Sroberto				getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13)));
494454359Sroberto			break;
494554359Sroberto
494654359Sroberto		case CMD_RUTCPARAM:
494754359Sroberto		{
494854359Sroberto			float t0t = getflt((unsigned char *)&mb(14));
494954359Sroberto			short wnt = getshort((unsigned char *)&mb(18));
495054359Sroberto			short dtls = getshort((unsigned char *)&mb(12));
495154359Sroberto			short wnlsf = getshort((unsigned char *)&mb(20));
495254359Sroberto			short dn = getshort((unsigned char *)&mb(22));
495354359Sroberto			short dtlsf = getshort((unsigned char *)&mb(24));
495454359Sroberto
495554359Sroberto			if ((int)t0t != 0)
495654359Sroberto			  {
495754359Sroberto			    mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf);
495854359Sroberto			  }
495954359Sroberto			else
496054359Sroberto			  {
496154359Sroberto			    strcpy(t, "<NO UTC DATA>");
496254359Sroberto			  }
496354359Sroberto		}
496454359Sroberto		break;
496554359Sroberto
496654359Sroberto		case CMD_RSAT1BIAS:
496754359Sroberto			sprintf(t, "%.1fm %.2fm/s at %.1fs",
496854359Sroberto				getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8)));
496954359Sroberto			break;
497054359Sroberto
497154359Sroberto		case CMD_RIOOPTIONS:
497254359Sroberto		{
497354359Sroberto			sprintf(t, "%02x %02x %02x %02x",
497454359Sroberto				mb(0), mb(1), mb(2), mb(3));
497554359Sroberto			if (mb(0) != TRIM_POS_OPT ||
497654359Sroberto			    mb(2) != TRIM_TIME_OPT)
497754359Sroberto			{
497854359Sroberto				(void)trimbletsip_setup(parse, "bad io options");
497954359Sroberto			}
498054359Sroberto		}
498154359Sroberto		break;
498254359Sroberto
498354359Sroberto		case CMD_RSPOSXYZ:
498454359Sroberto		{
498554359Sroberto			double x = getflt((unsigned char *)&mb(0));
498654359Sroberto			double y = getflt((unsigned char *)&mb(4));
498754359Sroberto			double z = getflt((unsigned char *)&mb(8));
498854359Sroberto			double f = getflt((unsigned char *)&mb(12));
498954359Sroberto
499054359Sroberto			if (f > 0.0)
499154359Sroberto			  sprintf(t, "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec",
499254359Sroberto				  x, y, z,
499354359Sroberto				  f);
499454359Sroberto			else
499554359Sroberto			  return;
499654359Sroberto		}
499754359Sroberto		break;
499854359Sroberto
499954359Sroberto		case CMD_RSLLAPOS:
500054359Sroberto		{
500154359Sroberto			double lat = getflt((unsigned char *)&mb(0));
500254359Sroberto			double lng = getflt((unsigned char *)&mb(4));
500354359Sroberto			double f   = getflt((unsigned char *)&mb(12));
500454359Sroberto
500554359Sroberto			if (f > 0.0)
500654359Sroberto			  sprintf(t, "lat %f %c, long %f %c, alt %.2fm",
500754359Sroberto				  ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
500854359Sroberto				  ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
500954359Sroberto				  getflt((unsigned char *)&mb(8)));
501054359Sroberto			else
501154359Sroberto			  return;
501254359Sroberto		}
501354359Sroberto		break;
501454359Sroberto
501554359Sroberto		case CMD_RDOUBLEXYZ:
501654359Sroberto		{
501754359Sroberto			double x = getdbl((unsigned char *)&mb(0));
501854359Sroberto			double y = getdbl((unsigned char *)&mb(8));
501954359Sroberto			double z = getdbl((unsigned char *)&mb(16));
502054359Sroberto			sprintf(t, "x= %.1fm, y= %.1fm, z= %.1fm",
502154359Sroberto				x, y, z);
502254359Sroberto		}
502354359Sroberto		break;
502454359Sroberto
502554359Sroberto		case CMD_RDOUBLELLA:
502654359Sroberto		{
502754359Sroberto			double lat = getdbl((unsigned char *)&mb(0));
502854359Sroberto			double lng = getdbl((unsigned char *)&mb(8));
502954359Sroberto			sprintf(t, "lat %f %c, lon %f %c, alt %.2fm",
503054359Sroberto				((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
503154359Sroberto				((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
503254359Sroberto				getdbl((unsigned char *)&mb(16)));
503354359Sroberto		}
503454359Sroberto		break;
503554359Sroberto
503654359Sroberto		case CMD_RALLINVIEW:
503754359Sroberto		{
503854359Sroberto			int i, sats;
503954359Sroberto
504054359Sroberto			strcpy(t, "mode: ");
504154359Sroberto			t += strlen(t);
504254359Sroberto			switch (mb(0) & 0x7)
504354359Sroberto			{
504454359Sroberto			default:
504554359Sroberto				sprintf(t, "0x%x", mb(0) & 0x7);
504654359Sroberto				break;
504754359Sroberto
504854359Sroberto			case 3:
504954359Sroberto				strcat(t, "2D");
505054359Sroberto				break;
505154359Sroberto
505254359Sroberto			case 4:
505354359Sroberto				strcat(t, "3D");
505454359Sroberto				break;
505554359Sroberto			}
505654359Sroberto			t += strlen(t);
505754359Sroberto			if (mb(0) & 0x8)
505854359Sroberto				strcpy(t, "-MANUAL, ");
505954359Sroberto			else
506054359Sroberto				strcpy(t, "-AUTO, ");
506154359Sroberto			t += strlen(t);
506254359Sroberto
506354359Sroberto			sats = (mb(0)>>4) & 0xF;
506454359Sroberto
506554359Sroberto			sprintf(t, "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ",
506654359Sroberto				getflt((unsigned char *)&mb(1)),
506754359Sroberto				getflt((unsigned char *)&mb(5)),
506854359Sroberto				getflt((unsigned char *)&mb(9)),
506954359Sroberto				getflt((unsigned char *)&mb(13)),
507054359Sroberto				sats, (sats == 1) ? "" : "s");
507154359Sroberto			t += strlen(t);
507254359Sroberto
507354359Sroberto			for (i=0; i < sats; i++)
507454359Sroberto			{
507554359Sroberto				sprintf(t, "%s%02d", i ? ", " : "", mb(17+i));
507654359Sroberto				t += strlen(t);
507754359Sroberto				if (tr)
507854359Sroberto					tr->ctrack |= (1 << (mb(17+i)-1));
507954359Sroberto			}
508054359Sroberto
508154359Sroberto			if (tr)
508254359Sroberto                        { /* mark for tracking status query */
508354359Sroberto				tr->qtracking = 1;
508454359Sroberto			}
508554359Sroberto		}
508654359Sroberto		break;
508754359Sroberto
508854359Sroberto		case CMD_RSTATTRACK:
508954359Sroberto		{
509054359Sroberto			sprintf(t-2, "[%02d]=\"", mb(0)); /* add index to var name */
509154359Sroberto			t += strlen(t);
509254359Sroberto
509354359Sroberto			if (getflt((unsigned char *)&mb(4)) < 0.0)
509454359Sroberto			{
509554359Sroberto				strcpy(t, "<NO MEASUREMENTS>");
509654359Sroberto				var_flag &= ~DEF;
509754359Sroberto			}
509854359Sroberto			else
509954359Sroberto			{
510054359Sroberto				sprintf(t, "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f",
510154359Sroberto					(mb(1) & 0xFF)>>3,
510254359Sroberto					mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER",
510354359Sroberto					mb(3),
510454359Sroberto					getflt((unsigned char *)&mb(4)),
510554359Sroberto					getflt((unsigned char *)&mb(12)) * RTOD,
510654359Sroberto					getflt((unsigned char *)&mb(16)) * RTOD);
510754359Sroberto				t += strlen(t);
510854359Sroberto				if (mb(20))
510954359Sroberto				{
511054359Sroberto					var_flag &= ~DEF;
511154359Sroberto					strcpy(t, ", OLD");
511254359Sroberto				}
511354359Sroberto				t += strlen(t);
511454359Sroberto				if (mb(22))
511554359Sroberto				{
511654359Sroberto					if (mb(22) == 1)
511754359Sroberto						strcpy(t, ", BAD PARITY");
511854359Sroberto					else
511954359Sroberto						if (mb(22) == 2)
512054359Sroberto							strcpy(t, ", BAD EPH HEALTH");
512154359Sroberto				}
512254359Sroberto				t += strlen(t);
512354359Sroberto				if (mb(23))
512454359Sroberto					strcpy(t, ", collecting data");
512554359Sroberto			}
512654359Sroberto		}
512754359Sroberto		break;
512854359Sroberto
512954359Sroberto		default:
513054359Sroberto			strcpy(t, "<UNDECODED>");
513154359Sroberto			break;
513254359Sroberto		}
513354359Sroberto		strcat(t,"\"");
513454359Sroberto		set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag);
513554359Sroberto	}
513654359Sroberto}
513754359Sroberto
513854359Sroberto
513954359Sroberto/**============================================================
514054359Sroberto ** RAWDCF support
514154359Sroberto **/
514254359Sroberto
514354359Sroberto/*--------------------------------------------------
514456746Sroberto * rawdcf_init_1 - set up modem lines for RAWDCF receivers
514556746Sroberto * SET DTR line
514654359Sroberto */
514754359Sroberto#if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR))
514854359Srobertostatic int
514956746Srobertorawdcf_init_1(
515054359Sroberto	struct parseunit *parse
515154359Sroberto	)
515254359Sroberto{
515354359Sroberto	/*
515454359Sroberto	 * You can use the RS232 to supply the power for a DCF77 receiver.
515554359Sroberto	 * Here a voltage between the DTR and the RTS line is used. Unfortunately
515654359Sroberto	 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
515754359Sroberto	 */
515854359Sroberto
515954359Sroberto#ifdef TIOCM_DTR
516054359Sroberto	int sl232 = TIOCM_DTR;	/* turn on DTR for power supply */
516154359Sroberto#else
516254359Sroberto	int sl232 = CIOCM_DTR;	/* turn on DTR for power supply */
516354359Sroberto#endif
516454359Sroberto
516554359Sroberto	if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
516654359Sroberto	{
516756746Sroberto		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
516854359Sroberto	}
516954359Sroberto	return 0;
517054359Sroberto}
517154359Sroberto#else
517254359Srobertostatic int
517354359Srobertorawdcfdtr_init(
517454359Sroberto	struct parseunit *parse
517554359Sroberto	)
517654359Sroberto{
517756746Sroberto	msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer));
517854359Sroberto	return 0;
517954359Sroberto}
518054359Sroberto#endif  /* DTR initialisation type */
518154359Sroberto
518254359Sroberto/*--------------------------------------------------
518356746Sroberto * rawdcf_init_2 - set up modem lines for RAWDCF receivers
518456746Sroberto * CLR DTR line, SET RTS line
518554359Sroberto */
518656746Sroberto#if defined(TIOCMSET) &&  (defined(TIOCM_RTS) || defined(CIOCM_RTS))
518754359Srobertostatic int
518856746Srobertorawdcf_init_2(
518954359Sroberto	struct parseunit *parse
519054359Sroberto	)
519154359Sroberto{
519254359Sroberto	/*
519354359Sroberto	 * You can use the RS232 to supply the power for a DCF77 receiver.
519456746Sroberto	 * Here a voltage between the DTR and the RTS line is used. Unfortunately
519556746Sroberto	 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
519654359Sroberto	 */
519754359Sroberto
519854359Sroberto#ifdef TIOCM_RTS
519956746Sroberto	int sl232 = TIOCM_RTS;	/* turn on RTS, clear DTR for power supply */
520054359Sroberto#else
520156746Sroberto	int sl232 = CIOCM_RTS;	/* turn on DTR for power supply */
520254359Sroberto#endif
520354359Sroberto
520454359Sroberto	if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
520554359Sroberto	{
520656746Sroberto		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
520754359Sroberto	}
520854359Sroberto	return 0;
520954359Sroberto}
521054359Sroberto#else
521154359Srobertostatic int
521256746Srobertorawdcf_init_2(
521354359Sroberto	struct parseunit *parse
521454359Sroberto	)
521554359Sroberto{
521656746Sroberto	msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer));
521754359Sroberto	return 0;
521854359Sroberto}
521956746Sroberto#endif  /* DTR initialisation type */
522054359Sroberto
522154359Sroberto#else	/* defined(REFCLOCK) && defined(PARSE) */
522254359Srobertoint refclock_parse_bs;
522354359Sroberto#endif	/* defined(REFCLOCK) && defined(PARSE) */
522454359Sroberto
522554359Sroberto/*
522654359Sroberto * History:
522754359Sroberto *
522854359Sroberto * refclock_parse.c,v
522956746Sroberto * Revision 4.36  1999/11/28 17:18:20  kardel
523056746Sroberto * disabled burst mode
523156746Sroberto *
523256746Sroberto * Revision 4.35  1999/11/28 09:14:14  kardel
523356746Sroberto * RECON_4_0_98F
523456746Sroberto *
523556746Sroberto * Revision 4.34  1999/05/14 06:08:05  kardel
523656746Sroberto * store current_time in a suitable container (u_long)
523756746Sroberto *
523856746Sroberto * Revision 4.33  1999/05/13 21:48:38  kardel
523956746Sroberto * double the no response timeout interval
524056746Sroberto *
524156746Sroberto * Revision 4.32  1999/05/13 20:09:13  kardel
524256746Sroberto * complain only about missing polls after a full poll interval
524356746Sroberto *
524456746Sroberto * Revision 4.31  1999/05/13 19:59:32  kardel
524556746Sroberto * add clock type 16 for RTS set DTR clr in RAWDCF
524656746Sroberto *
524756746Sroberto * Revision 4.30  1999/02/28 20:36:43  kardel
524856746Sroberto * fixed printf fmt
524956746Sroberto *
525054359Sroberto * Revision 4.29  1999/02/28 19:58:23  kardel
525154359Sroberto * updated copyright information
525254359Sroberto *
525354359Sroberto * Revision 4.28  1999/02/28 19:01:50  kardel
525454359Sroberto * improved debug out on sent Meinberg messages
525554359Sroberto *
525654359Sroberto * Revision 4.27  1999/02/28 18:05:55  kardel
525754359Sroberto * no linux/ppsclock.h stuff
525854359Sroberto *
525954359Sroberto * Revision 4.26  1999/02/28 15:27:27  kardel
526054359Sroberto * wharton clock integration
526154359Sroberto *
526254359Sroberto * Revision 4.25  1999/02/28 14:04:46  kardel
526354359Sroberto * added missing double quotes to UTC information string
526454359Sroberto *
526554359Sroberto * Revision 4.24  1999/02/28 12:06:50  kardel
526654359Sroberto * (parse_control): using gmprettydate instead of prettydate()
526754359Sroberto * (mk_utcinfo): new function for formatting GPS derived UTC information
526854359Sroberto * (gps16x_message): changed to use mk_utcinfo()
526954359Sroberto * (trimbletsip_message): changed to use mk_utcinfo()
527054359Sroberto * ignoring position information in unsynchronized mode
527154359Sroberto * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY
527254359Sroberto *
527354359Sroberto * Revision 4.23  1999/02/23 19:47:53  kardel
527454359Sroberto * fixed #endifs
527554359Sroberto * (stream_receive): fixed formats
527654359Sroberto *
527754359Sroberto * Revision 4.22  1999/02/22 06:21:02  kardel
527854359Sroberto * use new autoconfig symbols
527954359Sroberto *
528054359Sroberto * Revision 4.21  1999/02/21 12:18:13  kardel
528154359Sroberto * 4.91f reconcilation
528254359Sroberto *
528354359Sroberto * Revision 4.20  1999/02/21 10:53:36  kardel
528454359Sroberto * initial Linux PPSkit version
528554359Sroberto *
528654359Sroberto * Revision 4.19  1999/02/07 09:10:45  kardel
528754359Sroberto * clarify STREAMS mitigation rules in comment
528854359Sroberto *
528954359Sroberto * Revision 4.18  1998/12/20 23:45:34  kardel
529054359Sroberto * fix types and warnings
529154359Sroberto *
529254359Sroberto * Revision 4.17  1998/11/15 21:24:51  kardel
529354359Sroberto * cannot access mbg_ routines when CLOCK_MEINBERG
529454359Sroberto * is not defined
529554359Sroberto *
529654359Sroberto * Revision 4.16  1998/11/15 20:28:17  kardel
529754359Sroberto * Release 4.0.73e13 reconcilation
529854359Sroberto *
529954359Sroberto * Revision 4.15  1998/08/22 21:56:08  kardel
530054359Sroberto * fixed IO handling for non-STREAM IO
530154359Sroberto *
530254359Sroberto * Revision 4.14  1998/08/16 19:00:48  kardel
530354359Sroberto * (gps16x_message): reduced UTC parameter information (dropped A0,A1)
530454359Sroberto * made uval a local variable (killed one of the last globals)
530554359Sroberto * (sendetx): added logging of messages when in debug mode
530654359Sroberto * (trimble_check): added periodic checks to facilitate re-initialization
530754359Sroberto * (trimbletsip_init): made use of EOL character if in non-kernel operation
530854359Sroberto * (trimbletsip_message): extended message interpretation
530954359Sroberto * (getdbl): fixed data conversion
531054359Sroberto *
531154359Sroberto * Revision 4.13  1998/08/09 22:29:13  kardel
531254359Sroberto * Trimble TSIP support
531354359Sroberto *
531454359Sroberto * Revision 4.12  1998/07/11 10:05:34  kardel
531554359Sroberto * Release 4.0.73d reconcilation
531654359Sroberto *
531754359Sroberto * Revision 4.11  1998/06/14 21:09:42  kardel
531854359Sroberto * Sun acc cleanup
531954359Sroberto *
532054359Sroberto * Revision 4.10  1998/06/13 12:36:45  kardel
532154359Sroberto * signed/unsigned, name clashes
532254359Sroberto *
532354359Sroberto * Revision 4.9  1998/06/12 15:30:00  kardel
532454359Sroberto * prototype fixes
532554359Sroberto *
532654359Sroberto * Revision 4.8  1998/06/12 11:19:42  kardel
532754359Sroberto * added direct input processing routine for refclocks in
532854359Sroberto * order to avaiod that single character io gobbles up all
532954359Sroberto * receive buffers and drops input data. (Problem started
533054359Sroberto * with fast machines so a character a buffer was possible
533154359Sroberto * one of the few cases where faster machines break existing
533254359Sroberto * allocation algorithms)
533354359Sroberto *
533454359Sroberto * Revision 4.7  1998/06/06 18:35:20  kardel
533554359Sroberto * (parse_start): added BURST mode initialisation
533654359Sroberto *
533754359Sroberto * Revision 4.6  1998/05/27 06:12:46  kardel
533854359Sroberto * RAWDCF_BASEDELAY default added
533954359Sroberto * old comment removed
534054359Sroberto * casts for ioctl()
534154359Sroberto *
534254359Sroberto * Revision 4.5  1998/05/25 22:05:09  kardel
534354359Sroberto * RAWDCF_SETDTR option removed
534454359Sroberto * clock type 14 attempts to set DTR for
534554359Sroberto * power supply of RAWDCF receivers
534654359Sroberto *
534754359Sroberto * Revision 4.4  1998/05/24 16:20:47  kardel
534854359Sroberto * updated comments referencing Meinberg clocks
534954359Sroberto * added RAWDCF clock with DTR set option as type 14
535054359Sroberto *
535154359Sroberto * Revision 4.3  1998/05/24 10:48:33  kardel
535254359Sroberto * calibrated CONRAD RAWDCF default fudge factor
535354359Sroberto *
535454359Sroberto * Revision 4.2  1998/05/24 09:59:35  kardel
535554359Sroberto * corrected version information (ntpq support)
535654359Sroberto *
535754359Sroberto * Revision 4.1  1998/05/24 09:52:31  kardel
535854359Sroberto * use fixed format only (new IO model)
535954359Sroberto * output debug to stdout instead of msyslog()
536054359Sroberto * don't include >"< in ASCII output in order not to confuse
536154359Sroberto * ntpq parsing
536254359Sroberto *
536354359Sroberto * Revision 4.0  1998/04/10 19:52:11  kardel
536454359Sroberto * Start 4.0 release version numbering
536554359Sroberto *
536654359Sroberto * Revision 1.2  1998/04/10 19:28:04  kardel
536754359Sroberto * initial NTP VERSION 4 integration of PARSE with GPS166 binary support
536854359Sroberto * derived from 3.105.1.2 from V3 tree
536954359Sroberto *
537054359Sroberto * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel
537154359Sroberto *
537254359Sroberto */
5373